在绝对位置 Container 中拖动 JComponent
Posted
技术标签:
【中文标题】在绝对位置 Container 中拖动 JComponent【英文标题】:Drag JComponent around in absolute position Container 【发布时间】:2014-04-02 01:56:54 【问题描述】:我已经设置了一个快速演示来拖动 JComponents,但是来自e.getPoint()
的鼠标坐标总是从鼠标拖动开始时的 (0, 0) 开始。
App.java
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class App extends JFrame
private static final long serialVersionUID = 7935470621073141683L;
private static final String TITLE = "Test";
private static AbsolutePanel panel;
private static App frame;
public App()
this(TITLE);
public App(String title)
super(title);
setSize(800, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
public static void main(String[] args)
SwingUtilities.invokeLater(new Runnable()
@Override
public void run()
panel = new AbsolutePanel();
frame = new App("Component Test");
frame.setContentPane(panel);
frame.setVisible(true);
doStuff();
);
public static void doStuff()
JNode[] nodes =
new JNode("A", 50, 50, 20),
new JNode("B", 100, 50, 20),
new JNode("C", 50, 100, 20),
new JNode("D", 100, 100, 20),
new JNode("E", 50, 150, 20),
new JNode("F", 100, 150, 20)
;
for (JNode node : nodes)
panel.addNode(node);
AbsolutePanel.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
public class AbsolutePanel extends JPanel
private static final long serialVersionUID = -2783388377109130628L;
private List<JNode> nodes;
public AbsolutePanel()
super(null);
nodes = new ArrayList<JNode>();
public List<JNode> getNodes()
return nodes;
public void addNode(JNode node)
nodes.add(node);
add(node);
Insets insets = this.getInsets();
Dimension size = node.getPreferredSize();
node.setBounds(node.getX() + insets.left, node.getY() + insets.top,
size.width, size.height);
@Override
protected void paintComponent(Graphics g)
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
for (JNode node : getNodes())
node.paint(g);
JNode.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
public class JNode extends Draggable
private static final long serialVersionUID = 4342026645661510597L;
private String label;
public JNode(String label, int x, int y, int size)
super(x, y, size);
this.label = label;
@Override
protected void paintComponent(Graphics g)
super.paintComponent(g);
Dimension size = this.getPreferredSize();
g.setColor(Color.YELLOW);
g.fillOval(getX(), getY(), size.width, size.height);
g.setColor(Color.BLUE);
g.drawOval(getX(), getY(), size.width, size.height);
g.drawString(label, getX() + size.width / 2 - 2, getY() + size.height / 2 + 4);
Draggable.java
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JComponent;
public class Draggable extends JComponent implements MouseListener, MouseMotionListener
private static final long serialVersionUID = 8036176852541863898L;
private boolean dragging = false;
public Draggable(int x, int y, int size)
super();
setPreferredSize(new Dimension(size, size));
setBounds(x, y, size, size);
addMouseListener(this);
addMouseMotionListener(this);
@Override
public void mouseDragged(MouseEvent e)
if (dragging)
int oldX = this.getX();
int oldY = this.getY();
int newX = e.getPoint().y;
int newY = e.getPoint().x;
System.out.printf("(%03d, %03d) -> (%03d, %03d)\n", oldX, oldY, newX, newY);
setLocation(e.getPoint());
repaint();
@Override
public void mouseMoved(MouseEvent e)
@Override
public void mouseClicked(MouseEvent e)
@Override
public void mousePressed(MouseEvent e)
dragging = true;
@Override
public void mouseReleased(MouseEvent e)
dragging = false;
@Override
public void mouseEntered(MouseEvent e)
setCursor(new Cursor(Cursor.HAND_CURSOR));
@Override
public void mouseExited(MouseEvent e)
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
【问题讨论】:
【参考方案1】:我使用Component Mover 来拖动组件。
编辑:
我遇到了重绘问题。
这是因为 fillOval/drawOval 方法实际上应该使用比组件大小小 1 的宽度/高度。如果你仔细看你的画,你会注意到右边/底部节点的边缘不是完全圆的。少用 1 会导致绘制发生在组件的范围内。
g.setColor(Color.YELLOW);
g.fillOval(getX(), getY(), size.width-1, size.height-1);
g.setColor(Color.BLUE);
g.drawOval(getX(), getY(), size.width-1, size.height-1);
话虽如此,您的代码实际上比它需要的更复杂。当我测试您的代码时,我摆脱了 Draggable 类,因为您在使用 ComponentMover 时不再需要它。所以现在你的 JNode 可以直接扩展 JComponent 了。由于它是一个组件,您可以让 Swing 自己进行绘制,这样您的 AbsolutePanel 就不需要任何自定义绘制。它只是变成了一个包含 Swing 组件的面板。由于您使用的是空布局,因此您需要设置每个 JNode 的边界。此外,JNode 中的绘画代码也需要更改,因为现在所有绘画都相对于 (0, 0),而不是 getX() 和 getY()。
【讨论】:
谢谢,效果很好,但我遇到了重绘问题。见image。有没有办法解决这个问题? 感谢您解决绘画问题。我从面板中删除了组件绘画并将节点相对于 (0, 0) 和 everything works great.以上是关于在绝对位置 Container 中拖动 JComponent的主要内容,如果未能解决你的问题,请参考以下文章
Photoshop 之类的画布图像可拖放、可缩放的图像在拖动时出现绝对位置问题
jQuery UI (Droppable):如果 droppable 具有相对/绝对的 css 位置,则可拖动元素不会放置在鼠标指针处