1

我已经设置了一个快速演示来拖动 JComponents,但是鼠标坐标e.getPoint()总是从鼠标拖动开始时的(0, 0)开始。

应用程序.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);
        }
    }
}

绝对面板.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));
    }
}
4

1 回答 1

3

我使用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()。

于 2014-02-28T21:15:39.817 回答