Java Swing组件学习笔记
写在前面
由于最近在做编译原理实验的作业——制作八、十、十六进制计算器,想要得高分需要做个界面。
于是乎想到之前有学过的Java的Swing组件(简单易用),不过也有些忘记了,就顺手写篇博客记录一下制作过程以及期间遇到的细节问题(
So,这篇博客讲的更多的会是计算器怎么做啦。
注意:由于本人用的是macOS系统,默认组件显示效果会与其他系统有所不同。
持续更新中……
前期工作
在使用Swing组件前,你至少需要了解JAVA的基本语法,以及常见错误排查。
那么,先让我们大致了解一下Java Swing吧。
什么是Swing组件?
注意:以下部分内容摘自菜鸟教程 - Java Swing 介绍
Swing 是一个为Java设计的GUI工具包。
Swing是Java基础类的一部分。
Swing包括了图形用户界面(GUI)器件如:文本框,按钮,分隔窗格和表。
Swing提供许多比AWT更好的屏幕显示元素。它们用纯Java写成,所以同Java本身一样可以跨平台运行,这一点不像AWT。它们是JFC的一部分。它们支持可更换的面板和主题(各种操作系统默认的特有主题),然而不是真的使用原生平台提供的设备,而是仅仅在表面上模仿它们。这意味着你可以在任意平台上使用JAVA支持的任意面板。轻量级组件的缺点则是执行速度较慢,优点就是可以在所有平台上采用统一的行为。
它包含些什么?
JFrame – java的GUI程序的基本思路是以JFrame为基础,它是屏幕上window的对象,能够最大化、最小化、关闭。
JPanel – Java图形用户界面(GUI)工具包swing中的面板容器类,包含在javax.swing 包中,可以进行嵌套,功能是对窗体中具有相同逻辑功能的组件进行组合,是一种轻量级容器,可以加入到JFrame窗体中。
JLabel – JLabel 对象可以显示文本、图像或同时显示二者。可以通过设置垂直和水平对齐方式,指定标签显示区中标签内容在何处对齐。默认情况下,标签在其显示区内垂直居中对齐。默认情况下,只显示文本的标签是开始边对齐;而只显示图像的标签则水平居中对齐。
JTextField – 一个轻量级组件,它允许编辑单行文本。
JButton – JButton 类的实例。用于创建按钮。
……
当然,Swing还有很多其他的组件,这里只列(抄)出一些常用组件。
这些组件按照不同的功能,可分为顶层组件、中间容器和基本组件,其层级结构为:
- 顶层容器
- 菜单栏(特殊中间容器)
- 中间容器
- 基本组件
如果破坏这个结构去绘制窗口,可能会导致出现一些奇怪的错误。
可以点击这里了解更多。
尝试编写
JFrame - 一切的开端
在编写任何GUI窗口以前,我们需要先创建一个JFrame实例,使得这个窗口能够在系统中显示。
这个JFrame便是我们上文有提到的顶层容器之一。
JFrame的常用默认构造方法有两个:
-
JFrame() 创建默认无标题窗口
-
JFrame(String) 创建带标题窗口
那么我们就可以这样new一个JFrame对象,并设置让它显示:
1 | import javax.swing.*; // 引入Swing组件 |
运行后会出现如下图的窗口:
当然也可以采用继承的方式(推荐):
1 | import javax.swing.*; |
使用继承的方式可以让我们更好地去修改这个JFrame窗口及其内含组件,大家也可能发现了,这里用到了两个方法,这是JFrame里默认定义的一些方法,合理使用它们可以更好地DIY你的JFrame,下面是一些常用方法:
方法 | 概述 |
---|---|
setTitle(String) | 设置当前JFrame的标题 |
setResizable(boolean) | 设置当前JFrame可否调整大小 |
setDefaultCloseOperation(int) | 设置当前JFrame点击关闭按钮的动作 |
setVisible(boolean) | 设置当前JFrame是否可见 |
setSize(int, int) | 设置当前JFrame宽高 |
setLocationRelativeTo(Component) | 设置当前JFrame位置,null居中 |
Insets getInsets() | 返回当前JFrame边框元素 |
add(Object) | 往当前JFrame添加组件 |
Q:为什么推荐使用继承的方式?
A:继承方式可以让我们更好地自定义(或者说DIY)JFrame,包括一些配置以及添加相关组件、监听事件等,对于Swing中含有的其他组件,也是推荐这样,当然前提是你需要DIY这个组件。
JPanel - 重点基础
创建好窗口后,我们便需要往这个JFrame里添加中间容器,JPanel便是其中之一。
它就是一个普通的面板,可以往其中添加任意基本组件,甚至可以嵌套JPanel,如果是了解、学习过HTML的读者,可以大致地将其理解为<div>标签,而JFrame则大致是<body>标签。
JPanel的常用的构造方法有:
- JPanel() 创建默认使用流式布局的面板
- JPanel(LayoutManager) 创建指定布局的面板
因为JPanel可以添加组件,所以JPanel里也有一些和JFrame类似的方法,例如setSize
和add
。
不过除了普通的面板,Swing组件里还提供了这些:
面板组件 | 概述 |
---|---|
JScrollPanel | 可滚动显示的面板 |
JSplitPane | 分隔面板 |
JTabbedPane | 选项卡面板 |
JLayeredPane | 层级面板 |
由于面板在不添加其他组件时,并不会显示任何,在没有介绍其他组件以前,这里便不做过多介绍。但需要注意的是,面板很重要,对于组件布局这件头疼的事情来说,它起到了一个很好地中间作用(类似HTML中<div>的重要性)。
JButton - 初识布局
有了界面,怎么能让它空空如也呢?第一件事当然是往窗口里加图标!
JButton常用的构造方法有:
- JButton() 创建无内容的按钮
- JButton(String) 创建含文本内容的按钮
- JButton(Icon) 创建有图标的按钮
这里再介绍一下JButton的常用方法:
方法 | 概述 |
---|---|
setText(String) | 设置按钮显示的文本 |
setFont(Font) | 设置按钮显示的文本的字体 |
setForeground(Color) | 设置按钮文本的字体颜色 |
setIcon(Icon) | 设置按钮默认图标 |
setPressedIcon(Icon) | 设置按下时图标 |
setDisabledIcon(Icon) | 设置不可用时图标 |
addActionListener(ActionListener) | 添加监听事件 |
doClick() | 模拟点击 |
那么根据这些方法,我们就可以尝试着new一个JButton,添加到我们之前创建好的JFrame里去:
1 | import javax.swing.*; |
显示效果如下:
可以看到,我们没有对JButton、JFrame做任何配置时,往JFrame直接添加JButton组件会占满整个窗口。
甚至是添加3、4个JButton时,也可能会被最后被添加的那一个占满。
这里会涉及到两个概念:设置大小、组件布局。
首先是布局——这一概念非常重要,之后会专门讲到,这里先提一下,在Swing组件中常用的布局管理器:
布局管理器 | 描述 |
---|---|
FlowLayout | 流式布局,按组件加入顺序水平方向排列到当前组件,排满一行换下一行。 |
GirdLayout | 网格布局,将当前组件按指定行列数用网格分隔,每个网格放一个组件。 |
GridBagLayout | 网格袋布局,按网格将当前组件分割,每个组件可以占一个或多个网格,每个组件所占的网格大小可以用水平线和垂直线自定义。 |
BoxLayout | 箱式布局,将当前组件中的多个组件按水平或垂直方式排列。 |
GroupLayout | 分组布局,将当前组件按层次分组(串行或并行),分别确定组件组在水平和垂直方向的位置。 |
CardLayout | 卡片布局,将当前组件中的每个组件看作一张卡片,一次只显示一张,默认显示第一张。 |
BorderLayout | 边界布局,把当前组件按东西南北中五个方位分割,每个区域放一个组件。 |
SpringLayout | 弹性布局,通过定义组件四条边的坐标位置来实现布局。 |
null | 空(绝对)布局,对每个组件设置位置、大小放置到当前组件中。 |
注意:如果当前组件没有设置任何布局管理器,默认使用FlowLayout(JFrame除外,它会默认使用BorderLayout)。
对于大多数组件来说,setSize
这个方法是可以直接用的,但若是这个组件被放到一个有布局管理器的组件时,这个方法是会失效的,我们需要用上另外一个方法来定义它的大小:
- setPreferredSize(Dimension)
这个方法并不算Swing组件中的一个,而是Swing的前身——awt中的一个方法,它会获取当前空间的preferredsize,它会自己选择最好的大小,并且随着外部空间的大小改变,而setSize是固定大小,两者各有用处,这里我们只需要先了解到有布局管理器的情况下需要用setPreferredSize即可。
这里举个例子:
1 | import javax.swing.*; |
可以很清楚地看到,按钮成功地缩小嘞。但是会发现,这个按钮被莫名其妙放到了中间?
为之前jPanel对象设置边框后,我们会惊讶地发现,这个JPanel居然占满了整个窗口,甚至是设置了大小也一样?
1 | import javax.swing.*; |
这又回到了之前提到的布局概念,由于JFrame默认是BorderLayout布局,分为东西南北中五块,每一个组件会默认占满一块(无法自定大小),而我把JPanel添加到JFrame时没有定义位置,所以会默认填满整个窗口。
如果对JFrame设置其他布局管理器,就可以避免这个情况。