不安分的黑娃
踏踏实实,坚持学习,慢慢就懂了~

参考资料

  1. Java Swing 教程(C语言中文网)
  2. oracle 怎么使用 swing 组件?
  3. JDK 1.8 API

什么是 Swing ?

Swing 是一个用于 Java GUI 编程(图形界面设计)的工具包(类库);换句话说,Java 可以用来开发带界面的 PC 软件,使用到的工具就是 Swing。

Swing 使用纯粹的 Java 代码来模拟各种控件(使用 Java 自带的作图函数绘制出各种控件),没有使用本地操作系统的内在方法,所以 Swing 是跨平台的。也正是因为 Swing 的这种特性,人们通常把 Swing 控件称为轻量级控件。

Swing 和 AWT

AWT(Abstract Window Toolkit,抽象窗口工具)是一套早期的 Java GUI 开发工具,Swing 也是在 AWT 的基础上发展起来的。

AWT 的初衷是用来开发小型的图形界面程序,提供的功能较少,诸如剪切板、打印支持、键盘导航、弹出式菜单、滚动窗格等很多重要的功能在 AWT 中都不具备;此外,AWT 发生错误的几率也很高。

Java 官方看到了 AWT 的不足,就开始着手开发新的 GUI 类库,以继续占领 Java GUI 开发的市场,这就是后来的 Swing。

Swing 弥补了 AWT 的不足,并对 AWT 进行了扩充,几乎支持了所有的常用控件和功能,它们不但更加漂亮,而且更加易用,真正实现了“一次编译,到处运行”的承诺。

目前,Swing 已经代替 AWT 成为 Java 图形界面设计的首选,相对于 AWT 来说,Swing 有过之而无不及。

Swing 组件

1 JFrame 窗口

JFrame 用来设计类似于 Windows 系统中窗口形式的界面。JFrame 是 Swing 组件的顶层容器,该类继承了 AWT 的 Frame 类,支持 Swing 体系结构的高级 GUI 属性。

2 JPanel 面板

JPanel 是一种中间层容器,它能容纳组件并将组件组合在一起,但它本身必须添加到其他容器中使用。JPanel 类的构造方法如下:

  • JPanel():使用默认的布局管理器创建新面板,默认的布局管理器为 FlowLayout。
  • JPanel(LayoutManagerLayout layout):创建指定布局管理器的 JPanel 对象。

3 LayoutManager 布局管理器

3.1 边框布局管理器

BorderLayout(边框布局管理器)是 Window、JFrame 和 JDialog 的默认布局管理器。边框布局管理器将窗口分为 5 个区域:North、South、East、West 和 Center。

image

BorderLayout 布局管理器的构造方法如下所示:

  • BorderLayout():创建一个 Border 布局,组件之间没有间隙。
  • BorderLayout(int hgap,int vgap):创建一个 Border 布局,其中 hgap 表示组件之间的横向间隔;vgap 表示组件之间的纵向间隔,单位是像素。

3.2 流式布局管理器

FlowLayout(流式布局管理器)是 JPanel 和 JApplet 的默认布局管理器。FlowLayout 会将组件按照从上到下、从左到右的放置规律逐行进行定位。与其他布局管理器不同的是,FlowLayout 布局管理器不限制它所管理组件的大小,而是允许它们有自己的最佳大小。

FlowLayout 布局管理器的构造方法如下。

  • FlowLayout():创建一个布局管理器,使用默认的居中对齐方式和默认 5 像素的水平和垂直间隔。
  • FlowLayout(int align):创建一个布局管理器,使用默认 5 像素的水平和垂直间隔。其中,align 表示组件的对齐方式,对齐的值必须是 FlowLayoutLEFT、FlowLayout.RIGHT 和 FlowLayout.CENTER,指定组件在这一行的位置是居左对齐、居右对齐或居中对齐。
  • FlowLayout(int align, int hgap,int vgap):创建一个布局管理器,其中 align 表示组件的对齐方式;hgap 表示组件之间的横向间隔;vgap 表示组件之间的纵向间隔,单位是像素。
    image

3.3 卡片布局管理器

CardLayout(卡片布局管理器)能够帮助用户实现多个成员共享同一个显不空间,并且一次只显示一个容器组件的内容。

CardLayout 布局管理器将容器分成许多层,每层的显示空间占据整个容器的大小,但是每层只允许放置一个组件。
CardLayout 的构造方法如下。

  • CardLayout():构造一个新布局,默认间隔为 0。
  • CardLayout(int hgap, int vgap):创建布局管理器,并指定组件间的水平间隔(hgap)和垂直间隔(vgap)。

image
image

3.4 网格布局管理器

GridLayout(网格布局管理器)为组件的放置位置提供了更大的灵活性。它将区域分割成行数(rows)和列数(columns)的网格状布局,组件按照由左至右、由上而下的次序排列填充到各个单元格中。

GridLayout 的构造方法如下:

  • GridLayout(int rows,int cols):创建一个指定行(rows)和列(cols)的网格布局。布局中所有组件的大小一样,组件之间没有间隔。
  • GridLayout(int rows,int cols,int hgap,int vgap):创建一个指定行(rows)和列(cols)的网格布局,并且可以指定组件之间横向(hgap)和纵向(vgap)的间隔,单位是像素。
    image

3.5 网格包布局管理器

GridBagLayout(网格包布局管理器)是在网格基础上提供复杂的布局,是最灵活、 最复杂的布局管理器。GridBagLayout 不需要组件的尺寸一致,允许组件扩展到多行多列。每个 GridBagLayout 对象都维护了一组动态的矩形网格单元,每个组件占一个或多个单元,所占有的网格单元称为组件的显示区域。

GridBagLayout 所管理的每个组件都与一个 GridBagConstraints 约束类的对象相关。这个约束类对象指定了组件的显示区域在网格中的位置,以及在其显示区域中应该如何摆放组件。除了组件的约束对象,GridBagLayout 还要考虑每个组件的最小和首选尺寸,以确定组件的大小。

为了有效地利用网格包布局管理器,在向容器中添加组件时,必须定制某些组件的相关约束对象。GridBagConstraints 对象的定制是通过下列变量实现的:

  1. gridx 和 gridy
    用来指定组件左上角在网格中的行和列。容器中最左边列的 gridx 为 0,最上边行的 gridy 为 0。这两个变量的默认值是 GridBagConstraints.RELATIVE,表示对应的组件将放在前一个组件的右边或下面。
  2. gridwidth 和 gridheight
    用来指定组件显示区域所占的列数和行数,以网格单元而不是像素为单位,默认值为 1。
  3. fill
    指定组件填充网格的方式,可以是如下值:GridBagConstraints.NONE(默认值)、GridBagConstraints.HORIZONTAL(组件横向充满显示区域,但是不改变组件高度)、GridBagConstraints.VERTICAL(组件纵向充满显示区域,但是不改变组件宽度)以及 GridBagConstraints.BOTH(组件横向、纵向充满其显示区域)。
  4. ipadx 和 ipady
    指定组件显示区域的内部填充,即在组件最小尺寸之外需要附加的像素数,默认值为 0。
  5. insets
    指定组件显示区域的外部填充,即组件与其显示区域边缘之间的空间,默认组件没有外部填充。
  6. anchor
    指定组件在显示区域中的摆放位置。可选值有 GridBagConstraints.CENTER(默认值)、GridBagConstraints.NORTH、GridBagConstraints.
    NORTHEAST、GridBagConstraints.EAST、GridBagConstraints.SOUTH、GridBagConstraints.SOUTHEAST、GridBagConstraints.WEST、GridBagConstraints.SOUTHWEST 以及 GridBagConstraints.NORTHWEST。
  7. weightx 和 weighty
    用来指定在容器大小改变时,增加或减少的空间如何在组件间分配,默认值为 0,即所有的组件将聚拢在容器的中心,多余的空间将放在容器边缘与网格单元之间。weightx 和 weighty 的取值一般在 0.0 与 1.0 之间,数值大表明组件所在的行或者列将获得更多的空间。
    image

