从学习 C 语言编程开始,到学习数据结构与算法,到学习 Java SE 基础,所编写的程序都是在所谓的“控制台”中运行的。也就是那个简陋的、枯燥的、毫无美感可言的命令行窗口执行的。
可是,现在大家广泛使用的各种实用软件,无论是在台式机上运行的,或者在平板电脑上运行的,甚至在手机上运行的,都是绚丽多彩、富有立体感和极为友好的图形界面。那么 Java 能编写出这样界面的应用程序么?毫无疑问 Java 是可以的。
这里给出简单的代码,先让大伙了解一下:
public class MyFirstWindow {
private JFrame jframeMain;
public MyFirstWindow() {
//初始化一个窗口对象;
//设置窗口的标题为“MyFirstWindow”
jframeMain = new JFrame("MyFirstWindow");
//设置窗口的大小为 1200 * 800,单位是像素;
jframeMain.setSize(1200,800);
//设置窗口位置:left 为 600 像素,top 为 300 像素;
jframeMain.setLocation(600,300);
}
/**
* 显示这个窗口,并启动窗口线程;
*/
public void showWindow() {
jframeMain.setVisible(true);
}
}
给出测试类:
public class Test {
public static void main(String[] args) {
new MyFirstWindow().showWindow();
}
}
运行,显示如下:
JFrame 类称为框架类,是一个窗口的框架。别看这个简单的框架,它拥有 windows 窗口所有性质和一般性操作,比如:最大化、最小化、可移动、可缩放、可关闭等操作。
GUI,即图形用户界面,是用户与程序交互的主要方式之一。Java提供了一组GUI工具包,可以帮助开发者创建美观、易于使用的应用程序。GUI(图形用户界面)编程是开发一个应用程序的重要组成部分。它影响了用户与软件的交互方式,使人们能够通过直观的图形界面与程序进行操作。Java 作为一门广泛应用于各领域的编程语言,其 GUI 编程能力也非常强大。
下面,我将详细整理 Java GUI 编程的基本概念、组件、布局管理器以及事件处理等方面的知识。
Java 提供了丰富的 GUI 组件库,用于创建各种图形用户界面。Java 开发 GUI 的主要框架是 AWT(Abstract Window Toolkit)和 Swing。Swing 是基于 AWT 构建的,因此 Swing 组件也可以与 AWT 组件兼容。AWT 代表抽象窗口工具包,是Java最早的 GUI 工具包。Swing 是 AWT 的改进版,提供了更多的组件和更好的外观。这两个工具包都包含一组组件,可以用于构建 GUI 应用程序。
Java GUI 编程的核心是事件处理。事件是用户与程序之间的交互,例如单击按钮或选择复选框。Java 提供了事件模型,开发者可以使用它来处理事件。事件模型由事件源、事件对象、事件监听器和事件处理器组成。事件源是发出事件的组件,事件对象是事件的描述,事件监听器是负责处理事件的对象,事件处理器是实际处理事件的方法。
Java GUI 编程需要开发者熟悉一些基本概念,例如布局管理器、组件和容器。布局管理器用于控制组件在容器中的位置和大小。Java 提供了多个布局管理器,包括边界布局、流布局和网格布局。组件是 GUI 的基本构建块,例如按钮、标签和文本框。容器是包含组件的对象,例如面板和对话框。
AWT 是 Java 中最早的 GUI 工具包,它提供了一组基础的 GUI 组件和窗口管理器,可以用于创建简单的 GUI 应用程序。以下是 AWT 工具包的一些常用组件和用法:
public class MyFrame extends Frame {
public MyFrame() {
super("My Frame");
setSize(400, 300);
setVisible(true);
}
public static void main(String[] args) {
new MyFrame();
}
}
public class MyPanel extends Frame {
public MyPanel() {
super("My Panel");
setSize(400, 300);
Panel panel = new Panel();
panel.setBackground(Color.RED);
add(panel);
setVisible(true);
}
public static void main(String[] args) {
new MyPanel();
}
}
public class MyButton extends Frame implements ActionListener {
public MyButton() {
super("My Button");
setSize(400, 300);
Button button = new Button("Click me");
button.addActionListener(this);
add(button);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
System.out.println("Button clicked");
}
public static void main(String[] args) {
new MyButton();
}
}
public class MyLabel extends Frame {
public MyLabel() {
super("My Label");
setSize(400, 300);
Label label = new Label("Hello, World!");
add(label);
setVisible(true);
}
public static void main(String[] args) {
new MyLabel();
}
}
public class MyTextField extends Frame implements ActionListener {
private TextField textField;
public MyTextField() {
super("My TextField");
setSize(400, 300);
textField = new TextField();
textField.addActionListener(this);
add(textField);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
System.out.println("Text entered: " + textField.getText());
textField.setText("");
}
public static void main(String[] args) {
new MyTextField();
}
}
以上是 AWT 工具包中的一些常用组件和用法。虽然 AWT 工具包已经被更先进的 Swing 和 JavaFX 工具包所取代,但是了解和掌握 AWT 工具包仍然有助于理解 Java GUI 编程的基本原理和概念。
Swing 是 Java 的一个扩展包,包含了丰富的 GUI 组件,用于创建图形用户界面。Swing 组件以 “J” 开头,例如 JFrame
、JButton
等。与 AWT 相比,Swing 组件更加轻量级,具有更好的可定制性、可移植性和可扩展性。
要使用 Swing 组件,需要导入以下包:
import javax.swing.*;
我们从创建一个简单的 Swing 窗口开始。以下是一个创建空白窗口的示例代码:
public class SimpleSwingWindow {
public static void main(String[] args) {
// 创建一个 JFrame 实例
JFrame frame = new JFrame("My Simple Swing Window");
// 设置窗口关闭时的操作
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 设置窗口的大小
frame.setSize(400, 300);
// 设置窗口可见
frame.setVisible(true);
}
}
在上述代码中,我们首先创建了一个 JFrame
实例,并设置了窗口标题。然后,通过 setDefaultCloseOperation()
方法设置了关闭窗口时的操作,接下来设置了窗口的大小,最后,将窗口设置为可见。
Swing 组件是构建 GUI 应用程序的基石。Swing 提供了丰富的组件,如按钮、文本框、标签等。
JButton
是一个标准的按钮组件,用户可以点击它来触发某种操作。下面是一个创建按钮的示例:
JButton button = new JButton("Click me!");
JLabel
是一个用于显示文本、图像或两者的组件。下面是一个创建文本标签的示例:
JLabel label = new JLabel("Hello, Swing!");
JTextField
是一个允许用户输入单行文本的组件。下面是一个创建文本框的示例:
JTextField textField = new JTextField(20);
JTextArea
是一个允许用户输入多行文本的组件。下面是一个创建文本区域的示例:
JTextArea textArea = new JTextArea(5, 20);
JCheckBox
是一个允许用户通过选中或取消选中来表示二进制选择的组件。下面是一个创建复选框的示例:
JCheckBox checkBox = new JCheckBox("Check me!");
JRadioButton
与 JCheckBox
类似,但一组单选按钮中只能选择一个。要将一组单选按钮关联在一起,需要使用 ButtonGroup
。下面是一个创建单选按钮的示例:
JRadioButton radioButton1 = new JRadioButton("Option 1");
JRadioButton radioButton2 = new JRadioButton("Option 2");
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(radioButton1);
buttonGroup.add(radioButton2);
JComboBox
是一个允许用户从列表中选择一个选项的组件。下面是一个创建下拉列表的示例:
String[] options = {"Option 1", "Option 2", "Option 3"};
JComboBox<String> comboBox = new JComboBox<>(options);
以上只是 Swing 组件库中的一部分组件,还有很多其他组件可供开发者使用。
布局管理器(Layout Manager)负责管理组件在容器中的位置和大小。Swing 提供了多种布局管理器,如 BorderLayout
、FlowLayout
、GridLayout
和GridBagLayout
等。
BorderLayout
将容器划分为五个区域:NORTH
、SOUTH
、EAST
、WEST
和 CENTER
。每个区域只能放置一个组件。以下是一个使用 BorderLayout
的示例:
JFrame frame = new JFrame("BorderLayout Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setLayout(new BorderLayout());
frame.add(new JButton("North"), BorderLayout.NORTH);
frame.add(new JButton("South"), BorderLayout.SOUTH);
frame.add(new JButton("East"), BorderLayout.EAST);
frame.add(new JButton("West"), BorderLayout.WEST);
frame.add(new JButton("Center"), BorderLayout.CENTER);
frame.setVisible(true);
FlowLayout
是最简单的布局管理器,它将组件按照添加顺序从左到右、从上到下排列。以下是一个使用 FlowLayout
的示例:
JFrame frame = new JFrame("FlowLayout Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setLayout(new FlowLayout());
frame.add(new JButton("Button 1"));
frame.add(new JButton("Button 2"));
frame.add(new JButton("Button 3"));
frame.setVisible(true);
GridLayout
将容器划分为指定数量的行和列,组件按照添加顺序从左到右、从上到下填充单元格。以下是一个使用 GridLayout
的示例:
JFrame frame = new JFrame("GridLayout Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setLayout(new GridLayout(3, 2));
frame.add(new JButton("Button 1"));
frame.add(new JButton("Button 2"));
frame.add(new JButton("Button 3"));
frame.add(new JButton("Button 4"));
frame.add(new JButton("Button 5"));
frame.add(new JButton("Button 6"));
frame.setVisible(true);
GridBagLayout
是最灵活的布局管理器,可以以任何方式布置组件。
事件处理是 GUI 编程的核心。在 Java 中,事件处理使用监听器(Listener)实现。监听器是一个实现了特定接口的对象,用于监听组件的事件。当事件发生时,监听器将执行相应的操作。
Java 提供了许多事件类型,如 ActionEvent
、MouseEvent
和 KeyEvent
。我们可以使用事件监听器来处理这些事件。
ActionEvent
ActionEvent
是 Swing 中的一个重要事件,可以用于响应用户的操作事件,例如按钮点击、菜单选择等。以下是一些常用的ActionEvent
处理方法:
ActionListener
监听器可以通过添加 ActionListener 监听器来监听用户的操作事件,例如按钮点击事件。以下是示例代码:
JButton button = new JButton("Click me");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 处理按钮点击事件
}
});
可以使用 ActionEvent 的 getSource()
方法获取事件源,例如按钮组件。以下是示例代码:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == button) {
// 处理按钮点击事件
}
}
});
可以使用 ActionEvent 的getActionCommand()
方法获取事件命令,例如按钮上显示的文本。以下是示例代码:
JButton button1 = new JButton("OK");
button1.setActionCommand("OK");
JButton button2 = new JButton("Cancel");
button2.setActionCommand("Cancel");
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("OK")) {
// 处理OK按钮点击事件
} else if (command.equals("Cancel")) {
// 处理Cancel按钮点击事件
}
}
});
可以使用 JButton 的doClick()
方法手动触发按钮点击事件。以下是示例代码:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 处理按钮点击事件
}
});
// 手动触发按钮点击事件
button.doClick();
这里给出一个使用 ActionEvent 的示例程序,它创建一个窗口和一个按钮,并在单击按钮时显示一个对话框:
public class ActionEventExample {
public static void main(String[] args) {
JFrame frame = new JFrame("ActionEvent Example");
JPanel panel = new JPanel();
JButton button = new JButton("Click me!");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frame, "Hello, world!");
}
});
panel.add(button);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
在这个示例程序中,我们创建了一个 JFrame 对象和一个 JPanel 对象。我们创建了一个 JButton 对象,将其添加到面板中,并添加一个 ActionListener 对象。当用户单击按钮时,ActionListener 对象的 actionPerformed()
方法将被调用,并显示一个对话框,显示消息“Hello, world!”。
以上是一些常用的 ActionEvent 处理方法,可以根据实际需要选择合适的方法来处理用户的操作事件。
MouseEvent
MouseEvent 是 Swing 中的一个重要事件,可以用于响应鼠标事件,例如鼠标点击、移动、拖拽等。以下是一些常用的MouseEvent处理方法:
添加MouseListener
监听器
可以通过添加 MouseListener 监听器来监听鼠标事件,例如鼠标单击事件。以下是示例代码:
JButton button = new JButton("Click me");
button.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
// 处理鼠标单击事件
}
});
鼠标单击事件
鼠标单击事件在鼠标按下并释放后触发,可以使用 MouseEvent 的getClickCount()
方法获取点击次数。以下是示例代码:
button.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int clicks = e.getClickCount();
if (clicks == 1) {
// 处理单击事件
} else if (clicks == 2) {
// 处理双击事件
}
}
});
鼠标移动事件
鼠标移动事件在鼠标移动时触发,可以使用 MouseEvent 的getX()
和getY()
方法获取鼠标当前位置。以下是示例代码:
button.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
int x = e.getX();
int y = e.getY();
// 处理鼠标移动事件
}
});
鼠标拖拽事件
鼠标拖拽事件在鼠标按下并移动时触发,可以使用MouseEvent
的 getX()
和getY()
方法获取鼠标当前位置,也可以使用 MouseEvent
的getPoint()
方法获取鼠标当前位置的坐标。以下是示例代码:
button.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
// 记录鼠标按下时的位置
startX = e.getX();
startY = e.getY();
}
});
button.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
int endX = e.getX();
int endY = e.getY();
// 计算鼠标移动距离
int dx = endX - startX;
int dy = endY - startY;
// 更新组件位置
button.setLocation(button.getX() + dx, button.getY() + dy);
// 更新鼠标按下时的位置
startX = endX;
startY = endY;
}
});
以上是一些常用的MouseEvent
处理方法,可以根据实际需要选择合适的方法来处理鼠标事件。同时,还可以通过其他MouseEvent
方法获取更多鼠标事件相关信息,例如鼠标按钮、鼠标滚轮等。
KeyEvent
KeyEvent 是 Swing 中的一个重要事件,可以用于响应键盘事件,例如按键、释放、敲击等。以下是一些常用的KeyEvent 处理方法:
添加KeyListener监听器
可以通过添加KeyListener监听器来监听键盘事件,例如按键事件。以下是示例代码:
JTextField textField = new JTextField();
textField.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
// 处理按键事件
}
});
获取键码
可以使用 KeyEvent 的getKeyCode()
方法获取键码,例如按下的是哪个键。以下是示例代码:
textField.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_ENTER) {
// 处理回车键按下事件
}
}
});
获取字符
可以使用 KeyEvent 的getKeyChar()
方法获取字符,例如按下的是哪个字符。以下是示例代码:
textField.addKeyListener(new KeyAdapter() {
public void keyTyped(KeyEvent e) {
char c = e.getKeyChar();
if (c == 'a') {
// 处理按下a键事件
}
}
});
触发事件
可以使用 JTextField 的setText()
方法手动触发文本框内容的改变事件。以下是示例代码:
textField.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent e) {
// 处理键释放事件
}
});
// 手动触发文本框内容的改变事件
textField.setText(textField.getText());
以上是一些常用的 KeyEvent 处理方法,可以根据实际需要选择合适的方法来处理键盘事件。同时,还可以通过其他 KeyEvent 方法获取更多事件相关信息,例如事件时间、按键状态等。
在Java 8及以后版本中,可以使用Lambda表达式来简化事件监听器的代码。例如,上面的代码可以改写为:
button.addActionListener(e -> {
// 处理按钮点击事件
});
EventQueue.invokeLater
更新GUI界面在 Swing 中,所有的GUI操作都必须在事件调度线程(Event Dispatch Thread)中执行。如果需要在其他线程中更新 GUI界面,可以使用EventQueue.invokeLater()
方法,将更新操作加入事件队列中,在事件调度线程中执行。以下是一个使用EventQueue.invokeLater()
的示例代码:
EventQueue.invokeLater(new Runnable() {
public void run() {
// 在事件调度线程中执行更新操作
}
});
在 GUI 编程中,长时间运行的任务会阻塞 GUI 线程,导致 GUI 不响应。因此,我们需要使用多线程来避免这种情况。
下面是一个使用 SwingWorker 的示例程序,它创建一个窗口和一个按钮,并在单击按钮时使用 SwingWorker 来执行长时间运行的任务:
public class SwingWorkerExample {
public static void main(String[] args) {
JFrame frame = new JFrame("SwingWorker示例");
JPanel panel = new JPanel();
JButton button = new JButton("Click me!");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new SwingWorker<Void, Integer>() {
@Override
protected Void doInBackground() throws Exception {
for (int i = 0; i < 100; i++) {
Thread.sleep(100);
publish(i);
}
return null;
}
@Override
protected void process(List<Integer> chunks) {
for (int i : chunks) {
System.out.println(i);
}
}
}.execute();
}
});
panel.add(button);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
在这个示例程序中,我们创建了一个 JFrame 对象和一个 JPanel 对象。我们创建了一个 JButton 对象,并添加一个 ActionListener 对象。当用户单击按钮时,我们创建了一个 SwingWorker 对象,并使用 doInBackground() 方法执行长时间运行的任务。在这个示例程序中,我们只是休眠100毫秒,并迭代100次,然后使用publish()
方法发布进度值。 SwingWorker 对象还有一个process()
方法,可以在 GUI 线程中更新进度。在这个示例程序中,我们使用process()
方法输出进度值。
我们可以使用 Java 提供的组件来构建 GUI,如 JButton、JLabel 和 JTextField 。但是,有时候我们需要创建自定义组件来满足特定的需求。
下面是一个使用 JComponent 的示例程序,它创建了一个自定义的组件,显示一个红色的矩形:
public class CustomComponentExample {
public static void main(String[] args) {
JFrame frame = new JFrame("自定义组件示例");
JPanel panel = new JPanel();
MyComponent component = new MyComponent();
panel.add(component);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
static class MyComponent extends JComponent {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(50, 50, 100, 100);
}
}
}
在这个示例程序中,我们创建了一个 JFrame 对象和一个 JPanel 对象。我们创建了一个自定义组件 MyComponent,并将其添加到面板中。我们重写了 MyComponent 的 paintComponent()
方法,以绘制一个红色的矩形。最后,我们将面板添加到窗口中,并将窗口设置为可见。
JavaFX 是 Java 的第三个 GUI 工具包,它是为 Java SE 8及更高版本开发的。JavaFX 提供了许多现代化的 GUI 组件,如 TableView、TreeTableView、TreeView 等。JavaFX 还支持 CSS 样式表和 FXML 文件,使 GUI 设计更加灵活,它用于构建丰富、交互式的图形用户界面和媒体应用程序。相对于 Swing,JavaFX 提供了更现代化的 UI 设计、更好的性能、更丰富的媒体支持和更容易的可视化效果。
以下是一些 JavaFX GUI编程中常用的类和组件:
Stage是JavaFX中的顶级容器,表示应用程序的主窗口。可以使用Stage类创建和管理应用程序的主窗口,例如设置标题、大小、位置、图标等。
Scene是JavaFX中的容器,表示应用程序的一个场景或一个视图。可以在Scene中添加和管理应用程序的UI组件,例如按钮、标签、文本框等。
JavaFX提供了多种布局管理器来帮助开发者设计和管理UI界面的布局。例如,HBox和VBox可以用于水平和垂直布局,BorderPane可以用于边框式布局,GridPane可以用于网格布局等。
JavaFX提供了多种UI控件,例如按钮、标签、文本框、下拉框、列表框、滑块等,可以用于构建应用程序的用户界面。
JavaFX提供了多种UI效果,例如阴影、模糊、颜色调整等,可以用于改善应用程序的视觉效果。
JavaFX提供了多种媒体支持,例如音频、视频、动画等,可以用于创建交互式的媒体应用程序。
下面是一个简单的 JavaFX 示例程序,它创建一个窗口和一个按钮:
public class JavaFXExample extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) {
Button button = new Button("Click me!");
button.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("Button clicked!");
}
});
VBox layout = new VBox(button);
Scene scene = new Scene(layout);
stage.setScene(scene);
stage.setTitle("JavaFX Example");
stage.show();
}
}
在这个示例程序中,我们创建了一个 Stage 对象,将其命名为“JavaFX Example”,并创建了一个 Button 对象,将其命名为“Click me!”
我们将一个 EventHandler 对象添加到按钮上,以便在单击按钮时执行某些操作(在这种情况下,我们只是打印一条消息)。我们创建了一个 VBox 布局,将按钮添加到其中,并创建了一个 Scene 对象,将布局添加到其中。最后,我们将场景设置为窗口的场景,并将窗口设置为可见。