Java 通过JScrollPane异常行为重新调度MouseeEvent
我在这里修改了一些代码: 由于已知JScrollPane有一个bug没有向上传递MouseeEvent,所以我对FakeMouseListener做了一个变通Java 通过JScrollPane异常行为重新调度MouseeEvent,java,swing,mouseevent,jscrollpane,dispatchevent,Java,Swing,Mouseevent,Jscrollpane,Dispatchevent,我在这里修改了一些代码: 由于已知JScrollPane有一个bug没有向上传递MouseeEvent,所以我对FakeMouseListener做了一个变通 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.EventQueue; import j
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.LayoutManager;
import java.awt.Point;
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 {
private JPanel panel1;
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());
panel1 = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(600, 400);
}
};
JPanel panel2 = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(500, 300);
}
};
JScrollPane pane = new JScrollPane(panel2);
panel1.setBorder(BorderFactory.createLineBorder(Color.blue));
panel2.setBorder(BorderFactory.createLineBorder(Color.green));
panel1.setLayout(new CircleLayout());
panel1.add(pane);
frame.add(panel1);
MouseListener rml = new RealMouseListener();
panel1.addMouseListener(rml);
MouseListener fml = new FakeMouseListener();
pane.addMouseListener(fml);
frame.pack();
frame.setVisible(true);
}
});
}
private class RealMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent me) {
System.out.println(me);
Point point = me.getPoint();
System.out.println(panel1.getComponentAt(point));
System.out.println(panel1.getComponent(0));
}
}
private class FakeMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent me) {
panel1.dispatchEvent(me);
}
}
}
现在,如果单击左侧边框旁边的绿色边框内,我会得到:
java.awt.event.MouseEvent[MOUSE_PRESSED,(9,169),absolute(66,248),button=1,modifiers=Button1,extModifiers=Button1,clickCount=1] on javax.swing.JScrollPane[,49
LostMouseEvent$2$1[,0,0,600x400,layout=CircleLayout,alignmentX=0.0,alignmentY=0.0,border=javax.swing.border.LineBorder@633d51
javax.swing.JScrollPane[,49,49,503x303,layout=javax.swing.ScrollPaneLayout$UIResource,alignmentX=0.0,alignmentY=0.0,
如果我在中间点击,我得到:
java.awt.event.MouseEvent[MOUSE_PRESSED,(247,147),absolute(304,226),button=1,modifiers=Button1,extModifiers=Button1,clickCount=1] on javax.swing.JScrollPane[,
javax.swing.JScrollPane[,49,49,503x303,layout=javax.swing.ScrollPaneLayout$UIResource,alignmentX=0.0,alignmentY=0.0,border=javax.swing.plaf.metal.
javax.swing.JScrollPane[,49,49,503x303,layout=javax.swing.ScrollPaneLayout$UIResource,alignmentX=0.0,alignmentY=0.0,border=javax.swing.plaf.metal.
为什么?当我重新分派MouseeEvent时,是否需要修改其坐标?
圆形布局的代码为
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager;
public class CircleLayout implements LayoutManager {
private int heightGap;
public CircleLayout () {
heightGap = 0;
}
public CircleLayout (int heightGap) {
this.heightGap = heightGap;
}
/**
* Arranges the parent's Component objects in either an Ellipse or a Circle.
* Ellipse is not yet implemented.
*/
public void layoutContainer (Container parent) {
int x, y, w, h, s, c;
int childCompNum = parent.getComponentCount();
int parentWidth = (int)parent.getSize().width;
int parentHeight = (int)parent.getSize().height;
int centerX = (int) (parentWidth / 2);
int centerY = (int) (parentHeight / 2);
double angleOffset = 0.5 * Math.PI;
Component childComp = null;
for (int i = 0; i < childCompNum; i++) {
childComp = parent.getComponent(i);
w = childComp.getPreferredSize().width;
h = childComp.getPreferredSize().height;
if (childCompNum == 1) {
x = centerX - (int)w / 2;
y = centerY - (int)h / 2;
} else {
c = (int) (centerX * Math.cos((2 * i * Math.PI + angleOffset) / childCompNum));
s = (int) (centerY * Math.sin((2 * i * Math.PI + angleOffset) / childCompNum));
x = c + centerX - (int)w / 2;
y = s + centerY - (int)h / 2;
if (x + w > parentWidth) {x = (int)(parentWidth - w); }
if (y + h + heightGap > parentHeight) {y = (int)(parentHeight - h -heightGap); }
if (x < 0) {x = 0; }
if (y < 0) {y = 0; }
}
childComp.setBounds(x, y, w, h);
}
}
/** For compatibility with LayoutManager interface */
public void addLayoutComponent (String name, Component comp) {}
public Dimension preferredLayoutSize(Container target) {
return target.getSize();
}
public Dimension minimumLayoutSize(Container target) {
return target.getSize();
}
public void removeLayoutComponent(Component comp) {}
}
但是有相同的行为。代码
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Rectangle;
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 {
private JPanel panel1;
private JPanel panel2 = new JPanel();
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
LostMouseEvent lostMouseEvent = 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());
panel1 = new JPanel() {
private static final long serialVersionUID = 1L;
@Override
public Dimension getPreferredSize() {
return new Dimension(600, 400);
}
};
panel2 = new JPanel() {
private static final long serialVersionUID = 1L;
@Override
public Dimension getPreferredSize() {
return new Dimension(500, 300);
}
};
JScrollPane pane = new JScrollPane(panel2);
panel1.setBorder(BorderFactory.createLineBorder(Color.blue));
panel2.setBorder(BorderFactory.createLineBorder(Color.green));
panel1.setLayout(new CircleLayout());
panel1.add(pane);
frame.add(panel1);
MouseListener rml = new RealMouseListener();
panel1.addMouseListener(rml);
MouseListener fml = new FakeMouseListener();
panel2.addMouseListener(fml);
frame.pack();
frame.setVisible(true);
}
});
}
private class RealMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent me) {
Rectangle rec = SwingUtilities.convertRectangle(panel2, panel2.getVisibleRect(), panel1);
System.out.println(me);
Point point = me.getPoint();
System.out.println(panel1.getComponentAt(point));
System.out.println(panel1.getComponent(0));
}
}
private class FakeMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent me) {
JScrollPane pane = (JScrollPane) me.getSource();
MouseEvent newMe = SwingUtilities.convertMouseEvent(pane, me, pane.getViewport());
panel1.dispatchEvent(me);
}
}
}
返回
转换为javax.swing.JScrollPane
以AAA_格式.LostMouseEvent$FakeMouseListener.mousePressed(LostMouseEvent.java:95)
位于java.awt.Component.ProcessMouseeEvent(Component.java:6264)
位于javax.swing.JComponent.ProcessMouseeEvent(JComponent.java:3267)
位于java.awt.Component.processEvent(Component.java:6032)
位于java.awt.Container.processEvent(Container.java:2041)
位于java.awt.Component.dispatchEventImpl(Component.java:4630)
位于java.awt.Container.dispatchEventImpl(Container.java:2099)
位于java.awt.Component.dispatchEvent(Component.java:4460)
位于java.awt.LightweightDispatcher.RetargetMouseeEvent(Container.java:4577)
位于java.awt.LightweightDispatcher.ProcessMouseeEvent(Container.java:4235)
位于java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
位于java.awt.Container.dispatchEventImpl(Container.java:2085)
位于java.awt.Window.dispatchEventImpl(Window.java:2478)
位于java.awt.Component.dispatchEvent(Component.java:4460)
位于java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
位于java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
位于java.awt.EventDispatchThread.PumpeEventsforFilter(EventDispatchThread.java:184)
位于java.awt.EventDispatchThread.PumpeEventsforHierarchy(EventDispatchThread.java:174)
位于java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
位于java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
在java.awt.EventDispatchThread.run处(EventDispatchThread.java:122)
编辑
编辑2
更符合逻辑的是,可以从FakeMouseListener内部替换
JScrollPane pane = (JScrollPane) me.getSource();
MouseEvent newMe = SwingUtilities.convertMouseEvent(pane.getViewport(), me, panel1);
到
(再次)必须使用SwingUtilities.convertXxxXxx与儿童v.s.parent相关,问题循环布局来自本论坛,由ateraipi-pi-pi。。。piiiip,非常理解,但为了避免将其用于复合JC组件(必须派生到childs brrrr),有两个问题,必须确定鼠标单击是否包含子JPanel,边界是否有效,如果是,则将事件从父JPanel分派给子,否则事件对父JPanel保持有效,请注意,也可能存在对边框有效的点,不要忘记:-)您将“永远”将点从子对象转换为JScrollPane,因为我需要了解woodoo,将点从子对象转换为JViewport很简单,JViewport是关于JScrollPane的可见矩形,查看从一个窗口到另一个窗口的事件是关于所需的dispatchEvent(),尝试调整大小,移动,但如果JViewport中包含,则我将错过该窗口,必须添加(没有人知道,减去一个可能的异常)@mKorbel我不太了解所有这些。但是我想一直使用panel1.getComponentAt(point)来获取JScrollPane。修改MouseEvent的坐标是否足够?panel2.添加MouseListener(fml);这是为什么?只要复制粘贴我问题中的代码并根据Lysee edit2更新FakeMouseListener,这个坐标看起来是正确的,这就是发布修改代码的原因…@mKorblel,这太棒了!您刚刚在最后一行输入了panel1.dispatchEvent(我);调度的是旧事件,而不是新事件。
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: AAA_Format.LostMouseEvent$2$2 cannot be
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
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 {
private JPanel panel1;
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());
panel1 = new JPanel() {
private static final long serialVersionUID = 1L;
@Override
public Dimension getPreferredSize() {
return new Dimension(600, 400);
}
};
JPanel panel2 = new JPanel() {
private static final long serialVersionUID = 1L;
@Override
public Dimension getPreferredSize() {
return new Dimension(500, 300);
}
};
JScrollPane pane = new JScrollPane(panel2);
panel1.setBorder(BorderFactory.createLineBorder(Color.blue));
panel2.setBorder(BorderFactory.createLineBorder(Color.green));
panel1.setLayout(new CircleLayout());
panel1.add(pane);
frame.add(panel1);
MouseListener rml = new RealMouseListener();
panel1.addMouseListener(rml);
MouseListener fml = new FakeMouseListener();
pane.addMouseListener(fml);
frame.pack();
frame.setVisible(true);
}
});
}
private class RealMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent me) {
System.out.println(me);
Point point = me.getPoint();
System.out.println(me.getX());
System.out.println(me.getXOnScreen());
System.out.println(me.getY());
System.out.println(me.getYOnScreen());
}
}
private class FakeMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent me) {
JScrollPane pane = (JScrollPane) me.getSource();
MouseEvent newMe = SwingUtilities.convertMouseEvent(pane.getViewport(), me, panel1);
System.out.println(newMe.getX());
System.out.println(newMe.getXOnScreen());
System.out.println(newMe.getY());
System.out.println(newMe.getYOnScreen());
panel1.dispatchEvent(me);
}
}
}
JScrollPane pane = (JScrollPane) me.getSource();
MouseEvent newMe = SwingUtilities.convertMouseEvent(pane.getViewport(), me, panel1);
JPanel panel2 = (JPanel) me.getSource();
MouseEvent newMe = SwingUtilities.convertMouseEvent(panel2, me, panel1);