java - 拦截或委托(delegate)具有重叠组件的事件

标签 java swing events paintcomponent miglayout

我有两个大小相等的 JPanels,一个在另一个之上。顶层作为拖动选择面板,另一层添加了其他组件。我的问题是这些添加的组件的鼠标事件处理程序没有被触发,因为它们是由覆盖面板处理的。我怎样才能仍然拖过这些添加的组件的顶部,但仍然为底层组件启用 mouseEnteredmouseExited

这是截图:

enter image description here

如您所见,选择矩形绘制在覆盖的 JPanel 上,但好像我的鼠标无法穿过此面板以查看下面的内容(寻找更好的方法解释一下)。

最佳答案

重新发明轮子的替代方法是使用 JLayer(jdk7 的新功能,在 SwingLabs subproject JXLayer 中可用于 jdk6):

JLayer is a universal decorator for Swing components which enables you to implement various advanced painting effects as well as receive notifications of all AWTEvents generated within its borders

下面是一个简单的例子 - 只是为了演示它的用法,逻辑显然不完整:) - 用 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);

关于java - 拦截或委托(delegate)具有重叠组件的事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8782773/

相关文章:

java - 在 xml 文件中使用 CDATA 来解析 html 数据

java - 更改后 JLabel 图标不显示

excel - VBA - 事件内部事件(BeforeClose -> BeforeSave)不起作用

java - 在不同的核心上运行进程

java - 由于 java.lang.ArrayIndexOutOfBoundsException 无法打开图像

java - 当将值设置为特定列时,JTable Java 错误堆栈溢出

java - 我应该在哪里保存 JDBC 连接详细信息?

javascript - 在控制台中显示更改 slider 值

c# - 在接口(interface)中使用事件

java - 使用 Apache HttpClient 和负载平衡的 SharePoint REST 调用在首次 GET 后失败