public void mousePressed(MouseEvent e) {
//Invoked when a mouse button has been pressed on a component.
if (e.getButton() == MouseEvent.BUTTON1) {
isDown = true;
System.out.println("isDown is now true");
}
if (e.getButton() == MouseEvent.BUTTON3) {
isDown2 = true;
System.out.println("isDown2 is now true");
}
do {
Point location = MouseInfo.getPointerInfo().getLocation();
int x = location.x - (drawingPanel.getLocationOnScreen()).x;
int y = location.y - (drawingPanel.getLocationOnScreen()).y;
drawingPanel.paint(drawingPanel.getGraphics(), (x - (x % 20) - 1), (y - (y % 20) - 1), 19, 19);
} while (isDown);
System.out.println("Mouse has been pressed down.");
}
public void mouseReleased(MouseEvent e) {
//Invoked when a mouse button has been released on a component.
if (e.getButton() == MouseEvent.BUTTON1) {
isDown = false;
System.out.println("isDown is now false");
}
if (e.getButton() == MouseEvent.BUTTON3) {
isDown2 = false;
System.out.println("isDown2 is now false");
}
System.out.println("Mouse has been released.");
}
这是我到目前为止所拥有的。我最初的意图是设计代码,以便在按下鼠标时将布尔isDown
设置为true,然后在while
为真时我将运行isDown
循环。如果释放鼠标按钮,我会将isDown
设置为false以终止while
循环。
我在这里搞砸了什么?两个MouseEvent方法不可能同时运行吗? isDown
布尔变量的更改未被注册,我的手上有一个无限循环。
答案 0 :(得分:7)
这是对事件调度线程的经典违反。
所有UI代码都在一个线程内运行。所有事件都从同一个线程调度UI,这意味着如果您阻止此线程(使用循环或其他阻塞操作),则不会调度任何事件。这将使您的程序看起来像挂起。
请查看Concurrency in Swing了解详情。
您真正应该做的是使用MouseMoitionListener
来跟踪拖动事件。查看How to use Mouse Listeners了解详情。
这drawingPanel.paint(drawingPanel.getGraphics(), (x - (x % 20) - 1), (y - (y % 20) - 1), 19, 19);
也让我无所适从。
您永远不应该使用getGraphics
来执行自定义绘画。 getGraphics
可以返回null,只是最后一个绘制周期的快照。使用此方法完成的任何绘制将在发生另一次重绘时被删除/清除。
您应该创建自定义组件(例如JPanel
)并覆盖它的paintComponent
方法并执行其中所需的任何绘画。查看Performing Custom Painting了解更多详情
示例强>
public class MouseDraggedTest {
public static void main(String[] args) {
new MouseDraggedTest();
}
public MouseDraggedTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Map<Point, List<Point>> mapPoints;
private Point currentPoint;
public TestPane() {
mapPoints = new HashMap<>(25);
MouseAdapter mouseListener = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
currentPoint = e.getPoint();
mapPoints.put(currentPoint, new ArrayList<Point>(25));
}
@Override
public void mouseReleased(MouseEvent e) {
List<Point> points = mapPoints.get(currentPoint);
if (points.isEmpty()) {
mapPoints.remove(currentPoint);
}
currentPoint = null;
}
@Override
public void mouseDragged(MouseEvent me) {
List<Point> points = mapPoints.get(currentPoint);
points.add(me.getPoint());
repaint();
}
};
addMouseListener(mouseListener);
addMouseMotionListener(mouseListener);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Point startPoint : mapPoints.keySet()) {
List<Point> points = mapPoints.get(startPoint);
for (Point p : points) {
if (startPoint != null) {
g.drawLine(startPoint.x, startPoint.y, p.x, p.y);
}
startPoint = p;
}
}
}
}
}
答案 1 :(得分:2)
您正在while
方法中执行mousePressed()
循环。这意味着你正在阻止Swing Event Dispatch Thread!由于只要isDown
为真,此方法就不会返回,那么执行将不会返回到侦听器处理程序,该处理程序将永远不会调用您的mouseReleased()
侦听器。
作为一般规则,您永远不应在侦听器中启动长时间运行的操作,因为只要它运行,您的GUI就不会响应任何事件。在这种情况下,这意味着永远!任何监听器都不应该做多设置几个标志,然后返回。您的应用程序必须保持响应。
一个典型的解决方案是启动一个新线程来执行长时间运行的工作。它将释放Event Dispatching Thread并调用mouseReleased()侦听器。
此解决方案的问题在于您的工作是在Swing组件上绘制。所有图形都应该以覆盖paintComponent
方法完成。正如@MadProgrammer已经在解释你的那样,我不会详细介绍它。