修复 JFrame 中重叠的 MouseListeners
Fix overlapping MouseListeners in JFrame
我 运行 遇到了 MouseListener
似乎相互重叠的问题。
在我的应用程序的 GUI class 中,我添加了@camickr 的 ComponentResizer
class 并注册了我的 JFrame
。当没有子组件时,或者当我不向子组件添加其他 MouseListener
时,它工作正常。但是当我这样做时,子组件似乎具有侦听器优先级,并且我无法调整北边界的大小。
我尝试了 addAWTEventListener()
方法,如下所示:
Toolkit.getDefaultToolkit().addAWTEventListener(event -> {
if (event instanceof MouseEvent) {
MouseEvent e = (MouseEvent) event;
if (e.getSource() == MainGUI.getMainFrame()) {
switch (e.getID()) {
case MouseEvent.MOUSE_CLICKED -> mouseClicked(e);
case MouseEvent.MOUSE_PRESSED -> mousePressed(e);
case MouseEvent.MOUSE_RELEASED -> mouseReleased(e);
case MouseEvent.MOUSE_ENTERED -> mouseEntered(e);
case MouseEvent.MOUSE_EXITED -> mouseExited(e);
case MouseEvent.MOUSE_DRAGGED -> mouseDragged(e);
case MouseEvent.MOUSE_MOVED -> mouseMoved(e);
default -> {}
}
}
}
}, AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
但是结果很奇怪,框架中的所有组件都可以同时调整大小。
这是问题的 SSCCE:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MainGUI {
private static JFrame mainFrame;
private static JPanel contentPane;
private static JPanel titleBar;
private static ComponentResizer resizer = new ComponentResizer();
public static void init() {
mainFrame = new JFrame();
contentPane = new JPanel();
titleBar = new JPanel();
titleBar.add(new JLabel("This is a title"));
titleBar.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
// Problematic part. The resizer works correctly without it.
titleBar.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("You clicked me!");
}
});
contentPane.setLayout(new BorderLayout());
contentPane.add(titleBar, BorderLayout.NORTH);
mainFrame.setContentPane(contentPane);
mainFrame.setPreferredSize(new Dimension(600, 400));
mainFrame.setUndecorated(true);
resizer.registerComponent(mainFrame);
}
public static void display() {
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setEnabled(true);
mainFrame.setVisible(true);
mainFrame.requestFocus();
}
public static JFrame getMainFrame() {
return mainFrame;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException |
IllegalAccessException | UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
MainGUI.init();
MainGUI.display();
});
}
}
这里是 ComponentResizer
class:
http://www.camick.com/java/source/ComponentResizer.java
所以问题是,有没有办法让 JFrame
的监听器在子组件监听器的“顶部”?
is there a way to keep the JFrame's listeners "on top" of the subcomponents listeners?
据我所知没有。只有一个组件可以接收 MouseEvent。
Swing 将从底部(parent / child 组件链)到顶部搜索组件以查找具有 MouseListener 的组件并将事件传递给该组件。所以第一个发现有侦听器的组件将接收事件。
一种解决方案是为您的标题栏提供一个带有 Border
.
的“包装器”面板
例如:
// Create wrapper panel with a border
JPanel wrapper = new JPanel(new BorderLayout());
wrapper.setBorder( new EmptyBorder(5, 5, 5, 5) );
wrapper.add(titleBar);
contentPane.add(wrapper, BorderLayout.NORTH);
//contentPane.add(titleBar, BorderLayout.NORTH);
现在您的标题栏将不会延伸到框架的边缘,因此当鼠标位于边缘的 5 个像素以内时,MouseEvent 将被传递到框架。
如果您希望 LineBorder
完全延伸到框架的边缘,您也可以从标题栏中删除边框并在包装面板上使用 CompoundBorder
。
请注意,您也可能会向 BorderLayout 的 CENTER 添加组件。如果这些组件中的任何一个具有 MouseListener,您将遇到同样的问题。根据您的要求,您可能需要考虑将 EmptyBorder 添加到框架的内容窗格中。这样您就可以有效地为整个框架添加边框。
我 运行 遇到了 MouseListener
似乎相互重叠的问题。
在我的应用程序的 GUI class 中,我添加了@camickr 的 ComponentResizer
class 并注册了我的 JFrame
。当没有子组件时,或者当我不向子组件添加其他 MouseListener
时,它工作正常。但是当我这样做时,子组件似乎具有侦听器优先级,并且我无法调整北边界的大小。
我尝试了 addAWTEventListener()
方法,如下所示:
Toolkit.getDefaultToolkit().addAWTEventListener(event -> {
if (event instanceof MouseEvent) {
MouseEvent e = (MouseEvent) event;
if (e.getSource() == MainGUI.getMainFrame()) {
switch (e.getID()) {
case MouseEvent.MOUSE_CLICKED -> mouseClicked(e);
case MouseEvent.MOUSE_PRESSED -> mousePressed(e);
case MouseEvent.MOUSE_RELEASED -> mouseReleased(e);
case MouseEvent.MOUSE_ENTERED -> mouseEntered(e);
case MouseEvent.MOUSE_EXITED -> mouseExited(e);
case MouseEvent.MOUSE_DRAGGED -> mouseDragged(e);
case MouseEvent.MOUSE_MOVED -> mouseMoved(e);
default -> {}
}
}
}
}, AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
但是结果很奇怪,框架中的所有组件都可以同时调整大小。
这是问题的 SSCCE:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MainGUI {
private static JFrame mainFrame;
private static JPanel contentPane;
private static JPanel titleBar;
private static ComponentResizer resizer = new ComponentResizer();
public static void init() {
mainFrame = new JFrame();
contentPane = new JPanel();
titleBar = new JPanel();
titleBar.add(new JLabel("This is a title"));
titleBar.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
// Problematic part. The resizer works correctly without it.
titleBar.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("You clicked me!");
}
});
contentPane.setLayout(new BorderLayout());
contentPane.add(titleBar, BorderLayout.NORTH);
mainFrame.setContentPane(contentPane);
mainFrame.setPreferredSize(new Dimension(600, 400));
mainFrame.setUndecorated(true);
resizer.registerComponent(mainFrame);
}
public static void display() {
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setEnabled(true);
mainFrame.setVisible(true);
mainFrame.requestFocus();
}
public static JFrame getMainFrame() {
return mainFrame;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException |
IllegalAccessException | UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
MainGUI.init();
MainGUI.display();
});
}
}
这里是 ComponentResizer
class:
http://www.camick.com/java/source/ComponentResizer.java
所以问题是,有没有办法让 JFrame
的监听器在子组件监听器的“顶部”?
is there a way to keep the JFrame's listeners "on top" of the subcomponents listeners?
据我所知没有。只有一个组件可以接收 MouseEvent。
Swing 将从底部(parent / child 组件链)到顶部搜索组件以查找具有 MouseListener 的组件并将事件传递给该组件。所以第一个发现有侦听器的组件将接收事件。
一种解决方案是为您的标题栏提供一个带有 Border
.
例如:
// Create wrapper panel with a border
JPanel wrapper = new JPanel(new BorderLayout());
wrapper.setBorder( new EmptyBorder(5, 5, 5, 5) );
wrapper.add(titleBar);
contentPane.add(wrapper, BorderLayout.NORTH);
//contentPane.add(titleBar, BorderLayout.NORTH);
现在您的标题栏将不会延伸到框架的边缘,因此当鼠标位于边缘的 5 个像素以内时,MouseEvent 将被传递到框架。
如果您希望 LineBorder
完全延伸到框架的边缘,您也可以从标题栏中删除边框并在包装面板上使用 CompoundBorder
。
请注意,您也可能会向 BorderLayout 的 CENTER 添加组件。如果这些组件中的任何一个具有 MouseListener,您将遇到同样的问题。根据您的要求,您可能需要考虑将 EmptyBorder 添加到框架的内容窗格中。这样您就可以有效地为整个框架添加边框。