从自定义按钮拖动 JFrame 不流畅
JFrame dragging from custom button not smooth
我使用与 Java - Custom shaped draggable JFrame
几乎相同的方法移动 JFrame
我有一个扩展 JPanel 的 class。在上述 class 中,我将之前的 x 和 y 设置为如下变量:
private int pressX, pressY
然后,在 mousePressed 方法中,我有:
pressX = e.getX();
pressY = e.getY();
最后,在 mouseDragged 中,我有:
mainFrame.setLocation((int) Math.round(mainFrame.getLocation().getX() + e.getX() - pressX), (int) Math.round(mainFrame.getLocation().getY() + e.getY() - pressY));
但是,拖动 window 时,会出现相当大的延迟或某种问题。这是一个视频,展示了视觉上发生的事情。
https://i.imgur.com/KWtbE1s.gifv
我正在使用 swing 库并使用大约每两毫秒滴答一次的计时器重新绘制。
编辑:
我修改了代码,使点相对于JPanel,但问题仍然存在。
dragMe = new Draggable() {
private static final long serialVersionUID = 1L;
private Point press;
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {
press = SwingUtilities.convertPoint(this, e.getPoint(), mainFrame);
}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
@Override
public void mouseDragged(MouseEvent e) {
Point drag = SwingUtilities.convertPoint(this, e.getPoint(), mainFrame);
mainFrame.setLocation((int) Math.round(mainFrame.getLocation().getX() + drag.getX() - press.getX()), (int) Math.round(mainFrame.getLocation().getY() + drag.getY() - press.getY()));
}
@Override
public void mouseMoved(MouseEvent e) {}
};
编辑 2:
不幸的是,我在这里创建的示例运行良好,但我不知道为什么它在真实代码中不起作用。我什至尝试将我在这个示例中所做的确切 class 复制到实际应用程序中,但问题仍然出现在真实代码中。
看来我将不得不对此进行更多研究。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public class Test extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
private static JFrame frame;
public static void main(String[] args) {
class Draggable extends JPanel implements MouseListener, MouseMotionListener {
private static final long serialVersionUID = 1L;
private Point press;
public Draggable() {
addMouseListener(this);
addMouseMotionListener(this);
}
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {
press = SwingUtilities.convertPoint(this, e.getPoint(), frame);
}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
@Override
public void mouseDragged(MouseEvent e) {
Point drag = SwingUtilities.convertPoint(this, e.getPoint(), frame);
frame.setLocation((int) Math.round(frame.getLocation().getX() + drag.getX() - press.getX()), (int) Math.round(frame.getLocation().getY() + drag.getY() - press.getY()));
}
@Override
public void mouseMoved(MouseEvent e) {}
}
Test t = new Test();
t.setBounds(0, 0, 1200, 600);
t.setVisible(true);
Draggable drag = new Draggable();
drag.setBounds(24, 24, 24, 24);
drag.setVisible(true);
Timer repaintTimer = new Timer(2, t);
frame = new JFrame();
frame.setSize(1200, 600);
frame.add(t);
frame.add(drag);
Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocation((dim.width - frame.getWidth()) / 2, (dim.height - frame.getHeight()) / 2);
frame.getContentPane().setLayout(null);
frame.setAlwaysOnTop(true);
frame.setResizable(false);
repaintTimer.start();
frame.setVisible(true);
frame.requestFocus();
}
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(24, 24, 24, 24);
}
}
查看 Moving Windows 是否有 class 可以为您执行此操作。
它比基本的拖动逻辑更复杂,因为它支持您可能不需要的其他功能。
在将侦听器添加到框架的一个(或多个)组件时拖动框架的基本逻辑(来自上面 class)是:
MouseInputAdapter mia = new MouseInputAdapter()
{
Point location;
Point pressed;
public void mousePressed(MouseEvent me)
{
pressed = me.getLocationOnScreen();
Window window = SwingUtilities.windowForComponent(me.getComponent());
location = window.getLocation();
}
public void mouseDragged(MouseEvent me)
{
Point dragged = me.getLocationOnScreen();
int x = (int)(location.x + dragged.getX() - pressed.getX());
int y = (int)(location.y + dragged.getY() - pressed.getY());
Window window = SwingUtilities.windowForComponent(me.getComponent());
window.setLocation(x, y);
}
};
panel.addMouseListener(mia);
panel.addMouseMotionListener(mia);
编辑:
下面是一些更通用的代码,允许您通过指定父组件接收事件来直接或间接移动组件:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class BasicComponentMover extends MouseInputAdapter
{
/*
** A class that allows you to drag a component around a panel.
** Optionally you can specify a "parent" component, in which case
** the MouseEvents will be converted to be relative to this component
** which will then be dragged. This will allow you to drag a JFrame by
** dragging a component that has been added to the frame.
*/
private Component parent;
private Component destination;
private Point pressed;
BasicComponentMover() {}
{
}
BasicComponentMover(Component parent)
{
this.parent = parent;
}
@Override
public void mousePressed(MouseEvent me)
{
destination = (parent == null) ? me.getComponent() : parent;
pressed = SwingUtilities.convertPoint(me.getComponent(), me.getPoint(), destination);
}
@Override
public void mouseDragged(MouseEvent me)
{
Point location = destination.getLocation();
Point drag = SwingUtilities.convertPoint(me.getComponent(), me.getPoint(), destination);
int x = (int)(location.x - pressed.getX() + drag.getX());
int y = (int)(location.y - pressed.getY() + drag.getY());
destination.setLocation(x, y);
}
private static void createAndShowGUI()
{
JPanel background = new JPanel(null);
background.setPreferredSize(new Dimension(300, 300));
background.setSize(background.getPreferredSize());
background.setBackground(Color.RED);
JPanel foreground = new JPanel(null);
foreground.setPreferredSize(new Dimension(50, 50));
foreground.setSize(foreground.getPreferredSize());
foreground.setBackground(Color.BLUE);
background.add(foreground);
JFrame frame = new JFrame("BasicComponentMover");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.add(background);
frame.setSize(500, 500);
frame.setLocationByPlatform( true );
frame.setVisible( true );
// Drag frame by dragging the red background panel
BasicComponentMover bcm1 = new BasicComponentMover(frame);
background.addMouseListener(bcm1);
background.addMouseMotionListener(bcm1);
// Drag the blue forground component around the red background
BasicComponentMover bcm2 = new BasicComponentMover();
foreground.addMouseListener(bcm2);
foreground.addMouseMotionListener(bcm2);
// Or, drage the background around the frame
BasicComponentMover bcm3 = new BasicComponentMover(background);
// foreground.addMouseListener(bcm3);
// foreground.addMouseMotionListener(bcm3);
}
public static void main(String[] args) throws Exception
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
尝试拖动 blue/red 个组件以查看差异。
我使用与 Java - Custom shaped draggable JFrame
几乎相同的方法移动 JFrame我有一个扩展 JPanel 的 class。在上述 class 中,我将之前的 x 和 y 设置为如下变量:
private int pressX, pressY
然后,在 mousePressed 方法中,我有:
pressX = e.getX();
pressY = e.getY();
最后,在 mouseDragged 中,我有:
mainFrame.setLocation((int) Math.round(mainFrame.getLocation().getX() + e.getX() - pressX), (int) Math.round(mainFrame.getLocation().getY() + e.getY() - pressY));
但是,拖动 window 时,会出现相当大的延迟或某种问题。这是一个视频,展示了视觉上发生的事情。
https://i.imgur.com/KWtbE1s.gifv
我正在使用 swing 库并使用大约每两毫秒滴答一次的计时器重新绘制。
编辑:
我修改了代码,使点相对于JPanel,但问题仍然存在。
dragMe = new Draggable() {
private static final long serialVersionUID = 1L;
private Point press;
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {
press = SwingUtilities.convertPoint(this, e.getPoint(), mainFrame);
}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
@Override
public void mouseDragged(MouseEvent e) {
Point drag = SwingUtilities.convertPoint(this, e.getPoint(), mainFrame);
mainFrame.setLocation((int) Math.round(mainFrame.getLocation().getX() + drag.getX() - press.getX()), (int) Math.round(mainFrame.getLocation().getY() + drag.getY() - press.getY()));
}
@Override
public void mouseMoved(MouseEvent e) {}
};
编辑 2:
不幸的是,我在这里创建的示例运行良好,但我不知道为什么它在真实代码中不起作用。我什至尝试将我在这个示例中所做的确切 class 复制到实际应用程序中,但问题仍然出现在真实代码中。
看来我将不得不对此进行更多研究。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public class Test extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
private static JFrame frame;
public static void main(String[] args) {
class Draggable extends JPanel implements MouseListener, MouseMotionListener {
private static final long serialVersionUID = 1L;
private Point press;
public Draggable() {
addMouseListener(this);
addMouseMotionListener(this);
}
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {
press = SwingUtilities.convertPoint(this, e.getPoint(), frame);
}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
@Override
public void mouseDragged(MouseEvent e) {
Point drag = SwingUtilities.convertPoint(this, e.getPoint(), frame);
frame.setLocation((int) Math.round(frame.getLocation().getX() + drag.getX() - press.getX()), (int) Math.round(frame.getLocation().getY() + drag.getY() - press.getY()));
}
@Override
public void mouseMoved(MouseEvent e) {}
}
Test t = new Test();
t.setBounds(0, 0, 1200, 600);
t.setVisible(true);
Draggable drag = new Draggable();
drag.setBounds(24, 24, 24, 24);
drag.setVisible(true);
Timer repaintTimer = new Timer(2, t);
frame = new JFrame();
frame.setSize(1200, 600);
frame.add(t);
frame.add(drag);
Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocation((dim.width - frame.getWidth()) / 2, (dim.height - frame.getHeight()) / 2);
frame.getContentPane().setLayout(null);
frame.setAlwaysOnTop(true);
frame.setResizable(false);
repaintTimer.start();
frame.setVisible(true);
frame.requestFocus();
}
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(24, 24, 24, 24);
}
}
查看 Moving Windows 是否有 class 可以为您执行此操作。
它比基本的拖动逻辑更复杂,因为它支持您可能不需要的其他功能。
在将侦听器添加到框架的一个(或多个)组件时拖动框架的基本逻辑(来自上面 class)是:
MouseInputAdapter mia = new MouseInputAdapter()
{
Point location;
Point pressed;
public void mousePressed(MouseEvent me)
{
pressed = me.getLocationOnScreen();
Window window = SwingUtilities.windowForComponent(me.getComponent());
location = window.getLocation();
}
public void mouseDragged(MouseEvent me)
{
Point dragged = me.getLocationOnScreen();
int x = (int)(location.x + dragged.getX() - pressed.getX());
int y = (int)(location.y + dragged.getY() - pressed.getY());
Window window = SwingUtilities.windowForComponent(me.getComponent());
window.setLocation(x, y);
}
};
panel.addMouseListener(mia);
panel.addMouseMotionListener(mia);
编辑:
下面是一些更通用的代码,允许您通过指定父组件接收事件来直接或间接移动组件:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class BasicComponentMover extends MouseInputAdapter
{
/*
** A class that allows you to drag a component around a panel.
** Optionally you can specify a "parent" component, in which case
** the MouseEvents will be converted to be relative to this component
** which will then be dragged. This will allow you to drag a JFrame by
** dragging a component that has been added to the frame.
*/
private Component parent;
private Component destination;
private Point pressed;
BasicComponentMover() {}
{
}
BasicComponentMover(Component parent)
{
this.parent = parent;
}
@Override
public void mousePressed(MouseEvent me)
{
destination = (parent == null) ? me.getComponent() : parent;
pressed = SwingUtilities.convertPoint(me.getComponent(), me.getPoint(), destination);
}
@Override
public void mouseDragged(MouseEvent me)
{
Point location = destination.getLocation();
Point drag = SwingUtilities.convertPoint(me.getComponent(), me.getPoint(), destination);
int x = (int)(location.x - pressed.getX() + drag.getX());
int y = (int)(location.y - pressed.getY() + drag.getY());
destination.setLocation(x, y);
}
private static void createAndShowGUI()
{
JPanel background = new JPanel(null);
background.setPreferredSize(new Dimension(300, 300));
background.setSize(background.getPreferredSize());
background.setBackground(Color.RED);
JPanel foreground = new JPanel(null);
foreground.setPreferredSize(new Dimension(50, 50));
foreground.setSize(foreground.getPreferredSize());
foreground.setBackground(Color.BLUE);
background.add(foreground);
JFrame frame = new JFrame("BasicComponentMover");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.add(background);
frame.setSize(500, 500);
frame.setLocationByPlatform( true );
frame.setVisible( true );
// Drag frame by dragging the red background panel
BasicComponentMover bcm1 = new BasicComponentMover(frame);
background.addMouseListener(bcm1);
background.addMouseMotionListener(bcm1);
// Drag the blue forground component around the red background
BasicComponentMover bcm2 = new BasicComponentMover();
foreground.addMouseListener(bcm2);
foreground.addMouseMotionListener(bcm2);
// Or, drage the background around the frame
BasicComponentMover bcm3 = new BasicComponentMover(background);
// foreground.addMouseListener(bcm3);
// foreground.addMouseMotionListener(bcm3);
}
public static void main(String[] args) throws Exception
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
尝试拖动 blue/red 个组件以查看差异。