java swing очистить очередь событий - PullRequest
5 голосов
/ 17 августа 2011

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

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

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

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

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

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

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

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

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

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


public class BusyCursorTest2 extends javax.swing.JFrame {

    public BusyCursorTest2() {

        javax.swing.JButton wait = new javax.swing.JButton("Wait 3 seconds");
        getContentPane().setLayout(new java.awt.GridLayout(2, 1, 0, 0));
        getContentPane().add(wait);
        getContentPane().add(new javax.swing.JToggleButton("Click me"));
        setTitle("Busy Cursor");
        setSize(300, 200);
        setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE);
        setVisible(true);

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

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

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

                try {
                    //do something expensive in EDT
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        //do nothing
                    }
                } finally {
                    switchToNormalCursor(BusyCursorTest2.this, timer);
                }
            }

        });
    }

    public static 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);
        return timer;
    }

    public static void switchToNormalCursor(final javax.swing.JFrame frame, final java.util.Timer timer) {
        timer.cancel();
        stopWaitCursor(frame);
        stopEventTrap(frame);
    }

    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(true);
    }

    private static 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(false);
    }

    private static void startEventTrap(javax.swing.JFrame frame) {
        frame.getGlassPane().addMouseListener(mouseAdapter);
        frame.getGlassPane().setVisible(true);
    }

    private static void stopEventTrap(javax.swing.JFrame frame) {
        frame.getGlassPane().removeMouseListener(mouseAdapter);
        frame.getGlassPane().setVisible(false);
    }

    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;

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

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

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

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

Спасибо.

Ответы [ 3 ]

3 голосов
/ 24 августа 2011

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

public class BusyCursorTest2 extends javax.swing.JFrame {

    public BusyCursorTest2() {

        javax.swing.JButton wait = new javax.swing.JButton("Wait 3 seconds");
        getContentPane().setLayout(new java.awt.GridLayout(2, 1, 0, 0));
        getContentPane().add(wait);
        getContentPane().add(new javax.swing.JToggleButton("Click me"));
        setTitle("Busy Cursor");
        setSize(300, 200);
        setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE);
        setVisible(true);

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

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

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

                try {
                    //do something expensive in EDT or otherwise
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        //do nothing
                    }
                } finally {
                    switchToNormalCursorEventThread(BusyCursorTest2.this, timer);
                }

            }

        });
    }

    public static 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);
        return timer;
    }

    public static void switchToNormalCursorEventThread(final javax.swing.JFrame frame, final java.util.Timer timer) {

        Runnable r = new Runnable() {

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

        };

        javax.swing.SwingUtilities.invokeLater(r);

    }

    public static void switchToNormalCursor(final javax.swing.JFrame frame, final java.util.Timer timer) {
        timer.cancel();
        stopWaitCursor(frame);
        stopEventTrap(frame);
    }

    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(true);
    }

    private static 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(false);
    }

    private static void startEventTrap(javax.swing.JFrame frame) {
        frame.getGlassPane().addMouseListener(mouseAdapter);
        frame.getGlassPane().setVisible(true);
    }

    private static void stopEventTrap(javax.swing.JFrame frame) {
        java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue();
        frame.getGlassPane().removeMouseListener(mouseAdapter);
        frame.getGlassPane().setVisible(false);
    }

    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, если это вообще возможно, не должен быть заблокирован. Но если вам нужно, у вас может быть рабочий курсор занятости, как указано выше.

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

2 голосов
/ 17 августа 2011

Читать статья .

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

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

1 голос
/ 28 июня 2018

Определенно не блокируйте 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:
 * /7792810/java-swing-ochistit-ochered-sobytii
 * 
 * @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, которые не являются потокобезопасными.

...