4.6 盒布局管理器

BoxLayout(盒布局管理器)通常和 Box 容器联合使用,Box 类有以下两个静态方法。

  • createHorizontalBox():返回一个 Box 对象,它采用水平 BoxLayout,即 BoxLayout 沿着水平方向放置组件,让组件在容器内从左到右排列。
  • createVerticalBox():返回一个 Box 对象,它采用垂直 BoxLayout,即 BoxLayout 沿着垂直方向放置组件,让组件在容器内从上到下进行排列。

image

4 JLable 标签组件

在添加了容器并指定了布局管理方式之后,便可以向容器中添加各种展示类的组件,像标签、按钮、单选和多选框等。

标签是一种可以包含文本和图片的非交互组件,其文本可以是单行文本,也可以是 HTML 文本。

对于只包含文本的标签可以使用 JLabel 类,该类的主要构造方法有如下几种形式。

  • JLabel():创建无图像并且标题为空字符串的 JLabel。
  • JLabel(Icon image):创建具有指定图像的 JLabel。
  • JLabel(String text):创建具有指定文本的 JLabel。
  • JLabel(String textjcon image,int horizontalAlignment):创建具有指定文本、图像和水平对齐方式的 JLabel,horizontalAlignment 的取值有 3 个,即 JLabel.LEFT、JLabel.RIGHT 和 JLabel.CENTER。

5 JButton 按钮组件

按钮是图形界面上常见的元素,在前面已经多次使用过它。在 Swing 中按钮是 JButton 类的对象,JButton 类的常用构造方法如下。

  • JButton():创建一个无标签文本、无图标的按钮。
  • JButton(Icon icon):创建一个无标签文本、有图标的按钮。
  • JButton(String text):创建一个有标签文本、无图标的按钮。
  • JButton(String text,Icon icon):创建一个有标签文本、有图标的按钮。

表1 JButton类的常用方法

方法名称 说明
addActionListener(ActionListener listener) 为按担组件注册 ActionListener 监听
void setIcon(Icon icon) 设置按钮的默认图标
void setText(String text) 设置按鈕的文本
void setMargin(Insets m) 设置按钮边框和标签之间的空白
void setMnemonic(int nmemonic) 设置按钮的键盘快捷键,所设置的快捷键在实际操作时需要结合 Alt 键进行实现
void setPressedIcon(Icon icon) 设置按下按钮时的图标
void setSelectedIcon(Icon icon) 设置选择按鈕时的图标
void setRolloveiicon(Icon icon) 设置鼠标移动到按扭区域时的图标
void setDisabledIcon(Icon icon) 设置按钮无效状态下的图标
void setVerticalAlignment(int alig) 设置图标和文本的垂直对齐方式
void setHorizontalAlignment(int alig) 设置图标和文本的水平对齐方式
void setEnable(boolean flag) 启用或禁用按扭
void setVerticalTextPosition(int textPosition) 设置文本相对于图标的垂直位置
void setHorizontalTextPosition(int textPosition) 设置文本相对于图标的水平位置

6 JTextField 单行文本框组件

Swing 中使用 JTextField 类实现一个单行文本框,它允许用户输入单行的文本信息。该类的常用构造方法如下:

  • JTextField():创建一个默认的文本框。
  • JTextField(String text):创建一个指定初始化文本信息的文本框。
  • JTextField(int columns):创建一个指定列数的文本框。
  • JTextField(String text,int columns):创建一个既指定初始化文本信息,又指定列数的文本框。
方法名称 说明
Dimension getPreferredSize() 获得文本框的首选大小
void scrollRectToVisible(Rectangle r) 向左或向右滚动文本框中的内容
void setColumns(int columns) 设置文本框最多可显示内容的列数
void setFont(Font f) 设置文本框的字体
void setScrollOffset(int scrollOffset) 设置文本框的滚动偏移量(以像素为单位)
void setHorizontalAlignment(int alignment) 设置文本框内容的水平对齐方式

7 JTextArea 文本域组件

文本域与文本框的最大区别就是文本域允许用户输入多行文本信息。

在 Swing 中使用 JTextArea 类实现一个文本域,其常用构造方法如下:

  • JTextArea():创建一个默认的文本域。
  • JTextArea(int rows,int columns):创建一个具有指定行数和列数的文本域。
  • JTextArea(String text):创建一个包含指定文本的文本域。
  • JTextArea(String text,int rows,int columns):创建一个既包含指定文本,又包含指定行数和列数的多行文本域。
方法名称 说明
void append(String str) 将字符串 str 添加到文本域的最后位置
void setColumns(int columns) 设置文本域的行数
void setRows(int rows) 设置文本域的列数
int getColumns() 获取文本域的行数
void setLineWrap(boolean wrap) 设置文本域的换行策略
int getRows() 获取文本域的列数
void insert(String str,int position) 插入指定的字符串到文本域的指定位置
void replaceRange(String str,int start,int end) 将指定的开始位 start 与结束位 end 之间的字符串用指定的字符串 str 取代

image

8 JCheckBox 复选框组件

一个复选框有选中和未选中两种状态,并且可以同时选定多个复选框。Swing 中使用 JCheckBox 类实现复选框,该类的常用构造方法如下:

  • JCheckBox():创建一个默认的复选框,在默认情况下既未指定文本,也未指定图像,并且未被选择。
  • JCheckBox(String text):创建一个指定文本的复选框。
  • JCheckBox(String text,boolean selected):创建一个指定文本和选择状态的复选框。

image

9 JRadioButton 单选按钮组件

单选按钮与复选框类似都有两种状态,不同的是一组单选按钮中只能有一个处于选中状态。Swing 中 JRadioButton 类实现单选按钮,它与 JCheckBox 一样都是从 JToggleButton 类派生出来的。JRadioButton 通常位于一个 ButtonGroup 按钮组中,不在按钮组中的 JRadioButton 也就失去了单选按钮的意义。

在同一个 ButtonGroup 按钮组中的单选按钮,只能有一个单选按钮被选中。因此,如果创建的多个单选按钮其初始状态都是选中状态,则最先加入 ButtonGroup 按钮组的单选按钮的选中状态被保留,其后加入到 ButtonGroup 按钮组中的其他单选按钮的选中状态被取消。

