4

私は2つのJPanels同じサイズを持っています。最上層はドラッグ選択パネルとして機能し、もう1つの層には他のコンポーネントが追加されています。私の問題は、これらの追加されたコンポーネントのマウスイベントハンドラーがトリガーされないことです。これらは代わりにオーバーレイパネルによって処理されるためです。mouseEnteredこれらの追加されたコンポーネントの上部をドラッグしても、下にあるコンポーネントをmouseExited有効にしておくにはどうすればよいですか?

これがスクリーンショットです:

ここに画像の説明を入力してください

ご覧のとおり、選択範囲の長方形はオーバーレイJPanelに描かれていますが、マウスがこのパネルを通り抜けて下にあるものを確認できないようです(それを説明するためのより良い方法を探しています)。

4

2 に答える 2

5

車輪の再発明の代わりに、JLayer(jdk7の新機能、SwingLabsサブプロジェクトJXLayerのjdk6で使用可能)を使用することもできます。

JLayerは、Swingコンポーネントのユニバーサルデコレータであり、さまざまな高度なペイントエフェクトを実装したり、境界内で生成されたすべてのAWTEventの通知を受信したりできます。

以下は、その使用法を示すための簡単な例です。ロジックは明らかに不完全です:)-mouseEventsでラバーバンドをスパンする例

// UI which allows to span a rubberband on top of the component
public static class RubberBandUI<V extends JComponent> extends LayerUI<V> {
    private JLayer<?> l;
    private Rectangle rubberband;
    private boolean selecting;

    @Override
    public void installUI(JComponent c) {
        super.installUI(c);
        l = (JLayer<?>) c;
        // this LayerUI will receive mouse/motion events
        l.setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
     }

     @Override
    public void uninstallUI(JComponent c) {
        super.uninstallUI(c);
        // JLayer must be returned to its initial state
        l.setLayerEventMask(0);
        l = null;
     }

    @Override
    public void paint(Graphics g, JComponent l) {
        // this paints layer as is
        super.paint(g, l);
        if (rubberband == null) return;
        Graphics2D g2 = (Graphics2D) g;
        // custom painting is here
        g2.setColor(Color.RED);
        g2.setStroke(new BasicStroke(2f));
        g2.draw(rubberband);
    }

    // intercept events as appropriate 

    @Override
    protected void processMouseMotionEvent(MouseEvent e, JLayer<? extends V> l) {
        super.processMouseMotionEvent(e, l);
        if (e.getID() == MouseEvent.MOUSE_DRAGGED && selecting) {
            Point point = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), l);
            adjustRubberband(point);
            l.repaint();
        }
    }

    @Override
    protected void processMouseEvent(MouseEvent e, JLayer<? extends V> l) {
        super.processMouseEvent(e, l);
        if (e.getID() == MouseEvent.MOUSE_RELEASED) {
            endRubberband();
        }
        if (e.getID() == MouseEvent.MOUSE_PRESSED && e.getSource() == l) {
            startRubberband(e.getPoint());
        }
    }

    // logic to start/stop/adjust the rubberband 
    private void adjustRubberband(Point point) {
        // logic to span the rubberband
        int width = point.x - rubberband.x;
        int height = point.y - rubberband.y;
        rubberband.setSize(width, height);
    }

    private void startRubberband(Point p) {
        rubberband = new Rectangle(p);
        selecting = true;
        // block events to child components while drawing
        l.getGlassPane().setVisible(true);
        l.repaint();
    }

    private void endRubberband() {
        selecting = false;
        l.getGlassPane().setVisible(false);
        l.repaint();
    }

    public void clear() {
        rubberband = null;
        l.repaint();
    }
}

サンプル使用スニペット:

JPanel panel = new JPanel();
for (int i = 0; i < 3; i++) {
    panel.add(new JButton("JButton"));
    panel.add(new JCheckBox("JCheckBox"));
    panel.add(new JTextField("JTextField"));
}
JLayer<JComponent> l = new JLayer<JComponent>(panel, new RubberBandUI<JComponent>());
frame.add(l);
于 2012-01-09T10:54:24.223 に答える
3

オーバーレイパネルは使用しないでください。前回の投稿で、これをどのように行うかについて提案しました。

または、オーバーレイパネルを使用する場合は、それを描画に使用し、基になるパネルでマウスイベントをリッスンしてから、オーバーレイパネルで再描画を呼び出します。

編集:

おそらく、より良いアプローチは、個々のコンポーネントでMouseListenerを使用してから、長方形の描画を処理するために、グローバルイベントリスナーを使用して、mousePressed、mouseDragged、mouseReleasedイベントをリッスンすることです。各イベントのソースをチェックして、ソースがパネル自体またはパネル上のコンポーネントであるかどうかを確認する必要があります。SwingUtilities.isDescendingFrom(...)この2番目のテストを支援するために使用できます。

于 2012-01-09T01:13:27.483 に答える