【Swing 7】坐标陷阱与单个组件拖放

  之前模仿QQ界面的时候,一直很苦恼布局的问题。虽说绝对定位相对于JFrame默

认的BorderLayout(布局管理器),JPanel的FlowLayout(流式管理器)方便了不少。可

以通过setBounds()直接设置坐标,可要是组件一多起来。非把你累死不可。

  好了,不多说,为什么说会有陷阱呢。大家看看下面这两个有界面。源代码贴在这。

两个界面就差了句setUndecorated(true); 可以看出,无论有无边框,它们的大小都是

一样的。到这里倒是还没出现问题!接着往下看。

 1 package demo;
 2
 3 import javax.swing.*;
 4 import java.awt.*;
 5
 6 public class DrawPanel {
 7     public static void main(String[] args) {
 8         new DrawPanel();
 9     }
10     public DrawPanel() {
11         JFrame f = new JFrame();
12
13         f.setUndecorated(true);         // 去掉界面的边框
14         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关掉界面时结束javaw.exe进程
15         f.setBounds(200, 200, 400, 300); // 参数分别是界面左上角的横, 纵坐标, 长和宽
16         f.setVisible(true);
17     }
18 }

去掉边框的界面

上面是什么都没加,空空如也的情况。接下来我们给它们加一个按钮,看看会有什么变化。

 1 package demo;
 2
 3 import javax.swing.*;
 4 import java.awt.*;
 5
 6 public class DrawPanel {
 7     public static void main(String[] args) {
 8         new DrawPanel();
 9     }
10     public DrawPanel() {
11         JFrame f = new JFrame();
12         f.setUndecorated(true);         // 去掉界面的边框
13         f.setLayout(null);              // null即不使用JFrame默认的边界布局, 而是设置布局为绝对定位
14
15         JButton b = new JButton("点击");
16         b.setBounds(50, 50, 60, 20);    // 参数分别是界面左上角的横, 纵坐标, 长和宽
17         f.add(b);
18         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关掉界面时结束javaw.exe进程
19         f.setBounds(200, 200, 400, 300);
20         f.setVisible(true);
21     }
22 }

添加按钮的对比

问题来了,来两张对比的图片。一目了然。

水平坐标(x值)的对比。

纵坐标(y值)的对比 

从上面两幅图很容易看出,有边框的按钮无论是左上角的x值或是y值都比没边框的

大了点。当然,这是相对于窗口来说的。现在,让我们来寻找真相。

System.out.println("按钮在界面上的坐标: " + b.getX() + ", " + b.getY()); 

很不幸,输出都是50, 50

这和前面我们设置按钮的位置时用的代码相符的。横纵坐标均是50。

b.setBounds(50, 50, 60, 20);    // 参数分别是界面左上角的横, 纵坐标, 长和宽

咦,那就奇怪了。明明有边框的按钮横纵坐标明显都偏大。(事实上,那个多出来的坐

标就是左边框和上边框啦!),我们再来证明一下。先要解决怎么获得坐标的问题,也就

是怎么得到界面上任一点的坐标呢?

有没有想到监听窗口呢?其实就是使用鼠标事件!

1 import java.awe.event.*; // 别忘了导入
2
3 b.addMouseListener(new MouseAdapter() {
4     public void mousePressed(MouseEvent e);
5         System.out.println("按钮在界面上的实际坐标: " + e.getX() + ", " + e.getY());
6 });

大家在按钮周围随便点点,便会发现,实际上按钮的x值是接近9,y值是接近36的。事

实上,这也是左边框和上边框的宽度。别问我为什么,这是我昨晚点了好久才得出来的数据。

好了,说了这么多,结论:

1. e.getX()和e.getY()得到的坐标才是真正的坐标。监听界面时,得到的是界面的点坐标。

而监听按钮时,得到的是在按钮上的点坐标。(而不是在界面上的坐标)。

2. b.getX()和b.getY()得到的不过是去除边框后的坐标,也就是setBounds()或setLocation

()里面设置的坐标。

3. 当没有边框时,上面两者是相等的。当有边框时,要分别加上左边框和上边框的宽度。

即b.getX() + 9和b.getY() + 36。

---------------------------------------------------------------------------------------------

解决了上面两个易错的问题,接下来就是讲讲拖动的原理了。和移动界面的原理差不多。好比

我们知道鼠标按住按钮上的那一点在按钮上的坐标 (下图中蓝色粗线),然后用该点在屏幕上的坐

