2011-12-17 11 views
2

Java SwingのmouseDraggedメッセージMouseMotionListenerのコールバックスピードに関する質問があります。 This postは関連性がありますが、全く同じではありませんので、私自身の質問を始めました。Java Swing mouseDraggedコールバックスピード

私は、基本的にデジタル化されたTCG(トレーディングカードゲーム)エミュレータである商業的流通を目の当たりにしていない小さな社内アプリケーションを作っています。 MtG(Magic the Gathering)に精通している人なら、そのようなプログラムから聞いたことがあります。私はthisのように見えるものを作成しようとしていますが、それほどファンシーはありません。

私のGUIは、メニュー付きのJFrameと、さまざまなボタンとラベルを含むパネルで構成されていますが、私は問題を説明するために関連する部分のみを扱います。本質的には

、私はいつでもあなたがプレイすることができ、あなたの手札のカードを示し、その中にJListとのことでJScrollPane、と、左側にJPanelと垂直分割JSplitPaneを使用しています。分割の右側には、DEFAULT_LAYERのサブ画像(のサブクラスは画像を追加するためにdrawの機能を上書きします)があり、PALETTE_LAYERの上のさまざまなレイヤーに、再生中のカードが表示されます。JLayeredPaneカスタムCardPanel(カードを示すJPanelの別のサブクラス)によって(ArrayListに集められた) JLayeredPane全体は、あなたがすでにプレイしたすべてのカードを使ってあなたの前のテーブルを表しています。

私が最初に周りのカードを移動するためにマウスドラッグイベントを使用し、その後、イベントを拾う私はマウスプレスを登録することができ、これはカード上であったかどうかを確認するためにJLayeredPaneMouseListenerMouseMotionListenerを添加することにより開始し、最後にそれを戻すためのマウスリリース。これはすべて正常に動作し、ロギング情報を追加すると、mouseDraggedのコールバック関数が頻繁に呼び出されることがわかり、視覚的に速くドラッグすることができます。

今日私はJListのカードをダブルクリックするのではなく、手札からカードを「テーブル」にドラッグできるように機能を追加することにしたので、JListに適切なリスナーを追加しましたMousePressedMouseReleasedのようないくつかの関数を埋めています。マウスを押すと、リストのどのカードがクリックされたかを確認し、リストをロックしてカスタムCardPanelを作成します(ただし、まだどこにも追加しないで、割り当てて起動します)。ドラッグされたマウスでは、このフラグが設定されているかどうかをチェックします。そうであれば、カーソルの位置を確認します。もしそれがJLayeredPaneの上にあれば、私はCardPanelDRAG_LAYERに加え、別のフラグを設定します。この2番目のフラグがマウスドラッグの連続呼び出しで設定されている場合は、パネルをもう一度追加しませんが、場所を変更するだけです。この機能は、私の以前のマウスドラッグコールバックの機能と実質的に同じです。マウスを離すと、リストのロックが解除され、JLayeredPaneの正しいレイヤーにCardPanelを追加します。

すべてが意図したとおりに働いているので、私は私のコードは大丈夫ですかなり確信しているが、ちょうど1若干の問題があります:

