拖动操作的副作用之一是mouseClicked
不会被调用。为什么这很重要?基本上,您可以使用这个事实来决定是否应该在mouseClicked
事件中取消选择对象,而不是像mousePressed
or之类的东西mouseReleased
。
它确实需要您维护有关当前和先前状态的一些信息,以便您知道对象是刚刚被选中还是先前被选中,但基本思想很有效。
![拉我一把](https://i.stack.imgur.com/kGoPM.gif)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class WhatADrag {
public static void main(String[] args) {
new WhatADrag();
}
public WhatADrag() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<Rectangle> boxes;
private Rectangle selected;
public TestPane() {
boxes = new ArrayList<>(25);
int x = 0;
int y = 0;
for (int index = 0; index < 10; index++) {
boxes.add(new Rectangle(x, y, 100, 100));
x += 25;
y += 25;
}
MouseAdapter ma = new MouseAdapter() {
private Rectangle previous;
private Point delta;
@Override
public void mousePressed(MouseEvent e) {
List<Rectangle> reversed = new ArrayList<>(boxes);
Collections.reverse(reversed);
previous = selected;
if (selected == null || !selected.contains(e.getPoint())) {
for (Rectangle box : reversed) {
if (box.contains(e.getPoint())) {
selected = box;
delta = new Point(e.getX() - selected.x, e.getY() - selected.y);
repaint();
break;
}
}
if (selected != null) {
boxes.remove(selected);
boxes.add(boxes.size() - 1, selected);
}
} else if (selected != null) {
delta = new Point(e.getX() - selected.x, e.getY() - selected.y);
}
}
@Override
public void mouseClicked(MouseEvent e) {
if (selected == previous && selected != null && selected.contains(e.getPoint())) {
selected = null;
repaint();
}
}
@Override
public void mouseDragged(MouseEvent e) {
if (selected != null) {
int x = e.getX() - delta.x;
int y = e.getY() - delta.y;
selected.x = x;
selected.y = y;
repaint();
}
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Rectangle box : boxes) {
if (box != selected) {
g2d.setColor(Color.BLUE);
g2d.fill(box);
g2d.setColor(Color.BLACK);
g2d.draw(box);
}
}
if (selected != null) {
g2d.setColor(Color.CYAN);
g2d.fill(selected);
g2d.setColor(Color.BLUE);
g2d.draw(selected);
}
g2d.dispose();
}
}
}
我只是迷路了。我正在查看所有这些代码,甚至不明白它在做什么。
是的,我对我的代码有很多这样的感觉。
基本上...
First: mousePressed
被调用,我反转我的对象列表,因为最上面的组件将是列表中的最后一个(这是我的要求),我将当前选择的对象存储在previous
变量中,我用它来确定是否有选择的变化与否。我检查用户是否点击了该selected
对象,如果他们点击了,我们基本上可以跳过其他所有内容。如果没有,我们确定他们点击了什么,如果有的话。这delta
只是他们点击的位置和对象的位置之间的差异,这是用来使拖动更自然的
如果没有拖动: mouseClicked
被调用。我们测试该selected
对象是否等于该previous
对象,如果在该对象内单击了鼠标selected
,如果是,则应取消选择true
当前对象。selected
否则用户基本上只是改变了选择,所以我们不想立即取消选择它。
否则,如果发生拖动: mouseDragged
被调用。我们只是检查是否有东西selected
,我们计算当前鼠标位置和“点击偏移量”之间的差异并更新selected
对象的位置
清如泥:P
还要记住的一件事是mouseReleased
将始终在之后调用mousePressed
,即使mouseClicked
不是(mouseReleased
在没有发生拖动时调用)。