JFrame 添加两个 mouselisteners 导致出现故障拖动效果

JFrame adding two mouselisteners causing glitchy drag effect

所以我有一个未修饰的 JFrame 我尝试将此 framedraglistener 添加到 JFrame 并且以某种方式工作。 但是如果我的鼠标在框架内的文本窗格内,我无法拖动框架。

所以我也尝试将它添加到文本窗格中,这有点奏效,但由于我添加了两个不同的鼠标侦听器而导致了故障效果。

在这里您可以看到鼠标侦听器造成的故障效果。 https://streamable.com/3yijqq

那么,如何在文本窗格内单击时取消其中一个鼠标侦听器,或者将两个鼠标侦听器变成一个既适用于 JFrame 又适用于文本窗格的鼠标侦听器,这样它就不会导致故障效果

这是 FrameDragListener

FrameDragListener frameDragListener = new FrameDragListener(this);
jTextPane1.addMouseListener(frameDragListener);
jTextPane1.addMouseMotionListener(frameDragListener);

public static class FrameDragListener extends MouseAdapter {

    private final JFrame frame;
    private Point mouseDownCompCoords = null;

    public FrameDragListener(JFrame frame) {
        this.frame = frame;
    }

    public void mouseReleased(MouseEvent e) {
        mouseDownCompCoords = null;
    }

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

    public void mouseDragged(MouseEvent e) {
        Point currCoords = e.getLocationOnScreen();
        frame.setLocation(currCoords.x - mouseDownCompCoords.x, currCoords.y - mouseDownCompCoords.y);
    }
}

你试过了吗:

public void mouseDragged(MouseEvent e) {
    Point currCoords = frame.getLocation();
    Point newMouseDownCompCoords = e.getPoint();
    frame.setLocation(currCoords.x + newMouseDownCompCoords.x - mouseDownCompCoords.x, currCoords.y + newMouseDownCompCoords.y - mouseDownCompCoords.y);
}

它对我有用:

import java.awt.Color;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;

public class Main {

    public static class FrameDragListener extends MouseAdapter {
        
        private final JFrame frame;
        private Point mouseDownCompCoords = null;

        public FrameDragListener(final JFrame frame) {
            this.frame = frame;
        }

        @Override
        public void mouseReleased(final MouseEvent e) {
            mouseDownCompCoords = null;
        }

        @Override
        public void mousePressed(final MouseEvent e) {
            mouseDownCompCoords = e.getPoint();
        }

        @Override
        public void mouseDragged(final MouseEvent e) {
            Point currCoords = frame.getLocation();
            Point newMouseDownCompCoords = e.getPoint();
            frame.setLocation(currCoords.x + newMouseDownCompCoords.x - mouseDownCompCoords.x, currCoords.y + newMouseDownCompCoords.y - mouseDownCompCoords.y);
        }
    }
    
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(() -> {
            final JTextPane jTextPane1 = new JTextPane();
            jTextPane1.setBorder(BorderFactory.createLineBorder(Color.CYAN.darker(), 5));
            jTextPane1.setText("Some text...");
            
            final JFrame frame = new JFrame("Drag the text pane");
            
            final FrameDragListener frameDragListener = new FrameDragListener(frame);
            jTextPane1.addMouseListener(frameDragListener);
            jTextPane1.addMouseMotionListener(frameDragListener);
            
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(jTextPane1);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

此代码的唯一问题是,如果您 抓住 JTextPane 真的很接近某个边缘(例如左边缘)并拖到框架边界外(例如在左侧)。但是如果你从所有边缘抓取 JTextPane 几个像素,那么你应该看到一个正常的拖动,就像我看到的那样。要解决这个边缘问题,您可能需要使用 java.awt.MouseInfo class 来始终获取用户鼠标指针的位置,即使在框架边界之外也是如此。我会尽快测试 MouseInfo 的想法,然后告诉你。

请 post 一个 MRE 以便您能得到更好的答案。

编辑 1:

下面是利用 MouseInfo class...

的代码
import java.awt.Color;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;

public class Main {

    public static class FrameDragListener extends MouseAdapter {
        
        private final JFrame frame;
        private Point mouseDownCoords = null;

        public FrameDragListener(final JFrame frame) {
            this.frame = frame;
        }

        @Override
        public void mouseReleased(final MouseEvent e) {
            mouseDownCoords = null;
        }

        @Override
        public void mousePressed(final MouseEvent e) {
            mouseDownCoords = MouseInfo.getPointerInfo().getLocation();
        }

        @Override
        public void mouseDragged(final MouseEvent e) {
            Point currCoords = frame.getLocation();
            Point newMouseDownCoords = MouseInfo.getPointerInfo().getLocation();
            frame.setLocation(currCoords.x + newMouseDownCoords.x - mouseDownCoords.x, currCoords.y + newMouseDownCoords.y - mouseDownCoords.y);
            mouseDownCoords = newMouseDownCoords;
        }
    }
    
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(() -> {
            final JFrame frame = new JFrame("Drag the text pane");

            final FrameDragListener frameDragListener = new FrameDragListener(frame);

            final JTextPane jTextPane1 = new JTextPane();
            jTextPane1.setBorder(BorderFactory.createLineBorder(Color.CYAN.darker(), 5));
            jTextPane1.setText("Some text...");

            jTextPane1.addMouseListener(frameDragListener);
            jTextPane1.addMouseMotionListener(frameDragListener);

            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(jTextPane1);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

有效,但问题依旧。这可能是由于 JTextPane 的文本被选中和取消选中。我会尝试修复它,然后再次通知您。

编辑 2:

似乎 JTextPane 的文本 selection/unselection 确实导致了问题。因为当我用 JLabel 替换 JTextPane 时它工作正常。所以现在的问题是:当用户在 JTextPane 中拖动时,你希望发生什么?您是要选择文本,还是要拖动框架?这些选项之间存在冲突。

我建议你只在顶部添加一个空的 space(例如一个空的 JPanel),用户应该抓住(未修饰的)框架并添加 FrameDragListener 实例,而不是 JTextPane 或用户界面的任何内容。