java swing очистить очередь событий

Можно ли сделать это стандартным способом?

Вот сценарий.

  1. Начните делать что-то дорогое в EDT (EDT блокируется, пока дорогая операция не закончится).

  2. Пока EDT был заблокирован, пользователь продолжал нажимать / перетаскивать кнопки мыши. Все действия мыши где-то записаны.

  3. Когда EDT свободен (сделано с дорогими вещами), он начинает обрабатывать события мыши.

На шаге 3 я хочу отказаться от накопившихся событий мыши. После освобождения EDT любое новое событие мыши должно обрабатываться обычным образом.

Любые идеи о том, как этого добиться.

PS: я не могу предотвратить блокировку EDT (я не контролирую поведение некоторых модулей в моей программе).

РЕДАКТИРОВАТЬ: Если я могу безопасно вызвать "SunToolkit.flushPendingEvents ()", то я всегда могу поставить стекло перед началом дорогостоящей операции в EDT. После завершения дорогостоящей операции в потоке EDT сбросьте все события - они перейдут на стеклянную панель, которая ничего не сделает. А потом пусть EDT работает как обычно.

EDIT2: я добавил SSCCE, чтобы продемонстрировать проблему.

открытый класс BusyCursorTest2 расширяет javax.swing.JFrame {

    public BusyCursorTest2 () {

        javax.swing.JButton wait = new javax.swing.JButton ("Подождите 3 секунды");
        getContentPane().setLayout(new java.awt.GridLayout(2, 1, 0, 0));. GetContentPane () добавить (ожидание);
        getContentPane().add(new javax.swing.JToggleButton("Нажмите меня"));
        setTitle("Busy Cursor");
        setSize(300, 200);
        setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE);
        SetVisible(истина);

        wait.addActionListener (новый java.awt.event.ActionListener () {

            public void actionPerformed (событие java.awt.event.ActionEvent) {

                final java.util.Timer timer = switchToBusyCursor (BusyCursorTest2.this);

                пытаться {
                    // сделать что-то дорогое в EDT
                    пытаться {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        //ничего не делать
                    }
                } в конце концов {
                    switchToNormalCursor(BusyCursorTest2.this, таймер);
                }
            }

        });
    }

    public static java.util.Timer switchToBusyCursor (окончательный фрейм javax.swing.JFrame) {
        startEventTrap(рама);
        java.util.TimerTask timerTask = новый java.util.TimerTask () {

            public void run () {
                startWaitCursor(рама);
            }

        };
        final java.util.Timer timer = new java.util.Timer ();
        timer.schedule (timerTask, DELAY_MS);
        таймер возврата;
    }

    public static void switchToNormalCursor (финальный кадр javax.swing.JFrame, финальный таймер java.util.Timer) {
        timer.cancel();
        stopWaitCursor(рама);
        stopEventTrap(рама);
    }

    закрытая статическая пустота startWaitCursor(фрейм javax.swing.JFrame) {. Frame.getGlassPane() SetCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));. Frame.getGlassPane() addMouseListener(MouseAdapter);. Frame.getGlassPane() SetVisible(истина);
    }

    частный статический void stopWaitCursor(фрейм javax.swing.JFrame) {. Frame.getGlassPane() SetCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));. Frame.getGlassPane() removeMouseListener(MouseAdapter);. Frame.getGlassPane() SetVisible(ложь);
    }

    закрытая статическая пустота startEventTrap (фрейм javax.swing.JFrame) {. Frame.getGlassPane() addMouseListener(MouseAdapter);. Frame.getGlassPane() SetVisible(истина);
    }

    частный статический void stopEventTrap(фрейм javax.swing.JFrame) {. Frame.getGlassPane() removeMouseListener(MouseAdapter);. Frame.getGlassPane() SetVisible(ложь);
    }

    приватная статическая финальная java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter () {
    };

    public static void main (String [] args) {
        javax.swing.SwingUtilities.invokeLater (new Runnable () {

            public void run () {
                новый BusyCursorTest2 ();
            }

        });

    }

    private static final int DELAY_MS = 250;

}
  1. Запустите SSCCE

  2. Нажмите на кнопку "Подождите 3 секунды". Имитирует дорогостоящую операцию. Курсор мыши изменится на занятый.

  3. Пока курсор занят, нажмите на кнопку "Нажми меня". Если через три секунды кнопка переключения меняет свое состояние, то событие мыши было получено кнопкой переключения и не было захвачено.