JRadioButton 类的常用构造方法如下。

  • JRadioButton():创建一个初始化为未选择的单选按钮,其文本未设定。
  • JRadioButton(Icon icon):创建一个初始化为未选择的单选按钮,其具有指定的图像但无文本。
  • JRadioButton(Icon icon,boolean selected):创建一个具有指定图像和选择状态的单选按钮,但无文本。
  • JRadioButton(String text):创建一个具有指定文本但未选择的单选按钮。
  • JRadioButton(String text,boolean selected):创建一个具有指定文本和选择状态的单选按钮。
  • JRadioButton(String text,Icon icon):创建一个具有指定的文本和图像并初始化为未选择的单选按钮。
  • JRadioButton(String text,Icon icon,boolean selected):创建一个具有指定的文本、图像和选择状态的单选按钮。

10 JComboBox 下拉列表组件

下拉列表的特点是将多个选项折叠在一起,只显示最前面的或被选中的一个。选择时需要单击下拉列表右边的下三角按钮,这时候会弹出包含所有选项的列表。用户可以在列表中进行选择,也可以根据需要直接输入所要的选项,还可以输入选项中没有的内容。

下拉列表由 JComboBox 类实现,常用构造方法如下:

  • JComboBox():创建一个空的 JComboBox 对象。
  • JComboBox(ComboBoxModel aModel):创建一个 JComboBox,其选项取自现有的 ComboBoxModel。
  • JComboBox(Object[] items):创建包含指定数组中元素的 JComboBox。

表1 JComboBox类的常用方法

方法名称 说明
void addItem(Object anObject) 将指定的对象作为选项添加到下拉列表框中
void insertItemAt(Object anObject,int index) 在下拉列表框中的指定索引处插入项
void removeltem(0bject anObject) 在下拉列表框中删除指定的对象项
void removeItemAt(int anlndex) 在下拉列表框中删除指定位置的对象项
void removeAllItems() 从下拉列表框中删除所有项
int getItemCount() 返回下拉列表框中的项数
Object getItemAt(int index) 获取指定索引的列表项,索引从 0 开始
int getSelectedIndex() 获取当前选择的索
Object getSelectedltem() 获取当前选择的项

JComboBox 能够响应 ItemEvent 事件和 ActionEvent 事件,其中 ItemEvent 触发的时机是当下拉列表框中的所选项更改时,ActionEvent 触发的时机是当用户在 JComboBox 上直接输入选择项并回车时。要处理这两个事件,需要创建相应的事件类并实现 ItemListener 接口和 ActionListener 接口。

image

11 JList 列表框组件事情

列表框与下拉列表的区别不仅仅表现在外观上,当激活下拉列表时,会出现下拉列表框中的内容。但列表框只是在窗体系上占据固定的大小,如果需要列表框具有滚动效果,可以将列表框放到滚动面板中。当用户选择列表框中的某一项时,按住 Shift 键并选择列表框中的其他项目,可以连续选择两个选项之间的所有项目,也可以按住 Ctrl 键选择多个项目。

Swing 中使用 JList 类来表示列表框,该类的常用构造方法如下:

  • JList():构造一个空的只读模型的列表框。
  • JList(ListModel dataModel):根据指定的非 null 模型对象构造一个显示元素的列表框。
  • JList(Object[] listData):使用 listData 指定的元素构造—个列表框。
  • JList(Vector<?> listData):使用 listData 指定的元素构造一个列表框。

上述的第一个构造方法没有参数,使用此方法创建列表框后可以使用 setListData() 方法对列表框的元素进行填充,也可以调用其他形式的构造方法在初始化时对列表框的元素进行填充。常用的元素类型有 3 种,分别是数组、Vector 对象和 ListModel 模型。

12 事件监听

事件表示程序和用户之间的交互,例如在文本框中输入,在列表框或组合框中选择,选中复选框和单选框,单击按钮等。事件处理表示程序对事件的响应,对用户的交互或者说对事件的处理是事件处理程序完成的。
当事件发生时,系统会自动捕捉这一事件,创建表示动作的事件对象并把它们分派给程序内的事件处理程序代码。这种代码确定了如何处理此事件以使用户得到相应的回答。

事件处理模型

image
由于同一个事件源上可能发生多种事件,因此,Java 采取了授权模型(Delegation Model),事件源可以把在其自身上所有可能发生的事件分别授权给不同的事件处理者来处理。例如,在 Panel 对象上既可能发生鼠标事件,也可能发生键盘事件,该 Panel 对象可以授权给事件处理者 a 来处理鼠标事件,同时授权给事件处理者 b 来处理键盘事件。

有时也将事件处理者称为监听器,主要原因在于监听器时刻监听事件源上所有发生的事件类型,一旦该事件类型与自己所负责处理的事件类型一致,就马上进行处理。授权模型把事件的处理委托给外部的处理实体进行处理,实现了将事件源和监听器分开的机制。

事件处理者(监听器)通常是一个类,该类如果能够处理某种类型的事件,就必须实现与该事件类型相对的接口。例如,一个 ButtonHandler 类之所以能够处理 ActionEvent 事件,原因在于它实现了与 ActionEvent 事件对应的接口 ActionListener。每个事件类都有一个与之相对应的接口。

动作事件监听器

动作事件监听器是 Swing 中比较常用的事件监听器,很多组件的动作都会使用它监听,像按钮被里击、列表框中选择一项等。与动作事件监听器有关的信息如下:

  • 事件名称:ActionEvent。
  • 事件监听接口: ActionListener。
  • 事件相关方法:addActionListener() 添加监听,removeActionListener() 删除监听。
  • 涉及事件源:JButton、JList、JTextField 等。

焦点事件监听器

焦点事件监听器在实际项目中应用也比较广泛,例如将光标离开文本框时弹出对话框,或者将焦点返回给文本框等。

与焦点事件监听器有关的信息如下:

  • 事件名称:FocusEvent。
  • 事件监听接口: FocusListener。
  • 事件相关方法:addFocusListener() 添加监听,removeFocusListener() 删除监听。
  • 涉及事件源:Component 以及派生类。

FocusEvent 接口定义了两个方法,分别为 focusGained() 方法和 focusLost() 方法,其中 focusGained() 方法是在组件获得焦点时执行,focusLost() 方法是在组件失去焦点时执行。

监听列表项选择事件

列表框控件 JList 会显示很多项供用户选择,通常在使用时会根据用户选择的列表项完成不同的操作。

13 JSlider 滑块组件

滑块(JSlider)是一个允许用户在有限区间内通过移动滑块来选择值的组件。

滑块可以显示主刻度标记以及主刻度之间的次刻度标记。刻度标记之间的值的个数由 setMajorTickSpacing() 方法和 setMinorTickSpacing() 方法来控制。刻度标记的绘制由 setPaintTicks() 方法控制。

滑块也可以在固定时间间隔(或在任意位置)沿滑块刻度打印文本标签,标签的绘制由 setLabelTable() 方法和 setPaintLabels() 方法控制。

JSIider类的常用构造方法:

  • JSlider() 创建一个范围在 0~100 且初始值为 50 的水平滑块
  • JSlider(BoundedRangeModel brm) 使用指定的 BoundedRangeModel 创建一个水平滑块
  • JSlider(int orientation) 使用指定的方向创建一个滑块,范围在 0~100 且初始值为 50
  • JSlider(int min,int max) 使用指定的最小值和最大值来创建一个水平滑块,初始值等于最小值加上最大值的平均值
  • JSlider(int min,int max,int value) 用指定的最小值、最大值和初始值创建一个水平滑块
