سؤال

I have set up a quick demo for dragging JComponents around, but the mouse coordinates from e.getPoint() always start at (0, 0) at the beginning of the mouse drag.

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));
    }
}
هل كانت مفيدة؟

المحلول

I use the Component Mover to drag components around.

Edit:

I am getting repainting issues.

That is because the fillOval/drawOval methods should actually use a width/height that is 1 less than the size of the component. If you look closely at your painting you will notice the the edge of the node on the right/bottom is not completely round. Using 1 less will cause the painting to occur within the bounds of your component.

    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);

Having said that your code is actually more complicated than it needs to be. When I tested your code I got rid of the Draggable class since you no longer need that when you use the ComponentMover. So now your JNode can extend JComponent directly. Since it is a component, you can just let Swing do the painting itself so your AbsolutePanel does not need any custom painting. It just becomes a panel that holds Swing components. Since you are using a null layout you need to set the bounds of each JNode. Also the painting code in JNode will need to change since all the painting is now relative to (0, 0), not getX() and getY().

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top