标,(红色线到蓝色粗线的长度)减去该点在按钮上(蓝色粗线)的坐标。再减去界面的左上角坐标

(红色粗线),万事大吉,搞定!

1. 先来个没有边框的版本

 1 package demo;
 2
 3 import javax.swing.*;
 4 import java.awt.event.*;
 5 import java.awt.*;
 6
 7 public class DrawPanel {
 8     int pointXOnButton, pointYOnButton;
 9     JFrame f;
10     public static void main(String[] args) {
11         new DrawPanel();
12     }
13     public DrawPanel() {
14         f = new JFrame("移动按钮");
15         f.setLayout(null);     // 不使用JFrame默认的边界布局而是使用直接设置坐标的绝对定位
16         f.setUndecorated(true);                                   // 去掉窗口自带的边框
17
18         // 获取电脑屏幕的尺寸(如15.6寸的屏幕一般是1920 * 1080像素), 使窗口在屏幕上居中显示
19         Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
20         int xOnScreen = screenSize.width / 2 - 400;       // 窗口左上角的x坐标
21         int yOnScreen = screenSize.height / 2 - 300;      // 窗口左上角的y坐标
22         init();
23         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗口后退出javaw.exe进程
24         f.setBounds(xOnScreen, yOnScreen, 800, 600);
25         f.setVisible(true);
26     }
27     public void init() {
28         JButton b = new JButton("点我");
29         b.setBounds(200, 100, 60, 20);
30         b.addMouseListener(new MouseAdapter() {
31             public void mousePressed(MouseEvent e) {
32                 pointXOnButton = e.getX();                   // 点在按钮上的x坐标
33                 pointYOnButton = e.getY();
34             }
35         });
36         b.addMouseMotionListener(new MouseMotionAdapter() {
37             public void mouseDragged(MouseEvent e) {
38                 int pointXOnScreen = e.getXOnScreen();        // 点在屏幕上的x坐标
39                 int pointYOnScreen = e.getYOnScreen();
40                 int frameXOnScreen = f.getX();                // 窗口左上角的x坐标
41                 int frameYOnScreen = f.getY();
42                 int buttonXOnFrame = pointXOnScreen - pointXOnButton - frameXOnScreen;
43                 int buttonYOnFrame = pointYOnScreen - pointYOnButton - frameYOnScreen;
44                 b.setLocation(buttonXOnFrame, buttonYOnFrame);
45             }
46         });
47         f.add(b);
48     }
49 }

无边框

2. 再来个有边框的版本(要考虑边框宽度了)

 1 package demo;
 2
 3 import javax.swing.*;
 4 import java.awt.event.*;
 5 import java.awt.*;
 6
 7 public class DrawPanel {
 8     int pointXOnButton, pointYOnButton;
 9     JFrame f;
10     public static void main(String[] args) {
11         new DrawPanel();
12     }
13     public DrawPanel() {
14         f = new JFrame("移动按钮");
15         f.setLayout(null);     // 不使用JFrame默认的边界布局而是使用直接设置坐标的绝对定位
16
17         // 获取电脑屏幕的尺寸(如15.6寸的屏幕一般是1920 * 1080像素), 使窗口在屏幕上居中显示
18         Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
19         int xOnScreen = screenSize.width / 2 - 400;       // 窗口左上角的x坐标
20         int yOnScreen = screenSize.height / 2 - 300;      // 窗口左上角的y坐标
21         init();
22         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗口后退出javaw.exe进程
23         f.setBounds(xOnScreen, yOnScreen, 800, 600);
24         f.setVisible(true);
25     }
26     public void init() {
27         JButton b = new JButton("点我");
28         b.setBounds(200, 100, 60, 20);
29         b.addMouseListener(new MouseAdapter() {
30             public void mousePressed(MouseEvent e) {
31                 pointXOnButton = e.getX();                   // 点在按钮上的x坐标
32                 pointYOnButton = e.getY();
33             }
34         });
35         b.addMouseMotionListener(new MouseMotionAdapter() {
36             public void mouseDragged(MouseEvent e) {
37                 int pointXOnScreen = e.getXOnScreen();        // 点在屏幕上的x坐标
38                 int pointYOnScreen = e.getYOnScreen();
39                 int frameXOnScreen = f.getX();                // 窗口左上角的x坐标
40                 int frameYOnScreen = f.getY();
41                 int buttonXOnFrame = pointXOnScreen - pointXOnButton - frameXOnScreen - 9; // 9是左边边框的宽度
42                 int buttonYOnFrame = pointYOnScreen - pointYOnButton - frameYOnScreen - 36; // 36是上边边框的厚度
43                 b.setLocation(buttonXOnFrame, buttonYOnFrame);
44             }
45         });
46         f.add(b);
47     }
48 }

