9

Swing でのイベントの伝播を理解するのに助けが必要です。各イベントが 1 つのコンポーネントのみによって処理されることはわかっています。したがって、outsideいくつかの子パネルを持つパネルがinsideあり、両方に mouseListeners を追加すると、そのうちの 1 つinsideが呼び出されます。それは素晴らしいことであり、それが期待される動作です。

しかし、次の状況での動作がわかりません: MouseMotionListener を登録しinside、MouseListener をoutside登録します。insideには通常の MouseEvents のリスナーがないため、すべての MouseMotionEvents を消費しoutside、MouseEvents を受け取ることを期待していinsideます。しかし、そうではなく、insideどうにかして MouseMotionEvents だけでなく、すべての MouseEvents を消費します。

次のコードは、問題を示しています。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class EventTest {
public static void main(String... args) {
    SwingUtilities.invokeLater(new Runnable(){
        @Override
        public void run() {
            JComponent inside = new JPanel(); 
            inside.setBackground(Color.red);
            inside.setPreferredSize(new Dimension(200,200));
            MouseMotionListener mm = new MouseMotionListener() {
                @Override
                public void mouseDragged(MouseEvent arg0) {
                    System.err.println("dragged");                      
                }
                @Override
                public void mouseMoved(MouseEvent arg0) {
                    System.err.println("moved");
                }
            };
            // next line disables handling of mouse clicked events in outside 
            inside.addMouseMotionListener(mm); 

            JComponent outside = new JPanel();
            outside.add(inside);
            outside.setPreferredSize(new Dimension(300,300));
            outside.addMouseListener( new MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    System.err.println("clicked");
                }
            });

            JFrame frame = new JFrame();
            frame.add(outside);
            frame.pack();
            frame.setVisible(true);
        }
    });
    }
}

inside親コンポーネントが関心を持つ可能性のあるすべてのイベントに対してリスナーを登録し、dispatchEvent を呼び出してイベントを親に転送することで、この問題を回避できます。

a)誰かがこの動作が説明されているいくつかのドキュメントを教えてもらえますか?MouseEvent の Javadoc を見て、私の期待は正しかったと思いました。したがって、それを理解するには別の説明が必要です。

b) 上記のスケッチよりも優れた解決策はありますか?

ありがとう、カトリン

編集: Swing がこのように動作する理由はまだ不明です。しかし、どうやら、物事を機能させる唯一の方法は、イベントを手動で転送することです。私はそうします。

4

3 に答える 3

8

a)設計上、Java マウス イベントは、子コンポーネントにマウス リスナーがない場合にのみ「バブルアップ」します。

b)ここと下に示すように、イベントを別のコンポーネントに転送できます。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class EventTest {

    public static void main(String... args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                final JComponent outside = new JPanel();
                JComponent inside = new JPanel();
                inside.setBackground(Color.red);
                inside.setPreferredSize(new Dimension(200, 200));
                inside.addMouseMotionListener(new MouseAdapter() {

                    @Override
                    public void mouseDragged(MouseEvent e) {
                        System.err.println("dragged");
                    }

                    @Override
                    public void mouseMoved(MouseEvent e) {
                        System.err.println("moved inside");
                        outside.dispatchEvent(e);
                    }
                });

                outside.add(inside);
                outside.setPreferredSize(new Dimension(300, 300));
                outside.addMouseMotionListener(new MouseAdapter() {

                    @Override
                    public void mouseMoved(MouseEvent arg0) {
                        System.err.println("moved outside");
                    }
                });

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(outside);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}
于 2012-08-06T17:58:54.460 に答える
1

Trashgod の回答と非常によく似てMouseAdapterいます。モーション リスナーとして a を使用し、それをオーバーライドして、親によって処理されるイベントを転送できます。これにより、コードに最小限の量しか追加されません。

        MouseAdapter mm = new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent arg0) {
                System.err.println("dragged");                      
            }
            @Override
            public void mouseMoved(MouseEvent arg0) {
                System.err.println("moved");
            }
            @Override
            public void mouseClicked(MouseEvent e) {
                outside.dispatchEvent(e);
            }
        };
        // For forwarding events
        inside.addMouseListener(mm); 
        // For consuming events you care about
        inside.addMouseMotionListener(mm);

私もこの方法を使用するdispatchEvent(e)方法を見つけることができませんでした。あなたはそのルートに行き詰まっていると思います。

于 2012-08-06T18:13:57.040 に答える