JFrame添加两个鼠标监听器会导致拖动效果不流畅。

huangapple go评论82阅读模式
英文:

JFrame adding two mouselisteners causing glitchy drag effect

问题

以下是翻译好的部分:

所以我有一个未装饰的JFrame,我尝试将这个FrameDragListener添加到JFrame上,以某种方式成功了。
但是,如果我的鼠标位于Frame内的文本窗格内,我无法拖动该窗格。

所以我尝试将其添加到文本窗格上,这在某种程度上起作用,但会引起一些闪烁效果,因为我添加了两个不同的鼠标监听器。

在这里,您可以看到鼠标监听器引起的闪烁效果。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);
}

}

英文:

So I have an undecorated JFrame I tried to add this framedraglistener to the JFrame and that worked in a way.
But I can't drag the frame if my mouse is inside the text pane inside the Frame.

So I tried to also add it to text pane and that kinda worked but is causing a glitchy effect because I am adding two different mouse listeners.

Here you can see the glitchy effect the mouse listeners are causing. https://streamable.com/3yijqq

So how can I either cancel one of the mouse listeners when clicking inside the text pane or turn the two mouse listeners into one that works both on the JFrame and inside the text pane so it won't be causing that glitchy effect

Here is the 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);
    }
}

答案1

得分: 1

Here is the translated code you requested:

你尝试过了吗

```java
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 类,以始终获取用户鼠标指针的位置,即使超出框架的边界。我将很快测试 MouseInfo 的想法并告诉你。

请发布一个 MRE 以便获得更好的答案。

编辑 1:

以下是使用 MouseInfo 类的代码:

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 的文本选择/取消选择引起的问题。因为当我将 JTextPane 替换为 JLabel 时,它正常工作。所以现在的问题是:当用户在 JTextPane 内拖动时,你希望发生什么?你希望选择文本,还是拖动框架?这两种选项之间存在冲突。

我建议你在顶部添加一个空白区域(例如一个空的 JPanel),用户可以在那里抓住(没有装饰的)框架,并将 FrameDragListener 实例添加到该区域,而不是添加到 JTextPane 或用户界面的任何内容中。

英文:

Have you tried:

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

It worked for me:

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

The only problem with this code, is if you grab the JTextPane really close to some edge (eg the left edge) and drag outside the frame bounds (eg at the left side). But if you grab the JTextPane a couple of pixels away from all edges, then you should see a normal drag as I saw. To solve this at-the-edge problem you may want to use the java.awt.MouseInfo class to always get the location of the user's mouse pointer even when outside the frame's bounds. I will test the idea of the MouseInfo shortly and let you know.

Please post an MRE so you can get better answers.

Edit 1:

Here follows the code which utilizes the 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);
});
}
}

It works, but the problem persists. It may be due to the text of the JTextPane being selected and unselected. I will try to fix it and then let you know again.

Edit 2:

Seems like indeed the selection/unselection of text of the JTextPane is causing the problem. Because when I substituted the JTextPane with a JLabel it worked fine. So the question now is: What do you want to happen when the user drags inside the JTextPane? Do you want the text to be selected, or the frame being dragged? There is a conflict between those options.

I would suggest you to just add an empty space (eg an empty JPanel) at the top, where the user is supposed to grab the (undecorated) frame and add the FrameDragListener instance to that, instead of the JTextPane or any contents of the user's interface.

huangapple
  • 本文由 发表于 2020年7月31日 20:34:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/63191935.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定