2011-08-16 26 views
4

これは標準的な方法で可能ですか?java swingイベントキューをクリアする

ここにシナリオがあります。

  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秒後にトグルボタンが状態を変えた場合、マウスイベントはトグルボタンで受信され、トラップされませんでした。

カーソルがビジー状態になっている間に、生成されたマウス(およびその他の)イベントは破棄されます。

ありがとうございました。

+0

いいえ、ほとんどのスイングコンポーネント(すべてのパネルとその内容など)はさまざまな開発者によって行われ、それらはいつでも変更される可能性があります。私はそれらのスイングコンポーネントについて何も仮定することはできません。私はルートペイン上に目に見えるガラス板を作って、出来事を得るのを防ぐことができます。 –

+4

2つのソリューションがあります。 1)高価なopsをワーカースレッドに入れます。 2)他のイベントをブロックするためにガラス板を使用する。スイングは開発者からアプリを保護するようには設計されていません。 –

+1

EventQueueとの整合性を変更または分割するには良い方法ではなく、このフォーラムで最も深い検索を行うことで、 'EventQueue theQueue = getToolkit()。getSystemEventQueue();' EDTにイベントを手動で送信すると、待っているスレッドが失われ、現在の形で永遠に残っている、単純にそれをしないでください。 – mKorbel

答えて

2

OK、私はついに仕事をすべて手に入れました。私は正しく動作する例のためにSSCCEを掲示しています。トリックは、 "javax.swing.SwingUtilities.invokeLater()"メソッドを使用してglasspaneを隠すことです。必要なコードを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をブロックしてはならない。しかし、そうしなければならない場合は、上記のように作業中のカーソルを持つことができます。

コメントは大歓迎です。

1

このarticleをお読みください。

基本的に、長時間実行されるタスクはEDT上で実行しないでください。 Javaは、そのようなタスクのためにSwingWorkerを提供しています。

詳細については詳しく説明しますが、回答を受け入れる傾向はありません。

+0

私はSwingWorkerを使用していますJAVA 1.5と互換性があります)。私が制御できないコードは他のコードです。ご回答有難うございます。 –

+0

さて、私は戻って私の質問への答えを受け入れました(私は自分自身に答えていましたので、まだそれらを受け入れました)。私が他のポストの助けを借りていた人にとって、私は思い出したところでそれらのポストを元に戻した。 –