方法名称 说明
createStandardLabels(int increment) 创建一个数字文本标签的 Hashtable,从滑块最小值处开始增加,并使用指定的增量
getLabelTable() 返回哪些标签在哪些刻度绘制的字典
getMaj orTickSpacing() 返回主刻度标记的间隔
getMaximum() 从 BoundedRangeModel 返回滑块所支持的最大值
getMinimum() 从 BoundedRangeModel 返回滑块所支持的最小值
getMinorTickSpacing() 返回次刻度标记的间隔
getSnapToTicks() 如果滑块(及其所表示的值)解析为最靠近用户放置滑块处的刻度标记的值,则返回为 true
getValue() 从 BoundedRangeModel 返回滑块的当前值
setLabelTable(Dictionary labels) 用于指定将在给定值处绘制哪个标签
setMaj orTickSpacing(int n) 此方法设置主刻度标记的间隔
setMaximum(int maximum) 将滑块的最大值设置为 maximum
setMinimum(int minimum) 将滑块的最小值设置为 minimum
setMinorTickSpacing(int n) 设置次刻度标记的间隔
setOrientation(int orientation) 将滑块的方向设置为 SwingConstants.VERTICAL 或 SwingConstants.HORIZONTAL
setPaintLabels(boolean b) 确定是否在滑块上绘制标签
setPaintTicks(boolean b) 确定是否在滑块上绘制刻度标记
setPaintTrack(boolean b) 确定是否在滑块上绘制滑道
setSnapToTicks(boolean b) 指定为 true,则滑块(及其所表示的值)解析为最靠近用户放置滑块处的刻度标记的值
setValue(int n) 将滑块的当前值设置为 n

image

14 JProgressBar 进度条组件

进度条(JProgressBar)是一种以可视化形式显示某些任务进度的组件。JProgressBar 类实现了一个用于为长时间的操作提供可视化指示器的 GUI 进度条。在任务的完成进度中,进度条显示该任务完成的百分比。此百分比通常由一个矩形以可视化形式表示,该矩形开始是空的,随着任务的完成逐渐被填充。此外,进度条可显示此百分比的文本表示形式。

JProgressBar 类的常用构造方法和 JSlider 类的常用构造方法一样,这里不再重复。

方法名称 说明
getMaximum() 返回进度条的最大值
getMinimum() 返回进度条的最小值
getPercentComplete() 返回进度条的完成百分比
getString() 返回当前进度的 String 表示形式
getValue() 返回进度条的当前 value
setBorderPainted(boolean b) 设置 borderPainted 属性,如果进度条应该绘制其边框,则此属性为 true
setIndeterminate(boolean newValue) 设置进度条的 indeterminate 属性,该属性确定进度条处于确定模式中还处于不确定模式中
setMaximum(int n) 将进度条的最大值设置为 n
setMinimum(int n) 将进度条的最小值设置为 n
setOrientation(int newOrientation) 将进度条的方向设置为 newOrientation
setString(String s) 设置进度字符串的值
setStringPainted(boolean b) 设置 stringPainted 属性的值,该属性确定进度条是否应该呈现进度字符串
setValue(int n) 将进度条的当前值设置为 n
updateUI() 将 UI 属性重置为当前外观对应的值

其中,setOrientation() 方法的参数值必须为 SwingConstants.VERTICAL 或 SwingConstants.HORIZONTAL。JProgressBar 使用 BoundedRangeModel 作为其数据模型,以 value 属性表示该任务的“当前”状态,minimum 和 maximum 属性分别表示开始点和结束点。

技巧:如果要执行一个未知长度的任务,可以调用 setlndeterminate(true) 将进度条设置为不确定模式。不确定模式的进度条将持续地显示动画来表示正进行的操作。一旦可以确定任务长度和进度量,则应该更新进度条的值,将其切换到确定模式。

image

15 Timer 计时器组件

计时器(Timer)组件可以在指定时间间隔触发一个或多个 ActionEvent。设置计时器的过程包括创建一个 Timer 对象,在该对象上注册一个或多个动作侦听器,以及使用 start() 方法启动该计时器。

创建 Timer 类时要指定一个延迟参数和一个 ActionListener。延迟参数用于设置初始延迟和事件触发之间的延迟(以毫秒为单位)。启动计时器后,它将在向已注册监听器触发第一个 ActionEvent 之前等待初始延迟。第一个事件之后,每次超过事件间延迟时它都继续触发事件,直到被停止。

创建 Timer 类之后,可以单独更改初始延迟和事件间延迟,并且可以添加其他 ActionListener。如果希望计时器只在第一次时触发然后停止,可以对计时器调用 setRepeats(false)。

方法名称 说明
addActionListener(ActionListener 1) 将一个动作监听器添加到 Timer
getDelay() 返回两次触发动作事件间延迟,以毫秒为单位
isCoalesce() 如果 Timer 组合多个挂起的动作事件,则返回 true
isRunning() 如果 Timer 正在运行,则返回 true
restart() 重新启动 Timer,取消所有挂起的触发并使它按初始延迟触发
setCoalesce(boolean flag) 设置 Timer 是否组合多个挂起的 ActionEvent
setDelay(int delay) 设置 Timer 的事件间延迟,两次连续的动作事件之间的毫秒数
setLogTimers(boolean flag) 启用/禁用计时器日志
setRepeats(boolean flag)
start() 启动 Timer,使它开始向其监听器发送动作事件
stop() 停止 Timer,使它停止向其监听器发送动作事件

16 JMenu和JPopupMenu:菜单和弹出式菜单

菜单由 Swing 中的 JMenu 类实现,可以包含多个菜单项和带分隔符的菜单。在菜单中,菜单项由 JMenuItem 类表示,分隔符由 JSeparator 类表示。

菜单本质上是带有关联 JPopupMenu 的按钮。当按下“按钮”时,就会显示 JPopupMenu。如果“按钮”位于 JMenuBar 上,则该菜单为顶层窗口。如果“按钮”是另一个菜单项,则 JPopupMenu 就是“下拉”菜单。

JMenu 菜单

创建菜单常用构造方法有两个:JMenu() 和 JMenu(String s)。第一个构造方法创建一个无文本的 JMenu 对象,第二个构造方法创建一个带有指定文本的 JMenu 对象。JMenu 类的常用方法如表 所示:

方法名称 说明
add(Action a) 创建连接到指定 Action 对象的新菜单项,并将其追加到此菜单的末尾
add(Component c) 将某个组件追加到此菜单的末尾
add(Component c,int index) 将指定组件添加到此容器的给定位置
add(JMenuItem menultem) 将某个菜单项追加到此菜单的末尾
add(String s) 创建具有指定文本的新菜单项,并将其追加到此菜单的末尾
addSeparator() 将新分隔符追加到菜单的末尾
doCliclc(int pressTime) 以编程方式执行“单击”操作
getDelay() 返回子菜单向上或向下弹出前建议的延迟(以毫秒为单位)
getltem(int pos) 返回指定位置的 JMenuItem
getItemCount() 返回菜单上的项数,包括分隔符
getMenuComponent(int n) 返回位于位置 n 的组件
getMenuComponents() 返回菜单子组件的 Component 数组
getSubElements() 返回由 MenuElement 组成的数组,其中包含此菜单组件的子菜单
insert(JMenuItem mi,int pos) 在给定位置插入指定的 JMenuitem
insert(String s,pos) 在给定位置插入具有指定文本的新菜单项
insertSeparator(int index) 在指定的位置插入分隔符
isMenuComponent(Component c) 如果在子菜单层次结构中存在指定的组件,则返回 true
isPopupMenuVisible() 如果菜单的弹出窗口可见,则返回 rue
isSelected() 如果菜单是当前选择的(即高亮显示的)菜单,则返回 true
isTopLevelMenu() 如果菜单是“顶层菜单”(即菜单栏的直接子级),则返回 true
setDelay(int d) 设置菜单的 PopupMenu 向上或向下弹出前建议的延迟
setMenuLocation(int x,int y) 设置弹出组件的位置
setPopupMenuVisible(boolean b) 设置菜单弹出的可见性
setSelected(boolean b) 设置菜单的选择状态

