MouseEvent потерян в JScrollPane
Это код, который я использую, чтобы показать проблему, с которой я сталкиваюсь в другом проекте.
Я не получаю никакой строки, как это, если я использую JScrollPane в качестве оболочки для Panel2. Зачем? Я хочу нажать на JscrollPane и напечатать событие следующим образом.
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);
Тогда сообщение выше было напечатано.
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: На самом деле в моем проекте больше, чем одна панель2. Первоначально у меня были panel1 и много panel2 внутри. Затем я хотел обернуть каждую панель 2 с помощью JScrollPane и начал сталкиваться с этой проблемой.
Мне нужно иметь только один MouseListener, чтобы минимизировать изменения в коде.
2 ответа
- Используйте EDT для создания и управления компонентами Swing
- Не звоните
setSize()
скорее позвониpack()
перед установкойJFrame
видимый. - Не звоните
setPrefferedSize()
скорее переопределитьgetPrefferedSize()
Ваш код работает, как и ожидалось, он напечатает сообщение, только если panel1
нажата, обратите внимание panel1
позади JScrollPane
Таким образом, все, что находится за пределами зеленой границы panel1
, Чтобы он работал как для JScrollpane
/ panel2
а также JPanel
/ panel1
просто добавьте MouseListener
ОБА требуемых компонентов:
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);
}
}
}
РЕДАКТИРОВАТЬ:
Я лично не рекомендовал бы это, однако,
Чтобы добавить одного слушателя к JFrame
это захватит все MouseEvent
использование Toolkit
класс и вызов addAWTEventListener
вот так:
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:
Вы также можете добавить MouseListener
на ваш JFrame
Стеклянное стекло через JFrame.getGlassPane().addMouseListener(ml)
не забудьте установить стекло, видимое после настройки JFrame
видимый. Это позволит вам только добавить один Listener
, Посмотреть здесь:
...
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);
...
УПАДТЕ 2:
Основная причина возникновения у вас проблемы MouseEvent
заблудиться в JScrollPane
потому что это ошибка. Смотрите здесь.
Обходное решение показано:
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);
}
MouseEvent потерян в JScrollPane
ответ очень / довольно прост, убедитесь, что нет ничего ни о потерянных событиях, ни с JScrollPane,
Swing JComponent может запускать событие только в том случае, если там добавлен соответствующий слушатель
Вы не добавили MouseListener во второй JPanel,
этот JPanel помещается в родительский JPanel, этот родительский объект добавил MouseListener, а затем запускает mouseEvent, конечно, в вашем случае только за пределами границ 2-го JPanel, добавленных в этот контейнер
затем 2-й JPanel является deepestComponentAt, и не возможно событие пожара без повторной отправки координат от родителя к потомку
Вы можете перезапустить событие также программно,