考虑边框宽度

时间: 2024-11-12 09:40:54

【Swing 7】坐标陷阱与单个组件拖放的相关文章

Java Swing界面编程(19)---密码输入组件:JPasswordField

JTextField是使用明文方式进行数据显示的,如果现在需要将回显的内容设置成其他字符,则可以使用JPasswordField类. package com.beyole.util; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPasswordField; public class test18 { public static void main(String[] args) { JFrame

Java Swing界面编程(6)---JButton按钮组件

package com.beyole.util; import java.awt.Font; import javax.swing.JButton; import javax.swing.JFrame; public class test5 { public static void main(String[] args) { JFrame frame=new JFrame(); JButton button=new JButton("Click Me!");//new出一个按钮的对象

Java Swing实战(五)表格组件JTable(1)

dbPanel面板的配置告一段落. 接下来配置taskPanel 面板. /** * @author: lishuai * @date: 2018/11/26 13:51 */ public class WeimingSyncApplets { public static void main(String[] args) { // 面板组件 JPanel taskPanel = new JPanel(); JPanel dbPanel = new JPanel(); JTabbedPane ta

Vue生命周期详解(1)- 单个组件

刚接触vue,使用vue并没意识到生命周期的重要性.直到项目深入,在解决父组件异步加载数据传给子组件并渲染时首次渲染异常的问题时,浪费了很多时间,才发现自己对vue生命周期理解的欠缺.因此,这次专门重新学习一下vue的生命周期并总结在这里分享,希望对大家有所帮助. 首先上官方大图(是不是很高大上?然而,有点晦涩,对初学者不是很友好!) 不过不用担心,咱们程序员不就是实践出真知嘛!上代码: 1 <!DOCTYPE html> 2 <html lang="en">

【Swing 8】多个组件移动

上次介绍了单个按钮的拖动原理,今天来个联合作战,实现之前一直以为要制造监听器 的误区,加到各个组件上,结果昨天深夜偶然想出了解决方法.而且是超级简单的那种,唉 ! 有时候,想多了真不见得是好事. 单个组件地拖动: http://www.cnblogs.com/Ruby517/p/6507001.html 其实要让多个组件都能响应拖动事件.那么给它们写一个带有拖动方法的父类即可. 这次,我们把源代码分成几个类文件, 以后其它要用到图形界面的就可以直接调用了,不 过,在此之前,先解决一个问题.由于J

Delphi 动态创建组件,单个创建、单个销毁

效果图如下: 实现部分代码如下: var rec: Integer = 0; //记录增行按钮点击次数 implementation {$R *.dfm} //动态释放单个组件内存,即销毁组件 procedure TForm1.DeleteRow(Sender: TObject); begin if rec < 1 then Exit else begin TPanel(Panel1.Controls[rec]).Free; //释放单个控件内存 TComboBox(Panel2.Control

JAVA学习Swing章节按钮组件JButton的简单学习

package com.swing; import java.awt.Container; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.URL; import javax.swing.Icon; import javax.swing.ImageIcon;

JAVA学习笔记(四十九)- Swing相关组件

JFrame组件 import java.awt.Color; import javax.swing.JFrame; import javax.swing.JPanel; /* * Swing是在AWT基础上的扩展 * javax.swing包及其扩展包,组件的命名多以J开关 * * JFrame组件 */ public class Test08 { public static void main(String[] args) { JFrame frame=new JFrame("我的窗体&qu

14.4-全栈Java笔记: javax.swing常用控件有哪些?怎么用?

常用基本控件 javax.swing.JButton 在图形界面程序中,按钮可能是使用量最大的控件之一,javax.swing包中JButton类就是用来创建按钮的.如表1所示,为JButton常用的构造方法.  javax.swing.JLabel JLabel控件是最简单的Swing组件之一,用于在窗体上显示标签, JLabel既可以显示文本,也可以显示图像.如表3所示,为JLabel常用的构造方法. 注意: JLabel只能用于显示文本和图标信息,用户不能对其进行修改. javax.swi