菜单如果依附到 JMenuBar 对象上,则此菜单就是菜单栏中的菜单。菜单如果依附在 JPopupMenu 对象上,此菜单就是弹出式菜单。

JMenuItem 类实现的是菜单中的菜单项。菜单项本质上是位于列表中的按钮。当用户单击“按钮”时,则执行与菜单项关联的操作。JMenuItem 的常用构造方法有以下三个:

  • JMenuItem(String text):创建带有指定文本的 JMenuItem。
  • JMenuItem(String text,Icon icon):创建带有指定文本和图标的 JMenuItem。
  • JMenuItem(String text,int mnemonic):创建带有指定文本和键盘助记符的 JMenuItem。

image

弹出式菜单 JPopuMenu

弹出式菜单由 JPopupMenu 类实现,它是一个可弹出并显示一系列选项的小窗口。它还用于当用户选择菜单项并激活它时显示的“右拉式(pull-right)”菜单,可以在想让菜单显示的任何其他位置使用。
JPopupMenu 类的常用方法如表所示:

方法名称 说明
getInvoker() 返回作为此弹出菜单的“调用者”的组件
setInvoker(Component invoker) 设置弹出菜单的调用者,即弹出菜单在其中显示的组件
addPopupMenuListener(PopupMenuListener1) 添加 PopupMenu 监听器
removePopupMenuListener(PopupMenuListener1) 移除 PopupMenu 监听器
getPopupMenuListeners() 返回利用 addPopupMenuListener()添加到此 JMenuitem 的所有 PopupMenuListener 组成的数组
getLabel() 返回弹出菜单的标签
setLabel(String label) 设置弹出菜单的标签
show(Component invoker,int x,int y) 在调用者的坐标空间中的位置 X、Y 处显示弹出菜单
getComponentIndex(Component c) 返回指定组件的索引

image

image

17 JToolBar 工具栏组件

工具栏提供了一个用来显示常用按钮和操作的组件。它可以把任意类型的组件附加到工具条上,但是通常是增加按钮。工具栏 JToolBar 类的常用构造方法如下所示:

  • JToolBar() 创建新的工具栏,默认的方向为 HORIZONTAL
  • JToolBar(int orientation) 创建具有指定 orientation 的新工具栏
  • JToolBar(String name) 创建一个具有指定 name 的新工具栏
  • JToolBar(String name,int orientation) 创建一个具有指定 name 和 orientation 的新工具栏

与 JMenuBar 不一样,JToolBar 对象可以直接被添加到容器中。JTodBar 类的常用方法:

方法名称 说明
add(Action a) 添加一个指派动作的新的 JButton
addSeparator() 将默认大小的分隔符添加到工具栏的末尾
addSeparator(Dimension size) 将指定大小的分隔符添加到工具栏的末尾
getComponentAtIndex(int i) 返回指定索引位置的组件
getComponentIndex(Component c) 返回指定组件的索引
getMargin() 返回工具栏边框和它的按钮之间的空白
getOrientation() 返回工具栏的当前方向
isFloatable() 获取 floatable 属性
isRollover() 返回 rollover 状态
setBorderPainted(boolean b) 设置 borderPainted 属性,如果需要绘制边框,则此属性为 true
setFloatable(boolean b) 设置 floatable 属性,如果要移动工具栏,此属性必须设置为 true
setLayout(LayoutManager mgr) 设置此容器的布局管理器
setMargin(Insets m) 设置工具栏边框和它的按钮之间的空白
setOrientation(int o) 设置工具栏的方向
setRollover(boolean rollover) 设置此工具栏的 rollover 状态

18 JFileChooser 文件选择器

文件选择器为用户能够操作系统文件提供了桥梁。swing 中使用 JFileChooser 类实现文件选择器,该类常用的构造方法如下:

  • JFileChooser():创建一个指向用户默认目录的 JFileChooser。
  • JFileChooser(File currentDirectory):使用指定 File 作为路径来创建 JFileChooser。
  • JFileChooser(String currentDirectoryPath):创建一个使用指定路径的 JFileChooser。
  • JFileChooser(String currentDirectoryPath, FileSystemView fsv):使用指定的当前目录路径和 FileSystem View 构造一个 JFileChooser。

JFileChooser 类的常用方法如下所示:

  • int showOpenDialog(Component parent):弹出打开文件对话框。
  • int showSaveDialog(Component parent):弹出保存文件对话框。

19 JColorChooser 颜色选择器

JColorChooser 类提供一个用于允许用户操作和选择颜色的控制器窗格。该类提供三个级别的 API:

  1. 显示有模式颜色选取器对话框并返回用户所选颜色的静态便捷方法。
  2. 创建颜色选取器对话框的静态方法,可以指定当用户单击其中一个对话框按钮时要调用的 ActionListener。
  3. 能直接创建 JColorChooser 窗格的实例(在任何容器中),可以添加 PropertyChange 作为监听器以检测当前“颜色”属性的更改。

颜色选择器的常用构造方法如下。

  • JColorChooser():创建初始颜色为白色的颜色选取器窗格。
  • JColorChooser(Color initialColor):创建具有指定初始颜色的颜色选取器窗格。
  • JColorChooser(ColorSelectionModel model):创建具有指定 ColorSelectionModel 颜色选取器窗格。

一般使用 JColorChooser 类的静态方法 showDialog(Component component,String title,Color initialColor) 创建一个颜色对话框,在隐藏对话框之前一直堵塞进程。其中 component 参数指定对话框所依赖的组件,title 参数指定对话框的标题,initialColor 参数指定对话框返回的初始颜色,即对话框消失后返回的默认值。

常用方法:

方法名称 说明
getColor() 获取颜色选取器的当前颜色值
getDragEnabled() 获取dragEnabled 属性的值
setColor(Color color) 将颜色选取器的当前颜色设置为指定颜色
setColor(int c) 将颜色选取器的当前颜色设置为指定颜色
setColor(int r,int g,int b) 将颜色选取器的当前颜色设置为指定的 RGB 颜色
setDragEnabled(boolean b) 设置 dragEnabled 属性,该属性必须为 true 才能启用对此组件的自动拖动处理(拖放操作的第一部分)

20 JOptionPane 对话框组件

对话框通常用作从用户处接收附加信息,或者提供发生了某种事件的通知。Java 提供了 JOptionPane 类,用来创建标准对话框,也可以通过扩展 JDialog 类创建自定义的对话框。JOptionPane 类可以用来创建 4 种类型的标准对话框:确认对话框、消息对话框、输入对话框和选项对话框。

确认对话框

