一、前言
话说都 2022 年了,为啥还有项目在使用 Swing 来开发界面?
我百思不得其解,毕竟从我接触 Java 到现在,就没有看过 Swing 相关的任何东西。Thinking in Java 这本书,每次读都是很自觉的跳过 Swing 那一章。对于 Java 工程师来说,能涉及到 UI 交互的系统,绝大部分都是 web 项目。而 JSP 都已经落伍了,前后端都分离多少年了,这时候让我用 Swing 来写一个页面?
当然,为了生存,我还是不得不对老板说,我之前没接触过 Swing,一点也不会啊,但是没关系,我可以学。
其实存在即合理,在互联网行业待了这么久,自然是不知道有很多传统行业因为各种原因还在使用CS架构,而面对这些维护了十好几年的系统,你就不得不跳入 Swing 的深坑。
那么新问题又来了,都 2022 年了,为啥还会有人在准备写一个 Swing 的系列文章?
因为在我边学边划拉页面的过程,实在是太痛苦了。能搜索到的 Swing 的内容确实不多,能查到的内容,也都是很简单的样式展示。再加上不是什么主流的技术,没有什么很好的教程,所以只能扒源码的注释、尝试 set 各种属性看效果、找规律、翻古老系统里有没有可借鉴的用法。也是煎熬了两三周,算是对 Swing 入门了。
所以我想写这个系列文章,一方面是总结最近学到的“全新的”知识点,另一方面是能填补一些 Swing 相关的教程和文章的缺口,帮助少有的在 Swing 深坑中摸爬滚打的朋友们,一起沉默前行。
文章中涉及到的代码都会上传到 GitHub 上,项目地址:https://github.com/tinybye/someSwingDemos
二、啥是Swing
Swing 是 Java 的 GUI 库,Java 开发人员可以通过 Swing 来绘制客户端的界面。
这解答了我心中的一个疑惑,之前在网上看到 Java 前端工程师的招聘,当时就想,为啥Java会有前端工程师……
具体的概念后面再说,我们先搞一个 demo 出来,看看效果。之后对照着 demo 来慢慢讲解我们需要掌握的概念。
三、先写一个简单的窗口
程序员的惯例,一开始都要写个 Hello world,如图:
源码如下:
/**
* 只有hello world的窗口
*
* @author tinybye
* @date 2022/9/6
*/
public class SimpleFrame extends JFrame {
public SimpleFrame(String title) {
super(title);
JLabel label = new JLabel("Hello world!");
add(label);
// 指定窗口位置与大小
setBounds(300, 100, 400, 200);
// 显示窗口
setVisible(true);
}
public static void main(String[] args) {
new SimpleFrame("我是一个窗口");
}
}
下面我们一边看代码,一边介绍这个 demo 中涉及到的概念。
代码很简单,我们写了一个SimpleFrame
子类来继承JFrame
。
这里我们涉及到了第一个概念——容器。
当你想运行一个 Swing 写的 Java 图形化程序时,你需要有一个窗口来承载各种按钮、文本、列表等信息。而这个窗口(
Window
类)就是一个容器。而
JFrame
类继承了Window
类,它是一个最常见最基础的容器,带 GUI 的应用程序至少要使用一个JFrame
**。**你可以这样简单理解:如果你想启动一个图形化程序,你必须要创建一个JFrame
对象。
接下来,构造方法的入参指定了这个窗口的标题。在构造方法里,我们指定了该框架的大小、显示的位置,并且在里面添加了一个文本为“Hello world!”的JLabel
(标签)。
这里就是我们涉及到的第二个概念——组件。
一段文本、一个按钮、一个列表、一个下拉框,都是一个组件。你的容器承载着一堆组件,展示在你的面前,成为一个图形化程序。
组件们都继承了
JComponent
类。
构造方法里填充了这个页面的全部信息后,我们在main
方法里创建一个SimpleFrame
对象,一个有界面的 Java 程序就启动了,我们绘制的窗口就出现在了屏幕上。
四、一个有交互的例子
上面的只是一个展示窗口的非常简单的例子,现在我们再写一个有交互的 demo。
主窗口有一个按钮,以及文案,如图:
点击按钮之后,会弹出一个弹窗,随后,主窗口的点击次数会随之增加:
源码如下:
/**
* 一个有交互的窗口
*
* @author tinybye
* @date 2022/9/6
*/
public class ClickFrame extends JFrame {
int count = 0;
public ClickFrame(String title) {
super(title);
JLabel label = new JLabel("点击次数:" + count);
JButton button = new JButton("点我");
// 按钮监听事件
button.addActionListener(e -> {
count++;
label.setText("点击次数:" + count);
// 弹出一个简易的dialog对话框
JOptionPane.showMessageDialog(null, "别点了,别点了!");
});
// 设置布局,这里使用流式布局
setLayout(new FlowLayout());
// 标签和按钮都添加进窗口
add(label);
add(button);
// 指定窗口位置与大小
setBounds(300, 100, 200, 100);
// 显示窗口
setVisible(true);
}
public static void main(String[] args) {
new ClickFrame("一个有交互的窗口");
}
}
这个例子可谓是麻雀虽小五脏俱全了,设计的要素丰富了很多,有按钮,有 JLabel,有布局,有触发事件,还有新的容器 Dialog。
接下来我们就跟着代码一起,接触一下新的概念吧。
我们在窗口里放置了一个 JLabel 和一个按钮,这俩都是组件。按钮这个东西,肯定是可以点击的。我们通过addActionListener
方法为按钮增加一个监听器来监听按钮的点击动作,进而可以触发一个事件来实现点击按钮的交互。
这个事件里,我们做了三件事:记录点击次数、刷新JLabel以及弹出一个对话框,这个对话框是一个JDialog
JDialog
和JFrame
一样,也是一个容器。JFrame
是一个窗口,JDialog
是一个对话框。作为对话框,相对来说要简单一些。
之后使用setLayout
方法给窗口指定了布局管理器为FlowLayout
流式布局管理器。
一个新概念,布局管理器又是啥?
当一个窗口里有多个组件时,我们需要管理这些组件的摆放位置,这就是布局管理器的作用。
常用的布局管理器有很多种,有边框布局管理器、流式布局管理器等等,不同的布局管理器适用于不同类型页面的布局,可以分情况使用。代码里使用的是流式布局管理器,组件会按照从左到右,从上到下的顺序排列。
五、容器、组件和布局
本文主要是通过两个例子来介绍一下 Swing 最常见的几个概念,初步的认识一下一个简单且完整的 Swing 程序是什么样的。
在这里总结一下,今天涉及到的容器、组件和布局的概念。
1.容器
一个有界面的 Swing 程序,需要一个容器来承载这个界面上的各个元素。常见的容器类有JFrame
和JDialog
。
JFrame
会展示一个窗口,一个图形化的 Swing 程序必须要依赖一个JFrame
。
JDialog
是一个对话框,作为一个弹框,可以显示一些简单的信息。
2.组件
你在界面上看到的所有元素,比如:标签、按钮、文本框、下拉框等等,都是组件。我们通过把组件摆放到容器中,来生成一个你想要的页面。
组件的信息是可以动态变化的(比如第二个例子中 JLabel 的文案改变),其中有的组件也可以监听事件触发逻辑(比如点击按钮后展示弹窗)。
3.布局
如何让容器中的组件整齐清晰的按照你的想法摆放到正确的位置,是布局管理器要做的事情。不同的布局管理器会让组件按照不同的布局来展示。
本文只是简单介绍了流式布局管理器,更多的布局管理器,会在后续的文章中详细介绍。
其实刚接触 Swing 的时候,两眼一抹黑,并且感觉这种用代码定位而不是拖拽控件的方式实在是太反人性太繁琐了。不过接触了一段时间,发现 Swing 的整体设计真不赖,很多地方都是有规律可循的。给自己打打气吧,希望这个系列的文章更新完毕后,对 Swing 的使用就能游刃有余了。