Я хочу, чтобы в то время как курсор выглядит занятым, сгенерированные события мыши (и другие) будут отброшены.

Благодарю.

3 ответа

Решение

ОК, я наконец получил все, чтобы работать. Я публикую SSCCE для правильно работающего примера. Хитрость заключается в том, чтобы скрыть стеклянную панель с помощью метода "javax.swing.SwingUtilities.invokeLater ()". Оберните необходимый код в Runnable, а затем вызовите его, используя invokeLater. В таком случае Swing обрабатывает все события мыши (ничего не происходит, так как стеклянная панель перехватывает их), а затем скрывает стеклянную панель. Вот SSCCE.

открытый класс BusyCursorTest2 extends javax.swing.JFrame {

    public BusyCursorTest2() {

        javax.swing.JButton wait = new javax.swing.JButton("Подождите 3 секунды");
        getContentPane().setLayout(new java.awt.GridLayout(2, 1, 0, 0));. GetContentPane () добавить (ожидание);
        getContentPane().add(new javax.swing.JToggleButton("Нажмите меня"));
        setTitle("Busy Cursor");
        setSize(300, 200);
        setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE); SetVisible(истина);

        wait.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent) {

                final java.util.Timer timer = switchToBusyCursor(BusyCursorTest2.this); попробуй {
                    // что-то сделать дорого в EDT или иным образом try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        // ничего не делать}
                } finally {
                    switchToNormalCursorEventThread(BusyCursorTest2.this, timer);
                }

            }

        });
    } открытый статический java.util.Timer switchToBusyCursor(final javax.swing.JFrame frame) {
        startEventTrap(frame);
        java.util.TimerTask timerTask = new java.util.TimerTask() {

            public void run() {
                startWaitCursor(frame);
            }

        };
        final java.util.Timer timer = new java.util.Timer();
        timer.schedule(timerTask, DELAY_MS); таймер возврата; } открытый статический void switchToNormalCursorEventThread(финальный кадр javax.swing.JFrame, конечный таймер java.util.Timer) {

        Runnable r = new Runnable() {

            public void run() {
                switchToNormalCursor(frame, timer);
            }

        };

        javax.swing.SwingUtilities.invokeLater(г); } открытый статический void switchToNormalCursor(финальный кадр javax.swing.JFrame, финальный таймер java.util.Timer) {
        timer.cancel();
        stopWaitCursor(рама);
        stopEventTrap(рама);
    }

    private static void startWaitCursor(javax.swing.JFrame frame) {
        frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));. Frame.getGlassPane () addMouseListener(MouseAdapter);. Frame.getGlassPane () SetVisible(истина); } частный статический void stopWaitCursor(javax.swing.JFrame frame) {
        frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));. Frame.getGlassPane () removeMouseListener(MouseAdapter);. Frame.getGlassPane () SetVisible(ложь); } приватная статическая пустота startEventTrap(javax.swing.JFrame frame) {
        frame.getGlassPane().addMouseListener(mouseAdapter);. Frame.getGlassPane () SetVisible(истина); } приватная статическая пустота stopEventTrap (фрейм javax.swing.JFrame) {
        java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue();. Frame.getGlassPane () removeMouseListener(MouseAdapter);. Frame.getGlassPane () SetVisible(ложь);
    }

    private static final java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter() {
    };

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                new BusyCursorTest2();
            }

        });

    }

    private static final int DELAY_MS = 250;

}

Опять же, EDT, если это вообще возможно, не должен быть заблокирован. Но если вам нужно, у вас может быть рабочий курсор занятости, как указано выше.

Любые комментарии приветствуются.

Прочтите эту статью.

По сути, длительные задачи не должны выполняться на EDT. Java предоставила SwingWorker для таких задач.

Я бы более подробно рассказал, но вы не склонны принимать ответы.

Определенно не блокируйте EDT. Вы никогда не должны делать это!