确认对话框显示消息,并等待用户单击“确定”按钮来取消对话框,该对话框不返回任何值。而确认对话框询问一个问题,需要用户单击合适的按钮做出响应。确认对话框返回对应被选按钮的值。

JOptionPane#showConfirmDialog 创建确认对话框:

public static int showConfirmDialog(Component parentComponent,Object message,String title,int optionType,int messageType,Icon icon)

参数 parentComponent、message、title、messageType 和 icon 与 showMessageDialog() 方法中的参数的含义相同。其中,只有 parentComponent 和 message 参数是必需的,title 的默认值为“选择一个选项”。messageType 的默认值是 QUESTION_MESSAGE。optionType 参数用于控制在对话框上显示的按钮,可选值如下:

  • 0 或 JOptionPane.YES_NO_OPTIION。
  • 1 或 JOptionPane.YES_NO_CANCEL_0PTII0N。
  • 2 或 JOptionPane.OK_CANCEL_OPTIION。

showConfirmDialog() 方法返回所选选项对应的值,这些值可以是整数或常量值,如下:
0 或 JOptionPane.YES_OPTIION。
1 或 JOptionPane.NO_OPTIION。
2 或 JOptionPane.CANCEL_OPTIION。
0 或 JOptionPane.OK_OPTIION。
-1 或 JOptionPane.CLOSED_OPTIION。

提示:除了 CLOSED_OPTIION 外,其他常量值都对应于激活的按钮。CLOSED_OPTIION 表示对话框在没有任何按钮激活的情况下关闭,例如单击对话框上的关闭图标按钮。

消息对话框

消息对话框显示一条提示或警告用户的信息,并等待用户单击 OK 或“确定”按钮以关闭对话框。创建消息对话框的方法如下:

public static void showMessageDialog(Component parentComponent,Object message,String title,int messageType,Icon icon)

其中,只有 parentComponent 参数和 message 参数是必须指定的。parentComponent 可以是任意组件或者为空;message 用来定义提示信息,它是一个对象,但是通常使用字符串表示;title 是设置对话框标题的字符串;messageType 是以下整型或常量中的一个:

  • 0 或 JOptionPane.ERROR_MESSAGE。
  • 1 或 JOptionPane.INFORMATION_MESSAGE。
  • JOptionPane.PLAIN_MESSAGE。
  • 2 或 JOptionPane.WARNING_MESSAGE。
  • 3 或 JOptionPane.QUESTION_MESSAGE。

默认情况下,messageType 的值是 JOptionPane.INFORMATION_MESSAGE。除类型 PLAIN_MESSAGE外,每种类型都有相应的图标,也可以通过 icon 参数提供自己的图标。

输入对话框

输入对话框用于接收用户的输入。输入组件可以由文本框、下拉列表或者列表框进行实现。如果没有指定可选值,那么就使用文本框接收输入;如果指定了一组可选值,可选值的个数小于 20,那么将使用下拉列表显示;如果可选值的个数大于或等于 20,那么这些可选值将通过列表框显示。

创建输入对话框的方法如下:

public static String showInputDialog(Component parentComponent,Object message,String title,int messageType)
public static Object showInputDSalog(Component parentComponent,Object message,String title,int messageType,Icon icon,Object[] selectionValue,Object initValue)

其中,第一个 showInputDialog() 方法用于使用文本框输入,第二个 showInputDialog() 方法用于下拉列表或列表框的显示方式。参数 parentComponent 是必需的,message 默认为空,title 默认值为“输入”,messageType 的值默认为 3 或 JOptionPane.QUESTION_MESSAGE。

提示:showInputDialog() 方法中没有 optionType 参数,表示输入对话框的按钮是不可以设置的,通常显示“确定”和“取消”按钮。

选项对话框

选项对话框允许用户自己定制按钮内容。创建选项对话框的方法如下:

public static int showOptionDialog(Component parentComponent,Object message,String title,int optionType,int messageType,icon icon,Object[] options,Object initValue)

其中,使用 options 参数指定按钮,initValue 参数用于指定默认获得焦点的按钮。该方法返回表明激活的按钮的一个整型值。

21 JTable 表格

表格是 Swing 新增加的组件,主要功能是把数据以二维表格的形式显示出来,并且允许用户对表格中的数据进行编辑。表格组件是最复杂的组件之一,它的表格模型功能非常强大、灵活而易于执行。由于篇幅有限,本节只介绍默认的表格模型。

Swing 使用 JTable 类实现表格,常用构造方法如下所示:

  • JTable():构造一个默认的 JTable,使用默认的数据模型、默认的列模型和默认的选择模型对其进行初始化。
  • JTable(int numRows,int numColumns):使用 DefaultTableModel 构造具有 numRows 行和 numColumns 列个空单元格的 JTable。
  • JTable(Object[][] rowData,Object[] columnNames):构造一个 JTable 来显示二 维数组 rowData 中的值,其列名称为 columnNames。
方法名称 说明
getColumnCount() 返回列模型中的列数
getColumnN ame(int column) 返回出现在视图中 column 列位置处的列名称
getRowCount() 返回 JTable 中可以显示的行数(给定无限空间)
getRowSorter() 返回负责排序的对象
getSelectedColumn() 返回第一个选定列的索引,如果没有选定的列, 则返回 -1
getSelectedRow() 返回第一个选定行的索引,如果没有选定的行, 则返回 -1
getValueAt(int row,int column) 返回 row 和 column 位置的单元格值
isEditing() 如果正在编辑单元格,则返回 true
selectAll() 选择表中的所有行、列和单元格
setColumnSelectionInterval(int index0,int index1) 选择从 index0 到 index1之间(包含两端)的列
setRowSelectionInterval(int index0,int index1) 选择从 index0 到 index1 之间(包含两端)的行
setTableHeader(JTableHeader tableHeader) 将此 JTable 所使用的 tableHeader 设置为 newHeader
setUpdateSelectionOnSort(boolean update) 指定排序后是否应该更新选择
setValueAt(Object a Value,int row,int column) 设置表模型中 row 和 column 位置的单元格值

22 JTree 树组件

如果要显示一个层次关系分明的一组数据,用树结构是最合适的。树如同 Windows 资源管理器的左半部,可通过单击文件夹展开或者收缩内容。

Swing 使用 JTree 类实现树,它的主要功能是把数据按照树状进行显示,其数据来源于其他对象。JTree 树中最基本的对象叫作节点,表示在给定层次结构中的数据项。树以垂直方式显示数据,每行显示一个节点。树中只有一个根节点,所有其他节点从这里引出。除根节点外,其他节点分为两类:一类是代子节点的分支节点,另一类是不带子节点的叶节点。

JTree 类的常用构造方法如下:

  • JTree() 返回带有示例模型的 JTree
  • JTree(Object[] value) 返回 JTree,指定数组的每个元素作为不被显示的新根节点的子节点
  • JTree(TreeNode root) 返回 JTree,使用指定的 root 作为其根节点
  • JTree(TreeNode root,boolean aslcsAllowsChildren) 返回 JTree,使用指定的 root 作为其根节点,asksAllowsChildren 用于确定节点是否为叶节点

树节点由 javax.swing.tree 包中的接口 TreeNode 定义,该接口被 DefaultMutableTreeNode 类实现。

