Java 如何在ChildComponent上保留MouseListener,但正确跟踪父组件上的鼠标进出?
我有一个带有卡片布局和两张卡片的JPanel。我希望布局在每次鼠标进入或退出面板时翻转卡片。 除非其中一张卡是侦听鼠标事件的组件,否则这种方法可以正常工作。考虑下面的例子:Java 如何在ChildComponent上保留MouseListener,但正确跟踪父组件上的鼠标进出?,java,swing,layout,components,cardlayout,Java,Swing,Layout,Components,Cardlayout,我有一个带有卡片布局和两张卡片的JPanel。我希望布局在每次鼠标进入或退出面板时翻转卡片。 除非其中一张卡是侦听鼠标事件的组件,否则这种方法可以正常工作。考虑下面的例子: JPanel cardLayoutPanel = new JPanel(layout); JButton button = new JButton("listening!"); JLabel label = new JLabel("not listening."); cardLayoutPanel.add(button);
JPanel cardLayoutPanel = new JPanel(layout);
JButton button = new JButton("listening!");
JLabel label = new JLabel("not listening.");
cardLayoutPanel.add(button);
cardLayoutPanel.add(label);
layout.last(cardLayoutPanel);
cardLayoutPanel.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
System.out.println("entered!");
layout.next(cardLayoutPanel);
}
@Override
public void mouseExited(MouseEvent e) {
System.out.println("exited!");
layout.next(cardLayoutPanel);
}
});
问题是,如果MouseEvent被子组件捕获,那么在许多与此主题相关的问题中,父组件不会将其作为read处理。
我尝试了不同的方法,比如重新修补事件,或者如果事件坐标仍在面板中,则忽略退出事件
第一个解决方案根本不起作用,第二个解决方案也不起作用。此后,鼠标输入的事件不再发生
我怎样才能解决这个问题
我现在看到的唯一解决方案是从子组件中完全删除侦听器,并在父鼠标侦听器中自己执行冲突和事件处理,但我想这将是一个混乱,不是预期的方法
感谢您的任何帮助或想法
编辑:下面是一个完整的简短可编译示例:
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class CardLayoutTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel content = new JPanel();
content.setBorder(new EmptyBorder(new Insets(50, 50, 50, 50)));
CardLayout layout = new CardLayout();
JPanel cardLayoutPanel = new JPanel(layout);
JButton button = new JButton("listening!");
JLabel label = new JLabel("not listening.");
cardLayoutPanel.add(button);
cardLayoutPanel.add(label);
layout.last(cardLayoutPanel);
cardLayoutPanel.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
System.out.println("entered!");
layout.next(cardLayoutPanel);
}
@Override
public void mouseExited(MouseEvent e) {
System.out.println("exited!");
layout.next(cardLayoutPanel);
}
});
content.add(cardLayoutPanel);
frame.add(content);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
这不是一个好的解决方案,但我通过在进入父组件时调用flip事件实现了我想要的。这是因为我的面板之间有足够的空间 然而,我并没有像评论中所说的那样,用玻璃窗来达到这种效果。也许我做错了,但是事件没有正确地到达组件,甚至一些瞬间的检查不知从哪里失败了
如果有人知道如何正确地做到这一点,我将很高兴看到 我稍微修改了你的示例,并使其生效。关键(至少在本例中)是让按钮与
cardLayoutPanel
共享相同的mouseListener
。我不知道这是否是一个普遍的解决方案,但它确实在这里起作用。我还做了以下修改:
鼠标事件是一种痛苦。只需添加一个鼠标侦听器就可以防止事件沿组件树向下传播!有损益表的地方,你无法确定发生了什么。重新修补为“玻璃窗格”应该会起作用。我知道,这正是这里的问题所在。损益表和财务报表是什么意思?你所说的“作为‘玻璃窗格’的redispatch”是什么意思?PL&F可插拔外观-使GUI看起来像一个特定平台的代码,无论是Windows、Metal、Gtk还是其他平台。应该有很多关于玻璃窗格的例子,玻璃窗格是容器顶部的一个组件,可以在鼠标事件通过时拦截鼠标事件。好的,谢谢你,我会看看是否可以用这种方法运行。非常感谢你的努力!我会看看a是否能让你的解决方案明天运行。好的。一项观察。我使用主程序中的
按钮
实例来单击按钮。更好的方法是从MouseEvent
获取源代码并将其转换为JButton,然后使用它执行doClick
。这样他们就可以共享相同的mouseListener
事实上,我只是尝试了一下,以确保语法正确,所以我会修改我的答案。
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
public class CardLayoutTest {
JButton button = new JButton("listening!");
JPanel cardLayoutPanel = new JPanel();
CardLayout layout = new CardLayout();
public static void main(String[] args) {
new CardLayoutTest().start();
}
public void start() {
JFrame frame = new JFrame();
JPanel content = new JPanel();
content.setBorder(new EmptyBorder(
new Insets(50, 50, 50, 50)));
cardLayoutPanel.setLayout(layout);
cardLayoutPanel
.setPreferredSize(new Dimension(200, 200));
button.addActionListener(
ae -> System.out.println("IT WORKS!"));
button.removeMouseMotionListener(
button.getMouseMotionListeners()[0]);
button.removeMouseListener(
button.getMouseListeners()[0]);
MyMouseListener ml = new MyMouseListener();
button.addMouseListener(ml);
button.setBorder(new LineBorder(Color.red, 2));
JLabel label = new JLabel("not listening.");
label.setBorder(new LineBorder(Color.blue, 2));
cardLayoutPanel.add(button);
cardLayoutPanel.add(label);
layout.last(cardLayoutPanel);
cardLayoutPanel.addMouseListener(ml);
content.add(cardLayoutPanel);
frame.add(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private class MyMouseListener extends MouseAdapter {
@Override
public void mouseEntered(MouseEvent e) {
System.out.println("entered!");
layout.next(cardLayoutPanel);
}
public void mouseClicked(MouseEvent e) {
if (e.getSource() instanceof JButton) {
JButton b = (JButton)(e.getSource());
b.doClick();
}
}
@Override
public void mouseExited(MouseEvent e) {
System.out.println("exited!");
layout.next(cardLayoutPanel);
}
}
}