MouseEvent 在 JScrollPane 中丢失
这是我用来显示我在另一个项目中面临的问题的代码.
This is the code I am using to show the issue which I am facing in another project.
如果我使用 JScrollPane 作为 panel2 的包装器,我不会得到任何这样的行.为什么?我想点击 JscrollPane 并打印如下事件.
I am not getting any line like this if I use JScrollPane as a wrapper for panel2. Why? I want to click on JscrollPane and got event printed as following.
java.awt.event.MouseEvent[MOUSE_CLICKED,(800,469),absolute(808,499),button=1,modifiers=Button1,clickCount=1] on javax.swing.JPanel[,0,0,934x612,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=javax.swing.border.LineBorder@cc0e01,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=880,height=630]]
如果我现在改变
panel1.add(pane);
到
panel1.add(panel2);
然后上面的消息就打印出来了.
Then the message above got printed.
public class LostMouseEvent {
public static void main(String[] args) {
new LostMouseEvent();
}
public LostMouseEvent() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
JScrollPane pane = new JScrollPane(panel2);
panel1.setPreferredSize(new Dimension(880, 630));
panel1.setBorder(BorderFactory.createLineBorder(Color.blue));
panel2.setPreferredSize(new Dimension(840, 610));
panel2.setBorder(BorderFactory.createLineBorder(Color.green));
panel1.add(pane);
frame.add(panel1);
frame.pack();
frame.setVisible(true);
frame.setSize(950, 650);
panel1.addMouseListener(new MyMouseListener());
}
});
}
private class MyMouseListener extends MouseAdapter {
@Override
public void mouseClicked (MouseEvent me) {
System.out.println(me);
}
}
}
UPD:事实上,在我的项目中不止一个 panel2.最初,我有 panel1 和许多 panel2 里面.然后我想用 JScrollPane 包装每个 panel2 并开始面对这个问题.
UPD: In fact in my project there is more than just one panel2. Originally, I had panel1 and many panel2 inside. Then I wanted to wrap each panel2 with JScrollPane and started to face this problem.
我只需要一个 MouseListener 就可以最大限度地减少对代码的更改.
I need to have only one MouseListener to minimize changes to the code.
推荐答案
- 使用 EDT 创建和操作 Swing 组件
- 在设置
JFrame
可见之前不要调用setSize()
而是调用pack()
. - 不要调用
setPrefferedSize()
而是覆盖getPrefferedSize()
- Use EDT for creation and manipulation of Swing components
- Dont call
setSize()
rather callpack()
before settingJFrame
visible. - Dont call
setPrefferedSize()
rather overridegetPrefferedSize()
您的代码按预期工作,只有在单击 panel1
时才会打印消息,请注意 panel1
在 JScrollPane
后面,因此外部的任何内容绿色边框是 panel1
.要使其适用于 JScrollpane
/panel2
和 JPanel
/panel1
只需添加 MouseListener
到 BOTH 的必需组件:
Your code works as expected, it will only print the message if panel1
is clicked, note panel1
is behind JScrollPane
, thus anything outside the green border is panel1
. To make it work for both the JScrollpane
/panel2
and JPanel
/panel1
simply add the MouseListener
to BOTH of the required components:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class LostMouseEvent {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new LostMouseEvent();
}
});
}
public LostMouseEvent() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
JPanel panel1 = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(880, 630);
}
};
JPanel panel2 = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(840, 610);
}
};
JScrollPane pane = new JScrollPane(panel2);
panel1.setBorder(BorderFactory.createLineBorder(Color.blue));
panel2.setBorder(BorderFactory.createLineBorder(Color.green));
panel1.add(pane);
frame.add(panel1);
MouseListener ml=new MyMouseListener();
//add mouse listener to panel1 and panel2
panel1.addMouseListener(ml);
panel2.addMouseListener(ml);
//alternatively add to pane
//pane.addMouseListener(ml);
frame.pack();
frame.setVisible(true);
}
});
}
private class MyMouseListener extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent me) {
System.out.println(me);
}
}
}
不过,我个人不建议这样做,
I personally would not recommend this, however,
要向 JFrame
添加单个侦听器以捕获所有 MouseEvent
,请使用 Toolkit
类并调用 addAWTEventListener
像这样:
To add a single listener to the JFrame
that will capture all MouseEvent
s use Toolkit
class and call addAWTEventListener
like so:
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent awte) {//all mouse events will be processed here you will have to check for the mouse events you are interested in
System.out.println(awte);
}
}, AWTEvent.MOUSE_EVENT_MASK);//for Mouse events only
更新 1:
您还可以通过 JFrame.getGlassPane().addMouseListener(ml)<将
MouseListener
添加到您的 JFrame
的 glasspane/code> 设置 JFrame
可见后,不要忘记设置 glasspane 可见.这将允许您只需要添加一个 Listener
.见这里:
You could also add the MouseListener
to your JFrame
s glasspane via JFrame.getGlassPane().addMouseListener(ml)
dont forget to set the glasspane visible after setting JFrame
visible. This will allow you to only have to add a single Listener
. See here:
...
MouseListener ml = new MyMouseListener();
//add mouse listener to panel1 and panel2
//panel1.addMouseListener(ml);
//panel2.addMouseListener(ml);
//alternatively add to pane
//pane.addMouseListener(ml);
frame.getGlassPane().addMouseListener(ml);
frame.pack();
frame.setVisible(true);
frame.getGlassPane().setVisible(true);
...
UPADTE 2:
MouseEvent
在 JScrollPane
中丢失的主要原因是因为它是一个错误.请参阅此处.
The main reason for you having the problem of the MouseEvent
getting lost in JScrollPane
is because its a bug. See here.
显示的解决方法是:
public Test()
{
setUI(new javax.swing.plaf.metal.MetalScrollPaneUI(){
public void installListeners(JScrollPane scrollPane){}
});
JPanel canvas = new JPanel();
canvas.add( new JLabel("Test") );
setViewportView( canvas );
setVisible(true);
}
相关文章