Вот простой вспомогательный класс для этого (кредит Сантошу Тивари):

import java.awt.Component;
import java.awt.Cursor;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

/**
 * When blocking the EDT (Event Queue) in swing, the cursor won't update, and windows won't render.
 * This should show the hourglass even when you're blocking the EDT.
 *
 * Source:
 * https://stackru.com/questions/7085239/java-swing-clear-the-event-queue
 * 
 * @author Kieveli, Santosh Tiwari
 *
 */
public class BlockingWaitCursor {

   private static final java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter() {};

   /**
    * The Dialog or main window is required to show the cursor and animate it. The actionListener is called
    * as soon as initial setup is completed and the animation timer is running.
    * @param currentComponent A panel, dialog, frame, or any other swing component that is the current focus
    * @param action Your action to perform on the EDT. This is started extremely quickly and without delay.
    */
   public static void showWaitAndRun(Component currentComponent, ActionListener action ) {

      Timer timer = setupWaitCursor(currentComponent);

      try {
         // now allow our caller to execute their slow and delayed code on the EDT
         ActionEvent event = new ActionEvent(BlockingWaitCursor.class, ActionEvent.ACTION_PERFORMED, "run");
         action.actionPerformed(event);
      }
      finally {
         resetWaitCursor(currentComponent, timer);
      }
   }

   private static Timer setupWaitCursor(Component currentComponent) {
      final Component glassPane = findGlassPane(currentComponent);
      if ( glassPane == null ) {
         return null;
      }

      // block mouse-actions with a glass pane that covers everything
      glassPane.addMouseListener(mouseAdapter);
      glassPane.setVisible(true);

      // animate the wait cursor off of the EDT using a generic timer.
      Timer timer = new Timer();
      timer.schedule( new TimerTask() {
         @Override
         public void run() {
            glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            glassPane.addMouseListener(mouseAdapter);
            glassPane.setVisible(true);
         }

      }, 250l);

      return timer;
   }

   private static void resetWaitCursor(Component currentComponent, final Timer timer) {
      final Component glassPane = findGlassPane(currentComponent);
      if ( glassPane == null ) {
         return;
      }
      // Invoke later so that the event queue contains user actions to cancel while the loading occurred
      SwingUtilities.invokeLater(new Runnable() {
         @Override
         public void run() {
            if ( timer != null )
               timer.cancel();
            Toolkit.getDefaultToolkit().getSystemEventQueue();
            glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            glassPane.removeMouseListener(mouseAdapter);
            glassPane.setVisible(false);  
         }
      });
   }

   private static Component findGlassPane(Component currentComponent) {
      // try to locate the glass pane by looking for a frame or dialog as an ancestor
      JFrame frame = findFrame(currentComponent);
      JDialog dialog = findDialog(currentComponent);
      Component glassPane = null;
      if ( frame != null )
         glassPane = frame.getGlassPane();
      if ( dialog != null )
         glassPane = dialog.getGlassPane();
      return glassPane;
   }

   private static JFrame findFrame(Component currentComponent) {
      // find the frame if it exists - it may be the currentComponent
      if ( currentComponent instanceof JFrame )
         return (JFrame) currentComponent;

      Window window = SwingUtilities.getWindowAncestor(currentComponent);
      if ( window == null )
         return null;
      if ( ! (window instanceof JFrame) )
         return null;
      return (JFrame)window;
   }

   private static JDialog findDialog(Component currentComponent) {
      // find the dialog if it exists - it may be the currentComponent
      if ( currentComponent instanceof JDialog )
         return (JDialog) currentComponent;

      Window window = SwingUtilities.getWindowAncestor(currentComponent);
      if ( window == null )
         return null;
      if ( ! (window instanceof JDialog) )
         return null;
      return (JDialog)window;
   }

}

Но никогда не используйте это. Ну, если вы не гордитесь и не пишете быструю утилиту, которая затем вышла из-под контроля и стала основным приложением, и у вас нет времени, чтобы разобрать ваш код на части, чтобы выяснить, что может работать на работнике, и что будет обрыв из-за интеграции с Swing / SQL, которые не являются потокобезопасными.

Другие вопросы по тегам