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
或用户界面的任何内容。
所以我有一个未修饰的 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
或用户界面的任何内容。