为了创建一个树,使用 DefaultMutableTreeNode 类为树创建节点,它的两个常用的构造方法如下。

  1. DefaultMutableTreeNode(Object userObject):创建没有父节点和子节点,但允许有子节点的树节点,并使用指定的用户对象对它进行初始化。
  2. DefaultMutableTreeNode(Object userObject,boolean allowsChildren):创建没有父节点和子节点的树节点,使用指定的用户对象对它进行初始化,仅在指定时才允许有子节点。

23 JTabbedPane 选项卡组件

使用选项卡可以在有限的布局空间内展示更多的内容。Swing 使用 JTabbedPane 类实现选项卡。

JTabbedPane 类创建的选项卡可以通过单击标题或者图标在选项卡之间进行切换。JTabbedPane 类的常用构造方法如下:

  • JTabbedPane():创建一个具有默认 JTabbedPane.TOP 布局的空 TabbedPane。
  • JTabbedPane(int tabPlacement):创建一个空的 TabbedPane,使其具有以下指定选项卡布局中的一种:JTabbedPane.TOP、JTabbedPane.BOTTOM、JTabbedPane.LEFT 或 JTabbedPane.RIGHT。

创建了 JTabbedPane 实例之后,可使用 addTab() 方法和 insertTab() 方法将选项卡/组件添加到 TabbedPane 对象中。选项卡通过对应于添加位置的索引来表示,其中第一个选项卡的索引为 0,最后一个选项卡的索引为选项卡数量减 1。

TabbedPane 使用 SingleSelectionModel 属性来表示选项卡索引集和当前所选择的索引。如果选项卡数量大于 0,则总会有一个被选定的索引,此索引默认被初始化为第一个选项卡;如果选项卡数量为 0,则所选择的索引为 -1。

方法名称 说明
add(Component component,int index) 在指定的选项卡索引位置添加一个 component,默认的选项卡标题为组件名称
addTab(String title, Component component) 添加一个使用 title 作为标题,且没有图标的组件
getComponentAt(int index) 返回 index 位置的组件
getSelectedComponent() 返回此选项卡窗格当前选择的组件
getSelectedIndex() 返回当前选择的此选项卡窗格的索引
getTabCount() 返回此 tabbedPane 的选项卡数
insertTab(String title,Icon icon,Component component,String tip,int index) 在 index 位置插入一个组件,该组件通过 title 或 icon(任意一个都可以为 null)来表示
isEnabledAt(int index) 返回当前是否启用了 index 位置的选项卡
remove(int index) 移除对应于指定索引的选项卡和组件
setEnabledAt(int index,boolean enabled) 设置是否启用 index 位置的选项卡
setMnemonicAt(int tablndex,int mnemonic) 设置用于访问指定选项卡的键盘助记符
setTitleAt(int index,String title) 将 index 位置的标题设置为 title,它可以为 null
setToolTipTextAt(int index,String toolTipText) 将 index 位置的工具提示文本设置为 toolTipText,它可以为 null

选项卡面板和卡片布局不同的是,选项卡面板可以有标签。
image

代码示例

1.测试数据库连接

1.1 pom 依赖

<dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.7.20</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.29</version>
    </dependency>
    <dependency>
      <groupId>com.oracle.database.jdbc</groupId>
      <artifactId>ojdbc8</artifactId>
      <version>21.1.0.0</version>
    </dependency>

1.2 数据库测试表单

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * 数据库测试表单
 */
public class DdlCreaterForm implements ActionListener {

    // 弹出框头
    private String title;

    private JFrame frame;
    private JPanel contentPanel;
    // 数据库类型
    private JComboBox<String> type;
    // 数据库地址
    private JTextField url;
    // 驱动
    private JTextField driver;
    // 用户名
    private JTextField username;
    // 密码
    private JPasswordField password;

    // 【测试】按钮
    private JButton test;
    // 【导出】按钮
    private JButton export;
    // 【关闭】按钮
    private JButton close;

    public DdlCreaterForm(String title) {
        this.title = title;
        this.frame = new JFrame(title);
        this.type = new JComboBox<String>(new String[]{"oracle", "mysql5", "mysql8"});
        this.driver = new JTextField();
        driver.setEnabled(false);
        this.url = new JTextField();
        this.username = new JTextField();
        this.password = new JPasswordField();
        this.test = new JButton("test");
        this.export = new JButton("export");
        this.close = new JButton("close");
        init(frame);
    }

    private void init(JFrame frame) {
        contentPanel = new JPanel(new GridLayout(6, 1));

        contentPanel.add(wrapListField("data_type", type));
        contentPanel.add(wrapField("driver", driver));
        contentPanel.add(wrapField("url", url));
        contentPanel.add(wrapField("username", username));
        contentPanel.add(wrapField("password", password));

        JPanel buttonPenal = new JPanel(new GridLayout(1, 3));
        test.setActionCommand("test");
        test.addActionListener(this);

        export.setActionCommand("export");
        export.addActionListener(this);

        close.setActionCommand("close");
        close.addActionListener(this);

        buttonPenal.add(test);
        buttonPenal.add(export);
        buttonPenal.add(close);
        contentPanel.add(buttonPenal);

        contentPanel.setOpaque(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(contentPanel);
        frame.pack();
        frame.setVisible(true);
    }

    private JPanel wrapField(String lableName, JTextField field) {
        JPanel panel = new JPanel(new GridLayout(1, 2));
        JLabel label = new JLabel(lableName);
        panel.add(label);
        panel.add(field);
        return panel;
    }

    private JPanel wrapListField(String lableName, JComboBox<String> field) {
        JPanel panel = new JPanel(new GridLayout(1, 2));
        JLabel label = new JLabel(lableName);
        field.setActionCommand("DataTypeChange");
        field.addActionListener(this);
        panel.add(label);
        panel.add(field);
        return panel;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println(e.getActionCommand());
        if ("close".equals(e.getActionCommand())) {
            // 【关闭】按钮
            this.frame.dispose();
            this.frame.removeAll();
            System.exit(0);
        }

        if ("test".equals(e.getActionCommand())) {
            // 【测试】按钮
            DataSource dataSource = DataSource.getInstance();
            dataSource.setType(type.getSelectedItem().toString());
            dataSource.setDriver(driver.getText());
            dataSource.setUrl(url.getText());
            dataSource.setUsername(username.getText());
            dataSource.setPassword(password.getText());
            Boolean result = DbUtil.test(dataSource, "select 1 from order_info");
            if (result) {
                System.out.println("test connect success!");
                JOptionPane.showMessageDialog(this.frame, "数据库连接成功!", "测试连接", JOptionPane.INFORMATION_MESSAGE);
            } else {
                JOptionPane.showMessageDialog(this.frame, "数据库无法连接!", "测试连接", JOptionPane.ERROR_MESSAGE);
            }
        }
        if ("DataTypeChange".equals(e.getActionCommand())) {
            // 【数据库类型】下拉框
            String typeSelect = type.getSelectedItem().toString();
            if ("oracle".equals(typeSelect)) {
                driver.setText("oracle.jdbc.OracleDriver");
            } else if ("mysql8".equals(typeSelect)) {
                driver.setText("com.mysql.cj.jdbc.Driver");
            } else if ("mysql5".equals(typeSelect)) {
                driver.setText("com.mysql.jdbc.Driver");
            }
        }
    }
}

1.3 数据库工具类


/**
 * 数据源
 */
public class DataSource {