(代わりの階層ペインから、階層化区画にリストからカードをドラッグするとmouseDraggedコールバックがJList(1秒あたり約10回)で非常に低い頻度で呼び出され、目に見えない遅延を導入していることがわかりました(ドラッグの最初のケースでは1秒あたり約30回)。

問題を明確にするためにコードスニペットを追加しますが、自分で実行できるようにするためにすべてのコードを追加するのは恐れがあります。

この投稿の主な質問は、mouseDraggedが1つだけ速く呼び出される理由を知っている人は誰ですかMouseMotionListenerよりもMouseMotionListenerよりも速く呼ばれていますか? JLayeredPaneコンポーネントへのリスナーは、高速連続呼び出しを行い、リスナーはJListへの呼び出しが大幅に遅くなります。

注:私はNetbeansで開発しており、組み込みのグラフィカルなSwing Interface Builderを使用しています。私はメインクラスとしてJFrameフォームを使用しています。

public class MyFrame extends JFrame{ 
    ... 
    protected JLayeredPane layeredPane; 
    protected JList cardsInHandList; 
    ... 

    ... 
    protected ArrayList<String> cardsInHand; 
    ... 

    private void attachListeners(){ 
     layeredPane.addMouseListener(new MouseAdapter(){ 
      public void MousePressed(MouseEvent e){ 
       // set a flag, start a drag 
      } 
      public void MouseReleased(MouseEvent e){ 
       // unset a flag, stop a drag 
      } 
     }); 
     layeredPane.addMouseMotionListener(new MouseMotionAdapter(){ 
      public void MouseDragged(MouseEvent e){ 
       // drag the card around 
       // gets called a lot! 

       // actual code: 
       if (e.getButton() == MouseEvent.BUTTON1) { 
       if (!dragging) return; // the flag 

       int x = e.getX() - 10; 
       int y = e.getY() - 10; 

       // snap to grid 
       x /= GRIDX; 
       x *= GRIDX; 

       y /= GRIDY; 
       y *= GRIDY; 

       // redraw the card at its new location 
       draggedCard.setLocation(x, y); 
      } 
      } 
     }); 

     cardsInHandList.addMouseListener(new MouseAdapter(){ 
      public void MousePressed(MouseEvent e){ 
       // set a flag, start a drag 
      } 
      public void MouseReleased(MouseEvent e){ 
       // unset a flag, stop a drag 
      } 
     }); 
     cardsInHandList.addMouseMotionListener(new MouseMotionAdapter(){ 
      public void MouseDragged(MouseEvent evt){ 
       // check cursor location, drag if within bounds of layeredPane 
       // gets called a whole lot less!! _Why?_ 

       // actual code: 
      if (!draggingFromHand) return; // the flag 

      // check location of cursor with own method (contains() didn't work for me) 
      if (isCursorAtPointAboveLayeredPane(evt.getLocationOnScreen())) { 

       // calculate where and snap to grid 
       int x = (int) (evt.getLocationOnScreen().getX() - layeredPane.getLocationOnScreen().getX())-10; 
       int y = (int) (evt.getLocationOnScreen().getY() - layeredPane.getLocationOnScreen().getY())-10; 

        // snap to grid 
       x /= GRIDX; 
       x *= GRIDX; 
       y /= GRIDY; 
       y *= GRIDY; 

        if(!draggingFromHandCardPanelAdded){ 
         layeredPane.add(draggingFromHandCardPanel, JLayeredPane.DRAG_LAYER); 
         draggingFromHandCardPanelAdded = true; 
        } else { 
        draggingFromHandCardPanel.setLocation(x,y); 
        } 
      } 
     } 
     }); 
    } 

私は、問題を再現短い実行可能な例を構築し、どこかのコードを添付しようとするでしょうが、今の私はskootになりました。事前に

おかげ

PS:私はTransferHandlersとを含む、Javaでドラッグする別の方法があることを認識していますすべてのことを、それはあまりにも多くの手間のように思える、それはへの実際の答えではありません1つのコールバックが他のコールバックよりも多く呼び出されているように見えるので、その代わりに使用するように教えてください。

+0

は多分、私が答えるのは難しい、ウナギの@Hovercraft完全によって多分偉大なポストがためにあなたを助けることができるので4に、質問を分離することを分割参照、グローバルなイベントリスナーを使用してより良い結果を得る可能性があります私がそこに見る15番目の質問の1つ http://stackoverflow.com/search?q=user%3A522444+DragLabelOnLayeredPane – mKorbel

答えて

2

リストの外にドラッグすると、Javaがリストの合成マウスイベントを生成し始めます。これが原因である可能性があります。 JComponent#setAutoscrolls(boolean)のjavadocを参照してください。

あなたは http://tips4java.wordpress.com/2009/08/30/global-event-listeners/