JPanel subclass "jumps around" when dragged

时间:2016-04-04 18:50:48

标签: java swing jpanel drag mousemotionlistener

I'm currently coding on a small "Paint"-program of mine; so far, you can draw on it with a pen, zoom in up to 100x, and choose a color. Next thing I wanted to add was (or is) the possibility to drag the JPanel subclass, on which the image chosen to edit is drawn, around. Basically, by holding down the right mouse button, you change the location of the JPanel subclass, which is located on a JInternalFrame. I've got a code sample that should be working fine on its own; at least it does for me. To replicate the issue, just launch the DragPanelTest class and drag your mouse while over the component with the red border - the panel isn't dragged smoothly, but instead jumps back and forth all the time.

code:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.BorderFactory;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class DragPanelTest extends JPanel implements MouseMotionListener, MouseListener {
    Point oldDragPt;
    boolean dragEnabled;
    int newX;
    int newY;

    public static void main(String[] args) {
        System.out.println("Launching Test.java ...");

        JFrame frame = new JFrame("Title");
        JInternalFrame intFrame = new JInternalFrame("title", true, true, true, true);
        JDesktopPane deskPane = new JDesktopPane();
        DragPanelTest dragPanel = new DragPanelTest();

        frame.setSize(300, 300);;
        frame.setLayout(null);
        frame.setVisible(true);
        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        int x = (d.width - frame.getWidth()) / 2;
        int y = (d.height - frame.getHeight()) / 2;
        frame.setLocation(x, y);

        deskPane.setBounds(50, 50, 200, 200);
        deskPane.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        frame.add(deskPane);


        deskPane.add(intFrame);
        intFrame.setSize(150, 150);
        intFrame.add(dragPanel);
        intFrame.setVisible(true);
    }

    public DragPanelTest() {
        this.setSize(100,100);
        this.setBorder(BorderFactory.createLineBorder(Color.RED));
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
    }

    public void mousePressed(MouseEvent e) {
        if (e.isMetaDown()) {
            dragEnabled = true;
            oldDragPt = new Point((int) this.getMousePosition().getX(), (int) this.getMousePosition().getY());
        }
        repaint();
    }

    public void mouseReleased(MouseEvent e) {
        dragEnabled = false;
        oldDragPt = null;
    }

    public void mouseDragged(MouseEvent e) {
        if (e.isMetaDown() && this.getMousePosition() != null) {
            if (oldDragPt != null) {
                if (dragEnabled) {
                    int mouseX = (int) this.getMousePosition().getX();
                    int mouseY = (int) this.getMousePosition().getY();
                    int x = this.getX();
                    int y = this.getY();
                    int diffX = (mouseX - (int) oldDragPt.getX());
                    int diffY = (mouseY - (int) oldDragPt.getY());
                    newX = getX() + diffX;
                    newY = getY() + diffY;
                    this.setLocation(newX, newY);
                    this.repaint();
                    oldDragPt = new Point(mouseX, mouseY);
                }
            } else {
                oldDragPt = new Point((int) this.getMousePosition().getX(), (int) this.getMousePosition().getY());
            }
        }
    }

    public void mouseClicked(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseMoved(MouseEvent e) {} 
}

Note that I left out some System.out.println() or @Override commands to shorten the code a bit.

Anyhow, if anyone knows what I'm doing wrong / what to improve, I'd be very thankful!

2 个答案:

答案 0 :(得分:5)

the panel isn't dragged smoothly, but instead jumps back and forth all the time.

When you have jumping its because the relative movements between the mouse and the component and the parent panel is off. Your code is too complicated to point out the exact line causing the problem.

The basic code for dragging a component around a panel is:

public class DragListener extends MouseInputAdapter
{
    Point location;
    MouseEvent pressed;

    public void mousePressed(MouseEvent me)
    {
        pressed = me;
    }

    public void mouseDragged(MouseEvent me)
    {
        Component component = me.getComponent();
        location = component.getLocation(location);
        int x = location.x - pressed.getX() + me.getX();
        int y = location.y - pressed.getY() + me.getY();
        component.setLocation(x, y);
     }
}

For more advanced code with more feature you can also check out the Component Mover class found in Moving Windows.

答案 1 :(得分:0)

我在移动滚动窗格的视口时遇到了类似的问题。我认为,当重新定位组件时,保存点的值相对于原始位置,并且相对于新位置是不正确的。我的解决方案对我来说似乎不合逻辑,使得拖动操作流畅。我所做的是将点增量添加回保存的位置。

这是拖动视口的基本代码:

Point priorPanPoint;

public void mouseDragged(MouseEvent e) {
    Point newPt = subtractPoints(priorPanPoint, e.getPoint());
    priorPanPoint = addPoints(e.getPoint(), newPt);
    newPt = addPoints(getVisibleRect().getLocation(), newPt);
    viewport.setViewPosition(newPt);
}

public void mousePressed(MouseEvent e) {
    priorPanPoint = e.getPoint();
}

private Point addPoints(Point p1, Point p2) {
    return  new Point(p1.x + p2.x, p1.y + p2.y); }

private Point subtractPoints(Point p1, Point p2) {
    return new Point(p1.x - p2.x, p1.y - p2.y);
}