    private static DataSource dataSource;

    private String type;

    private String url;

    private String driver;

    private String username;

    private String password;

    private DataSource() {

    }

    public static DataSource getInstance() {
        if (dataSource == null) {
            dataSource = new DataSource();
        }
        return dataSource;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}


import java.sql.*;

/**
 * 数据库工具类
 */
public class DbUtil {

    public static Boolean test(DataSource dataSource, String sql) {
        Boolean result = Boolean.FALSE;
        try {
            Class.forName(dataSource.getDriver());
            Connection connection = DriverManager.getConnection(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
            if(connection.isValid(0)){
                result = Boolean.TRUE;
            }connection.close();
        } catch (SQLException | ClassNotFoundException throwables) {
            throwables.printStackTrace();
        }
        return result;
    }
}

1.4 测试


/**
 * 数据库测试
 */
public class DdlCreater {

    public static void main(String[] args) {
        DdlCreaterForm from = new DdlCreaterForm("ddl 生成");
    }
}

image

image

image

image

2.读取excel表字段生成实体类内容

2.1 pom 依赖

<dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.7.20</version>
    </dependency>
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>5.0.0</version>
    </dependency>

2.2 excel内容

image

2.3 excel解析器


import cn.hutool.poi.excel.ExcelUtil;

import java.io.File;
import java.util.List;

/**
 * Excel 解析器(读取 excel 中表结构,生成实体类内容)
 */
public class ExcelParser {

    private File excelFile;

    public ExcelParser(File excelFile) {
        this.excelFile = excelFile;
    }

    public String parse() {
        StringBuilder content = new StringBuilder();
        List<List<Object>> rows = ExcelUtil.getReader(excelFile, "Sheet1").read(1);
        content.append("{\n");
        for (int i = 0; i < rows.size(); i++) {
            List<Object> columns = rows.get(i);
            content.append("\t// ");
            content.append(columns.get(1));
            content.append("\n");
            content.append("\tprivate ");
            content.append(type(String.valueOf(columns.get(2)), String.valueOf(columns.get(3))));
            content.append(" ");
            content.append(columns.get(0));
            content.append(";\n");
        }
        content.append("}");
        return content.toString();
    }

    private String type(String type, String scale) {
        if ("C".equals(type)) {
            return "String";
        } else if ("N".equals(type)) {
            if (scale.contains(",") || scale.contains(",")) {
                return "Double";
            }
            return "Integer";
        }

        return "";
    }
}

2.4 实体类生成表单


import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

/**
 * 实体类生成器表单
 */
public class EntityCreatorForm implements ActionListener {
    // 弹出框头
    private String title;
    private JFrame frame;
    private JPanel contentPanel;

    // excel 文件选择器
    private JButton openButton;
    private JPanel fileChooserPanel;
    private JFileChooser fileChooser;
    private JTextField chooseFilePath;

    //  文件保存位置
    private JTextField destPath;
    private JButton destSelectButton;
    private JPanel destPathChooserPanel;
    private JFileChooser destPathChooser;

    // 【生成】按钮
    private JButton create;
    // 【关闭】按钮
    private JButton close;

    public EntityCreatorForm(String title) {
        this.title = title;
        this.frame = new JFrame(title);
        this.fileChooser = new JFileChooser();
        this.chooseFilePath = new JTextField();
        this.destPath = new JTextField();
        this.create = new JButton("create");
        this.close = new JButton("close");
        this.openButton = new JButton("open");
        this.destPathChooser = new JFileChooser();
        this.destSelectButton = new JButton("destSelect");
        init(frame);
    }

    private void init(JFrame frame) {
        contentPanel = new JPanel(new GridLayout(3, 1));
        // 文件选择器
        openButton.addActionListener(this);
        openButton.setActionCommand("openFile");
        fileChooserPanel = wrapFileChooser("选择 excel", chooseFilePath, openButton);
        contentPanel.add(fileChooserPanel);
        // 保存文件
        destSelectButton.setActionCommand("destPath");
        destSelectButton.addActionListener(this);
        destPathChooserPanel = wrapFileChooser("保存路径", destPath, destSelectButton);
        contentPanel.add(destPathChooserPanel);

        // 按钮
        JPanel buttonPenal = new JPanel(new GridLayout(1, 4));
        create.setActionCommand("create");
        create.addActionListener(this);
        close.setActionCommand("close");
        close.addActionListener(this);
        buttonPenal.add(create);
        buttonPenal.add(close);

        contentPanel.add(buttonPenal);
        contentPanel.setOpaque(true);
        // 设置关闭操作
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 设置 content panel
        frame.setContentPane(contentPanel);
        // 自适应窗口大小
        frame.pack();
        // 设置 frame 可见
        frame.setVisible(true);

    }

    private JPanel wrapField(String lableName, JTextField field) {
        JPanel panel = new JPanel(new GridLayout(1, 2));
        JLabel label = new JLabel(lableName);
        panel.add(label);
        panel.add(field);
        return panel;
    }

    private JPanel wrapFileChooser(String lableName, JTextField chooseFilePath, JButton button) {
        JPanel panel = new JPanel(new GridLayout(1, 2));
        JLabel label = new JLabel(lableName);
        chooseFilePath.setEnabled(false);
        JPanel filePathPanel = new JPanel(new GridLayout(1, 2));
        filePathPanel.add(chooseFilePath);
        filePathPanel.add(button);
        panel.add(label);
        panel.add(filePathPanel);
        return panel;
    }

    private JPanel wrapButton(String lableName, JButton button) {
        JPanel panel = new JPanel(new GridLayout(1, 2));
        JLabel label = new JLabel(lableName);
        panel.add(label);
        panel.add(button);
        return panel;
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        if ("openFile".equals(e.getActionCommand())) {
            // 打开文件
            int returnVal = fileChooser.showOpenDialog(fileChooserPanel);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                File selectedFile = fileChooser.getSelectedFile();
                chooseFilePath.setText(selectedFile.getAbsolutePath());
                System.out.println("选择的文件是:" + selectedFile.getAbsolutePath());
            }
        }


        if ("destPath".equals(e.getActionCommand())) {
            // 打开文件
            destPathChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            int returnVal = destPathChooser.showOpenDialog(destPathChooserPanel);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                File selectedFile = destPathChooser.getSelectedFile();
                destPath.setText(selectedFile.getAbsolutePath());
                System.out.println("选择的文件是:" + selectedFile.getAbsolutePath());
            }
        }

        if ("close".equals(e.getActionCommand())) {
            // 【关闭】按钮
            this.frame.dispose();
            this.frame.removeAll();
            System.exit(0);
        }

        if ("create".equals(e.getActionCommand())) {
            // 【生成】按钮
            ExcelParser parser = new ExcelParser(fileChooser.getSelectedFile());
            JOptionPane.showMessageDialog(frame,parser.parse());
        }
    }
}


2.5 测试


/**
 * 实体类生成器
 */
public class EntityCreator {

    public static void main(String[] args) {
        EntityCreatorForm form = new EntityCreatorForm("生成实体类");
    }
}

image
image
image

image

弹出:
image
点击【确定】按钮,关闭弹窗。

posted on 2022-11-22 01:27  不安分的黑娃  阅读(293)  评论(0编辑  收藏  举报