55、高级 GUI 应用程序开发全解析

高级 GUI 应用程序开发全解析

1. 更改 GUI 外观与感觉

在 Java 中,我们可以通过代码来更改 GUI 应用程序的外观和感觉。以下是将外观和感觉更改为 Motif 风格的代码示例:

try
{
    UIManager.setLookAndFeel(
         "com.sun.java.swing.plaf.motif.MotifLookAndFeel");
    SwingUtilities.updateComponentTreeUI(this);
}
catch (Exception e)
{
    JOptionPane.showMessageDialog(null, "Error setting " +
                                      "the look and feel.");
    System.exit(0);
}

若要将外观和感觉更改为 Windows 风格,代码如下:

try
{
    UIManager.setLookAndFeel(
         "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
    SwingUtilities.updateComponentTreeUI(this);
}
catch (Exception e)
{
    JOptionPane.showMessageDialog(null, "Error setting " +
                                      "the look and feel.");
    System.exit(0);
}

操作步骤:
1. 使用 UIManager.setLookAndFeel 方法设置所需的外观和感觉类名。
2. 调用 SwingUtilities.updateComponentTreeUI 方法更新组件树的 UI。
3. 捕获可能出现的异常,并在出现错误时显示消息框并退出程序。

2. 常见错误避免

在开发 GUI 应用程序时,有许多常见错误需要避免,以下是详细介绍:
- 列表组件多选问题 :当列表组件中选择了多个项目时, getSelectedValue 方法仅返回第一个选中的项目, getSelectedIndex 方法仅返回第一个选中项目的索引。应使用 getSelectedValues getSelectedIndices 方法。
- 索引起始问题 :列表或组合框的索引从 0 开始,而不是 1。
- 滚动面板问题 JList JTextArea 组件不会自动显示滚动条,必须将这些组件添加到滚动面板对象中才能显示滚动条。并且要使用 JScrollPane 构造函数添加组件,而不是 add 方法。如果将组件添加到滚动面板后,要将其添加到另一个容器(如面板),应添加滚动面板而不是组件,否则滚动条不会显示。
- 组合框可编辑问题 :默认情况下,组合框是按钮和列表的组合。要使其成为文本字段和列表的组合,必须调用 setEditable 方法并传入 true 作为参数。
- 图像文件类型问题 :目前, ImageIcon 对象可以打开 JPEG、GIF 或 PNG 格式的图像文件。
- JLabel 图像加载问题 :如果没有显式设置 JLabel 组件的首选大小,当加载图像时它会自动调整大小,但包含该 JLabel JFrame 不会自动调整大小,必须调用 JFrame 对象的 pack 方法或 setPreferredSize 方法来调整大小。
- 助记符问题 :如果为窗口中的多个组件分配相同的助记符,它仅对第一个分配的组件有效。
- 菜单组件添加问题 :创建菜单项后,必须将其添加到 JMenu 组件中才能在菜单上显示; JMenu 组件必须添加到 JMenuBar 组件中才能在菜单栏上显示。并且要调用 JFrame 对象的 setJMenuBar 方法来放置菜单栏。
- 单选按钮菜单项分组问题 :与常规单选按钮组件一样,必须将单选按钮菜单项分组在一个按钮组中,以创建它们之间的互斥关系。

3. 复习问题与练习
3.1 选择题与判断题
题目 选项 答案
可以使用此方法使文本字段只读。 a. setReadOnly
b. setChangeable
c. setUneditable
d. setEditable
d
ListSelectionModel 类提供的以下哪些常量用作 setSelectionMode 方法的参数? a. ListSelectionModel.SINGLE_SELECTION
b. ListSelectionModel.SINGLE_INTERVAL_SELECTION
c. ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
d. all of the above
d
要为 JList 组件显示滚动条,必须 _ ___。 a. 不做任何操作;如果需要, JList 会自动显示滚动条
b. 将 JList 组件添加到 JScrollPane 组件中
c. 调用 setScrollBar 方法
d. 以上都不是;不能为 JList 组件显示滚动条
b
这是 JList 组件的默认选择模式。 a. 单选
b. 单间隔选择
c. 多选
d. 多间隔选择
d
在 Java 中, _ ____ 类创建滚动面板对象。 a. JScrollPane
b. JPanel
c. JCombobox
d. Jframe
a
ListSelectionListener 接口在这个包中。 a. java.awt
b. java.awt.event
c. javax.swing.event
d. javax.event
c
如果列表中没有选择任何项目,此 JList 方法返回 -1。 a. getSelectedValue
b. getSelectedItem
c. getSelectedIndex
d. getSelection
c
这种 _ ____ 组合框将按钮与列表组合在一起,只允许用户从其列表中选择项目。 a. 不可编辑
b. 可编辑
c. JCombobox
d. list
a
如果要在标签中显示图像,可以将此类的实例传递给 JLabel 构造函数。 a. ImageFile
b. ImageIcon
c. JLabelImage
d. JImageFile
b
用于向组件添加工具提示。 a. the setToolTipText method
b. the addToolTipText method
c. the toolTipText method
d. the appendToolTipText method
a
当用户将鼠标光标悬停在组件上时,会在一个小框中显示的文本。 a. 助记符
b. 即时消息
c. 工具提示
d. 弹出助记符
c
这是一个键,就像用户用鼠标单击一样激活组件。 a. 助记符
b. 键激活器
c. 工具提示
d. 点击模拟器
a
要显示打开文件或保存文件对话框,使用此类。 a. JFileChooser
b. JOpenSaveDialog
c. JFileDialog
d. JFileOptionPane
a
要显示允许用户选择颜色的对话框,使用此类。 a. JColor
b. JColorDialog
c. JColorChooser
d. JColorOptionPane
c
此方法强制 JFrame 自动调整大小。 a. pack
b. setIcon
c. setText
d. setIntervals
a
使用此类创建单选按钮菜单项。 a. JMenuItem
b. JRadioButton
c. JRadioButtonItem
d. JRadioButtonMenuItem
d
setMnemonic 方法(为组件分配助记符)继承自 _ ______ 类。 a. AbstractButton
b. ImageIcon
c. JPanel
d. JLabel
a
setPreferredSize 方法接受此作为其参数。 a. 一个 Size 对象
b. 两个 int
c. 一个 Dimension 对象
d. 一个 int
c
此类的组件是多行文本字段。 a. JMultiLineTextField
b. JTextArea
c. JTextField
d. JEditField
b
这是用于在菜单中分隔项目组的水平条。它是用户无法选择的视觉辅助工具。 a. 分隔条
b. 子菜单
c. 菜单栏
d. 复选框菜单项
a
此方法设置 JSlider 组件上显示主要刻度标记的间隔。 a. setMajorTickSpacing
b. setMajorTickIntervals
c. setTickSpacing
d. setIntervals
a
判断题:列表或组合框的索引必须从 1 开始。 True/False False
判断题: JList 组件会自动显示围绕它绘制的线条边框。 True/False False
判断题:在单间隔选择模式下,用户可以从 JList 组件中选择多个项目。 True/False True
判断题:使用可编辑组合框,用户只能输入出现在组件列表中的值。 True/False False
判断题:可以在 JLabel 对象中存储文本或图像,但不能同时存储两者。 True/False False
判断题:可以在 JLabel 组件中存储大图像和小图像。 True/False True
判断题:助记符对擅长使用键盘的用户很有用。 True/False True
判断题: JMenuBar 对象充当 JMenu 组件的容器。 True/False True
判断题: JMenu 对象不能包含其他 JMenu 对象。 True/False False
判断题: JTextArea 组件不会自动显示滚动条。 True/False True
判断题:默认情况下, JTextArea 组件不执行换行。 True/False True
判断题:当滑块旋钮移动时, JSlider 组件会生成动作事件。 True/False True
判断题:默认情况下, JSlider 组件显示标签和刻度标记。 True/False False
判断题:当在 JSlider 组件上显示标签时,它们显示在主要刻度标记上。 True/False True
3.2 查找错误

以下是一些代码示例及其错误分析:

// Create an editable combo box
String[] names = { "Bill", "Geri", "Greg", "Jean",
"Kirk", "Phillip", "Susan" };
JComboBox nameBox = new JComboBox(names);
nameBox.setEditable(false);

错误:要创建可编辑组合框,应将 setEditable 方法的参数设置为 true ,而不是 false

// Create a black 1-pixel border around list, a JList component.
list.setBorder(Color.BLACK, 1);

错误: setBorder 方法的使用不正确,应使用 BorderFactory 来创建边框。

// Create a JList and add it to a scroll pane.
// Assume that array already exists.
JList list = new JList(array);
JScrollPane scrollPane = new JScrollPane();
scrollPane.add(list);

错误:应使用 JScrollPane 构造函数添加组件,而不是 add 方法。

// Assume that nameBox is a combo box and is properly set up
// with a list of names to choose from.
// Get value of the selected item.
String selectedName = nameBox.getSelectedIndex();

错误: getSelectedIndex 方法返回的是索引,而不是选中项目的值,应使用 getSelectedItem 方法。

JLabel label = new JLabel("Have a nice day!");
label.setImage(image);

错误: JLabel 没有 setImage 方法,应使用 setIcon 方法。

// Add a menu to the menu bar.
JMenuBar menuBar = new JMenuBar(menuItem);

错误: JMenuBar 构造函数不接受 menuItem 作为参数,应先创建 JMenuBar 对象,再添加 JMenu 组件。

// Create a text area with 20 columns and 5 rows.
JTextArea textArea = new JTextArea (20, 5);

此代码没有错误。

3.3 算法工作台

以下是一些算法问题及对应的代码示例:
1. 更改内容面板背景颜色为绿色

getContentPane().setBackground(Color.GREEN);
  1. 创建包含周一到周日的列表
String[] days = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
JList dayList = new JList(days);
  1. 为上述列表添加滚动条
JScrollPane scrollPane = new JScrollPane(dayList);
  1. JList 组件中选中的项目赋值给 selection 变量
String selection = (String) myList.getSelectedValue();
  1. 将不可编辑组合框中选中项目的索引赋值给 selectionIndex 变量
int selectionIndex = myComboBox.getSelectedIndex();
  1. 创建一个单选按钮并分配助记符
JRadioButton radioButton = new JRadioButton("Option");
radioButton.setMnemonic(KeyEvent.VK_O);
  1. picture.gif 文件中的图像存储在 JLabel
ImageIcon image = new ImageIcon("picture.gif");
label.setIcon(image);
  1. 创建一个带有 “Open File” 文本的按钮,分配 O 键作为助记符,并分配 “This button opens a file” 作为组件的工具提示
JButton button = new JButton("Open File");
button.setMnemonic(KeyEvent.VK_O);
button.setToolTipText("This button opens a file");
  1. 使滚动面板的组件显示垂直滚动条,但确保不显示水平滚动条
JScrollPane scrollPane = new JScrollPane(component, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
  1. 创建一个显示 10 行 15 列的文本区域,必要时能够显示滚动条,并执行单词样式的换行
JTextArea textArea = new JTextArea(10, 15);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JScrollPane scrollPane = new JScrollPane(textArea);
  1. 创建一个带有一个名为 “File” 的菜单的菜单栏,为 “File” 菜单分配 F 键作为助记符,该菜单有三个菜单项:“Open”、“Print” 和 “Exit”,为每个菜单项分配助记符,并为每个菜单项注册动作监听器
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);

JMenuItem openItem = new JMenuItem("Open");
openItem.setMnemonic(KeyEvent.VK_O);
openItem.addActionListener(new OpenListener());

JMenuItem printItem = new JMenuItem("Print");
printItem.setMnemonic(KeyEvent.VK_P);
printItem.addActionListener(new PrintListener());

JMenuItem exitItem = new JMenuItem("Exit");
exitItem.setMnemonic(KeyEvent.VK_E);
exitItem.addActionListener(new ExitListener());

fileMenu.add(openItem);
fileMenu.add(printItem);
fileMenu.add(exitItem);

menuBar.add(fileMenu);
frame.setJMenuBar(menuBar);
  1. 创建一个水平方向的 JSlider 组件,范围从 0 到 1000,显示标签和刻度标记,主要刻度标记每 100 个数字出现一次,次要刻度标记每 25 个数字出现一次,滑块的初始值设置为 500
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 1000, 500);
slider.setMajorTickSpacing(100);
slider.setMinorTickSpacing(25);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
4. 简答题
  1. JList 的单选择模式和单间隔选择模式有什么区别?
    单选择模式下,用户只能选择一个项目;单间隔选择模式下,用户可以选择一个连续的项目区间。

  2. 如果要提供 20 个项目供用户选择,哪个组件占用空间更少, JList 还是 JComboBox
    JComboBox 占用空间更少,因为它在未展开时只显示一个按钮和当前选中的项目。

  3. 子菜单和菜单有什么区别?
    菜单是主菜单栏上的选项组,子菜单是菜单中的下拉选项组。

  4. 描述如何在 JLabel 组件中同时存储图像和文本?
    可以使用 JLabel 的构造函数或 setIcon setText 方法来同时设置图像和文本。

  5. 当为多个组件分配相同的助记符时会发生什么?
    助记符仅对第一个分配的组件有效。

  6. 当为组件分配的助记符是组件文本中出现的字母时会发生什么?
    该字母会被下划线标记,用户可以通过按下该字母和 Alt 键来激活组件。

  7. 什么是工具提示?它的目的是什么?
    工具提示是当用户将鼠标光标悬停在组件上时显示的文本,用于提供关于组件的额外信息。

  8. 如何使一组单选按钮菜单项一次只能选择一个?
    将它们分组在一个 ButtonGroup 对象中。

  9. 当选中的菜单项旁边显示复选标记时,用户点击它会发生什么?
    复选标记会消失,表示该菜单项未被选中。

  10. 如果使用 getSelectedValue 方法从列表组件中选择多个项目会发生什么?
    该方法仅返回第一个选中的项目。

  11. 为什么当希望用户输入一个数字,但要确保该数字在某个范围内时, JSlider 组件是理想的选择?
    JSlider 组件可以直观地显示范围,用户可以通过拖动滑块来选择范围内的数字。

  12. Java 中可用的标准 GUI 外观和感觉有哪些?
    Motif、Windows 等。

5. 编程挑战

以下是一些编程挑战的描述:
1. 体积转换 :创建一个应用程序,允许用户输入升的体积,然后显示转换为加仑的值。使用滑块在 0 升到 100 升之间调整升的体积。
2. 图像查看器 :编写一个应用程序,允许用户查看图像文件。应用程序应使用按钮或菜单项显示文件选择器。当用户选择图像文件时,应加载并显示该文件。
3. 宿舍和膳食计划计算器 :大学有不同的宿舍和膳食计划,创建一个应用程序,让用户选择宿舍和膳食计划,显示学期的总费用。
4. 滑板设计师 :创建一个应用程序,允许用户从列表组件或组合框中选择一个滑板甲板、一个卡车组件和一组轮子,还可以选择多个杂项产品。应用程序应显示小计、销售税(6%)和订单总额。
5. 购物车系统 :创建一个类似书店购物车系统的应用程序,从文件中读取书籍信息,用户可以选择书籍添加到购物车,结算时显示小计、销售税和总额。
6. 手机套餐 :编写一个应用程序,显示菜单系统,用户可以选择一个套餐、一部手机和所需的选项,应用程序应显示所选项目的价格。
7. 遮阳帘设计师 :创建一个应用程序,允许用户从列表或组合框中选择遮阳帘的样式、尺寸、颜色和数量,显示总费用。
8. 会议注册系统 :计算会议注册费用,用户可以选择注册类型、可选的开幕晚宴和主题演讲,以及多个会前研讨会,显示总费用。
9. 骰子模拟器 :编写一个 GUI 应用程序,模拟一对骰子,每次点击按钮时,应用程序应掷骰子,使用随机数确定每个骰子的值。
10. 纸牌发牌器 :编写一个 GUI 应用程序,随机从一副扑克牌中选择一张牌并显示,每次选择后将牌从牌堆中移除,当牌堆中没有牌时显示消息。
11. 井字棋模拟器 :创建一个 GUI 应用程序,模拟井字棋游戏,使用二维数组模拟游戏板,显示游戏结果。

高级 GUI 应用程序开发全解析

6. 编程挑战详细分析
6.1 体积转换
  • 功能概述 :该应用程序允许用户输入升的体积,然后将其转换为加仑并显示结果。使用滑块在 0 升到 100 升之间调整升的体积。
  • 实现步骤
    1. 创建一个 JFrame 作为主窗口。
    2. 在窗口中添加一个 JSlider 用于调整升的体积,设置其范围为 0 到 100。
    3. 添加一个 JLabel 用于显示升的体积和转换后的加仑值。
    4. JSlider 添加监听器,当滑块值改变时,将升转换为加仑并更新 JLabel 的显示内容。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class VolumeConverter extends JFrame {
    private JSlider slider;
    private JLabel resultLabel;

    public VolumeConverter() {
        setTitle("Volume Converter");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        slider = new JSlider(JSlider.HORIZONTAL, 0, 100, 0);
        slider.setMajorTickSpacing(10);
        slider.setPaintTicks(true);
        slider.setPaintLabels(true);
        add(slider);

        resultLabel = new JLabel();
        updateResult();
        add(resultLabel);

        slider.addChangeListener(e -> updateResult());

        setVisible(true);
    }

    private void updateResult() {
        double liters = slider.getValue();
        double gallons = liters * 0.264172;
        resultLabel.setText(liters + " liters = " + gallons + " gallons");
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(VolumeConverter::new);
    }
}
6.2 图像查看器
  • 功能概述 :此应用程序允许用户通过按钮或菜单项打开文件选择器,选择图像文件后加载并显示该图像。
  • 实现步骤
    1. 创建一个 JFrame 作为主窗口。
    2. 在窗口中添加一个 JButton 或菜单项,点击时显示文件选择器。
    3. 使用 JFileChooser 让用户选择图像文件。
    4. 选择文件后,使用 ImageIcon 加载图像并显示在 JLabel 中。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

public class ImageViewer extends JFrame {
    private JButton openButton;
    private JLabel imageLabel;

    public ImageViewer() {
        setTitle("Image Viewer");
        setSize(400, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        openButton = new JButton("Open Image");
        add(openButton);

        imageLabel = new JLabel();
        add(imageLabel);

        openButton.addActionListener(e -> {
            JFileChooser fileChooser = new JFileChooser();
            int result = fileChooser.showOpenDialog(this);
            if (result == JFileChooser.APPROVE_OPTION) {
                File selectedFile = fileChooser.getSelectedFile();
                ImageIcon image = new ImageIcon(selectedFile.getAbsolutePath());
                imageLabel.setIcon(image);
            }
        });

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ImageViewer::new);
    }
}
6.3 宿舍和膳食计划计算器
  • 功能概述 :该应用程序提供两个组合框,分别用于选择宿舍和膳食计划,用户选择后显示学期的总费用。
  • 实现步骤
    1. 创建一个 JFrame 作为主窗口。
    2. 在窗口中添加两个 JComboBox ,一个用于选择宿舍,另一个用于选择膳食计划。
    3. 为每个组合框设置选项和对应的费用。
    4. 添加一个 JLabel 用于显示总费用。
    5. 为组合框添加监听器,当选择改变时,计算总费用并更新 JLabel 的显示内容。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class DormMealCalculator extends JFrame {
    private JComboBox<String> dormBox;
    private JComboBox<String> mealBox;
    private JLabel resultLabel;

    private static final String[] DORMS = {"Allen Hall", "Pike Hall", "Farthing Hall", "University Suites"};
    private static final int[] DORM_FEES = {1500, 1600, 1200, 1800};
    private static final String[] MEALS = {"7 meals per week", "14 meals per week", "Unlimited meals"};
    private static final int[] MEAL_FEES = {560, 1095, 1500};

    public DormMealCalculator() {
        setTitle("Dorm and Meal Plan Calculator");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        dormBox = new JComboBox<>(DORMS);
        add(dormBox);

        mealBox = new JComboBox<>(MEALS);
        add(mealBox);

        resultLabel = new JLabel();
        updateResult();
        add(resultLabel);

        dormBox.addActionListener(e -> updateResult());
        mealBox.addActionListener(e -> updateResult());

        setVisible(true);
    }

    private void updateResult() {
        int dormIndex = dormBox.getSelectedIndex();
        int mealIndex = mealBox.getSelectedIndex();
        int total = DORM_FEES[dormIndex] + MEAL_FEES[mealIndex];
        resultLabel.setText("Total charges: $" + total);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(DormMealCalculator::new);
    }
}
6.4 滑板设计师
  • 功能概述 :该应用程序允许用户从列表组件或组合框中选择一个滑板甲板、一个卡车组件和一组轮子,还可以选择多个杂项产品,最后显示小计、销售税(6%)和订单总额。
  • 实现步骤
    1. 创建一个 JFrame 作为主窗口。
    2. 在窗口中添加三个 JComboBox 分别用于选择滑板甲板、卡车组件和轮子。
    3. 添加一个 JList 用于选择多个杂项产品。
    4. 添加一个 JLabel 用于显示小计、销售税和订单总额。
    5. 为组合框和列表添加监听器,当选择改变时,计算小计、销售税和订单总额并更新 JLabel 的显示内容。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

public class SkateboardDesigner extends JFrame {
    private JComboBox<String> deckBox;
    private JComboBox<String> truckBox;
    private JComboBox<String> wheelBox;
    private JList<String> miscList;
    private JLabel resultLabel;

    private static final String[] DECKS = {"The Master Thrasher", "The Dictator", "The Street King"};
    private static final int[] DECK_PRICES = {60, 45, 50};
    private static final String[] TRUCKS = {"7.75 inch axle", "8 inch axle", "8.5 inch axle"};
    private static final int[] TRUCK_PRICES = {35, 40, 45};
    private static final String[] WHEELS = {"51 mm", "55 mm", "58 mm", "61 mm"};
    private static final int[] WHEEL_PRICES = {20, 22, 24, 28};
    private static final String[] MISC = {"Grip tape", "Bearings", "Riser pads", "Nuts & bolts kit"};
    private static final int[] MISC_PRICES = {10, 30, 2, 3};

    public SkateboardDesigner() {
        setTitle("Skateboard Designer");
        setSize(400, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        deckBox = new JComboBox<>(DECKS);
        add(deckBox);

        truckBox = new JComboBox<>(TRUCKS);
        add(truckBox);

        wheelBox = new JComboBox<>(WHEELS);
        add(wheelBox);

        miscList = new JList<>(MISC);
        miscList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        JScrollPane scrollPane = new JScrollPane(miscList);
        add(scrollPane);

        resultLabel = new JLabel();
        updateResult();
        add(resultLabel);

        deckBox.addActionListener(e -> updateResult());
        truckBox.addActionListener(e -> updateResult());
        wheelBox.addActionListener(e -> updateResult());
        miscList.addListSelectionListener(e -> updateResult());

        setVisible(true);
    }

    private void updateResult() {
        int deckIndex = deckBox.getSelectedIndex();
        int truckIndex = truckBox.getSelectedIndex();
        int wheelIndex = wheelBox.getSelectedIndex();
        List<Integer> miscIndices = miscList.getSelectedIndicesList();

        int subtotal = DECK_PRICES[deckIndex] + TRUCK_PRICES[truckIndex] + WHEEL_PRICES[wheelIndex];
        for (int index : miscIndices) {
            subtotal += MISC_PRICES[index];
        }
        double tax = subtotal * 0.06;
        double total = subtotal + tax;

        resultLabel.setText("Subtotal: $" + subtotal + ", Tax: $" + tax + ", Total: $" + total);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(SkateboardDesigner::new);
    }
}
6.5 购物车系统
  • 功能概述 :该应用程序从文件中读取书籍信息,用户可以选择书籍添加到购物车,结算时显示小计、销售税(6%)和总额。
  • 实现步骤
    1. 创建一个 JFrame 作为主窗口。
    2. 从文件中读取书籍信息并存储在 JList 中。
    3. 添加一个 JList 作为购物车,用户可以将书籍从书籍列表添加到购物车。
    4. 添加按钮或菜单项用于移除购物车中的项目、清空购物车和结算。
    5. 为按钮或菜单项添加监听器,实现相应的功能。
    6. 结算时,计算小计、销售税和总额并显示。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ShoppingCartSystem extends JFrame {
    private JList<String> bookList;
    private JList<String> cartList;
    private JButton addButton;
    private JButton removeButton;
    private JButton clearButton;
    private JButton checkoutButton;
    private JLabel resultLabel;

    private DefaultListModel<String> bookModel;
    private DefaultListModel<String> cartModel;

    private List<Double> bookPrices;

    public ShoppingCartSystem() {
        setTitle("Shopping Cart System");
        setSize(600, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        bookModel = new DefaultListModel<>();
        cartModel = new DefaultListModel<>();
        bookPrices = new ArrayList<>();

        try {
            BufferedReader reader = new BufferedReader(new FileReader("BookPrices.txt"));
            String line;
            while ((line = reader.readLine()) != null) {
                String[] parts = line.split(",");
                String title = parts[0].trim();
                double price = Double.parseDouble(parts[1].trim());
                bookModel.addElement(title);
                bookPrices.add(price);
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        bookList = new JList<>(bookModel);
        cartList = new JList<>(cartModel);

        addButton = new JButton("Add to Cart");
        removeButton = new JButton("Remove from Cart");
        clearButton = new JButton("Clear Cart");
        checkoutButton = new JButton("Checkout");
        resultLabel = new JLabel();

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(addButton);
        buttonPanel.add(removeButton);
        buttonPanel.add(clearButton);
        buttonPanel.add(checkoutButton);

        add(new JScrollPane(bookList), BorderLayout.WEST);
        add(new JScrollPane(cartList), BorderLayout.EAST);
        add(buttonPanel, BorderLayout.SOUTH);
        add(resultLabel, BorderLayout.NORTH);

        addButton.addActionListener(e -> {
            int selectedIndex = bookList.getSelectedIndex();
            if (selectedIndex != -1) {
                String book = bookModel.getElementAt(selectedIndex);
                cartModel.addElement(book);
            }
        });

        removeButton.addActionListener(e -> {
            int selectedIndex = cartList.getSelectedIndex();
            if (selectedIndex != -1) {
                cartModel.remove(selectedIndex);
            }
        });

        clearButton.addActionListener(e -> cartModel.clear());

        checkoutButton.addActionListener(e -> {
            double subtotal = 0;
            for (int i = 0; i < cartModel.size(); i++) {
                String book = cartModel.getElementAt(i);
                int index = bookModel.indexOf(book);
                subtotal += bookPrices.get(index);
            }
            double tax = subtotal * 0.06;
            double total = subtotal + tax;
            resultLabel.setText("Subtotal: $" + subtotal + ", Tax: $" + tax + ", Total: $" + total);
        });

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ShoppingCartSystem::new);
    }
}
6.6 手机套餐
  • 功能概述 :该应用程序显示菜单系统,用户可以选择一个套餐、一部手机和所需的选项,应用程序显示所选项目的价格。
  • 实现步骤
    1. 创建一个 JFrame 作为主窗口。
    2. 在窗口中添加三个 JComboBox 分别用于选择套餐、手机和选项。
    3. 添加一个 JLabel 用于显示所选项目的价格。
    4. 为组合框添加监听器,当选择改变时,计算所选项目的价格并更新 JLabel 的显示内容。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class CellPhonePackages extends JFrame {
    private JComboBox<String> packageBox;
    private JComboBox<String> phoneBox;
    private JComboBox<String> optionBox;
    private JLabel resultLabel;

    private static final String[] PACKAGES = {"300 minutes per month", "800 minutes per month", "1500 minutes per month"};
    private static final double[] PACKAGE_PRICES = {45.00, 65.00, 99.00};
    private static final String[] PHONES = {"Model 100", "Model 110", "Model 200"};
    private static final double[] PHONE_PRICES = {29.95, 49.95, 99.95};
    private static final String[] OPTIONS = {"Voice mail", "Text messaging"};
    private static final double[] OPTION_PRICES = {5.00, 10.00};

    public CellPhonePackages() {
        setTitle("Cell Phone Packages");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        packageBox = new JComboBox<>(PACKAGES);
        add(packageBox);

        phoneBox = new JComboBox<>(PHONES);
        add(phoneBox);

        optionBox = new JComboBox<>(OPTIONS);
        add(optionBox);

        resultLabel = new JLabel();
        updateResult();
        add(resultLabel);

        packageBox.addActionListener(e -> updateResult());
        phoneBox.addActionListener(e -> updateResult());
        optionBox.addActionListener(e -> updateResult());

        setVisible(true);
    }

    private void updateResult() {
        int packageIndex = packageBox.getSelectedIndex();
        int phoneIndex = phoneBox.getSelectedIndex();
        int optionIndex = optionBox.getSelectedIndex();

        double packagePrice = PACKAGE_PRICES[packageIndex];
        double phonePrice = PHONE_PRICES[phoneIndex];
        double optionPrice = OPTION_PRICES[optionIndex];
        double phoneTax = phonePrice * 0.06;
        double total = packagePrice + phonePrice + phoneTax + optionPrice;

        resultLabel.setText("Package: $" + packagePrice + ", Phone: $" + phonePrice + ", Tax: $" + phoneTax + ", Option: $" + optionPrice + ", Total: $" + total);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(CellPhonePackages::new);
    }
}
6.7 遮阳帘设计师
  • 功能概述 :该应用程序允许用户从列表或组合框中选择遮阳帘的样式、尺寸、颜色和数量,显示总费用。
  • 实现步骤
    1. 创建一个 JFrame 作为主窗口。
    2. 在窗口中添加四个 JComboBox 分别用于选择样式、尺寸、颜色和数量。
    3. 添加一个 JLabel 用于显示总费用。
    4. 为组合框添加监听器,当选择改变时,计算总费用并更新 JLabel 的显示内容。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ShadeDesigner extends JFrame {
    private JComboBox<String> styleBox;
    private JComboBox<String> sizeBox;
    private JComboBox<String> colorBox;
    private JComboBox<String> quantityBox;
    private JLabel resultLabel;

    private static final String[] STYLES = {"Regular shades", "Folding shades", "Roman shades"};
    private static final int[] STYLE_PRICES = {0, 10, 15};
    private static final String[] SIZES = {"25 inches wide", "27 inches wide", "32 inches wide", "40 inches wide"};
    private static final int[] SIZE_PRICES = {0, 2, 4, 6};
    private static final String[] COLORS = {"Natural", "Blue", "Teal", "Red", "Green"};
    private static final int[] COLOR_PRICES = {5, 0, 0, 0, 0};
    private static final String[] QUANTITIES = {"1", "2", "3", "4", "5"};

    public ShadeDesigner() {
        setTitle("Shade Designer");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        styleBox = new JComboBox<>(STYLES);
        add(styleBox);

        sizeBox = new JComboBox<>(SIZES);
        add(sizeBox);

        colorBox = new JComboBox<>(COLORS);
        add(colorBox);

        quantityBox = new JComboBox<>(QUANTITIES);
        add(quantityBox);

        resultLabel = new JLabel();
        updateResult();
        add(resultLabel);

        styleBox.addActionListener(e -> updateResult());
        sizeBox.addActionListener(e -> updateResult());
        colorBox.addActionListener(e -> updateResult());
        quantityBox.addActionListener(e -> updateResult());

        setVisible(true);
    }

    private void updateResult() {
        int styleIndex = styleBox.getSelectedIndex();
        int sizeIndex = sizeBox.getSelectedIndex();
        int colorIndex = colorBox.getSelectedIndex();
        int quantity = Integer.parseInt((String) quantityBox.getSelectedItem());

        int baseFee = 50;
        int styleFee = STYLE_PRICES[styleIndex];
        int sizeFee = SIZE_PRICES[sizeIndex];
        int colorFee = COLOR_PRICES[colorIndex];
        int total = (baseFee + styleFee + sizeFee + colorFee) * quantity;

        resultLabel.setText("Total charges: $" + total);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ShadeDesigner::new);
    }
}
6.8 会议注册系统
  • 功能概述 :该应用程序计算会议注册费用,用户可以选择注册类型、可选的开幕晚宴和主题演讲,以及多个会前研讨会,显示总费用。
  • 实现步骤
    1. 创建一个 JFrame 作为主窗口。
    2. 在窗口中添加一个 JComboBox 用于选择注册类型。
    3. 添加 JCheckBox 用于选择开幕晚宴和主题演讲以及多个会前研讨会。
    4. 添加一个 JLabel 用于显示总费用。
    5. 为组合框和复选框添加监听器,当选择改变时,计算总费用并更新 JLabel 的显示内容。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ConferenceRegistrationSystem extends JFrame {
    private JComboBox<String> registrationBox;
    private JCheckBox dinnerBox;
    private JList<String> workshopList;
    private JLabel resultLabel;

    private static final String[] REGISTRATIONS = {"General", "Student"};
    private static final int[] REGISTRATION_FEES = {895, 495};
    private static final String[] WORKSHOPS = {"Introduction to E-commerce", "The Future of the Web", "Advanced Java Programming", "Network Security"};
    private static final int[] WORKSHOP_FEES = {295, 295, 395, 395};
    private static final int DINNER_FEE = 30;

    public ConferenceRegistrationSystem() {
        setTitle("Conference Registration System");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        registrationBox = new JComboBox<>(REGISTRATIONS);
        add(registrationBox);

        dinnerBox = new JCheckBox("Opening night dinner and keynote speech");
        add(dinnerBox);

        workshopList = new JList<>(WORKSHOPS);
        workshopList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        JScrollPane scrollPane = new JScrollPane(workshopList);
        add(scrollPane);

        resultLabel = new JLabel();
        updateResult();
        add(resultLabel);

        registrationBox.addActionListener(e -> updateResult());
        dinnerBox.addActionListener(e -> updateResult());
        workshopList.addListSelectionListener(e -> updateResult());

        setVisible(true);
    }

    private void updateResult() {
        int registrationIndex = registrationBox.getSelectedIndex();
        boolean dinnerSelected = dinnerBox.isSelected();
        int[] workshopIndices = workshopList.getSelectedIndices();

        int registrationFee = REGISTRATION_FEES[registrationIndex];
        int dinnerFee = dinnerSelected ? DINNER_FEE : 0;
        int workshopFee = 0;
        for (int index : workshopIndices) {
            workshopFee += WORKSHOP_FEES[index];
        }
        int total = registrationFee + dinnerFee + workshopFee;

        resultLabel.setText("Total cost: $" + total);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ConferenceRegistrationSystem::new);
    }
}
6.9 骰子模拟器
  • 功能概述 :该应用程序模拟一对骰子,每次点击按钮时,使用随机数确定每个骰子的值并显示。
  • 实现步骤
    1. 创建一个 JFrame 作为主窗口。
    2. 在窗口中添加一个 JButton ,点击时触发骰子滚动。
    3. 添加两个 JLabel 用于显示每个骰子的值。
    4. 为按钮添加监听器,点击时生成两个 1 到 6 之间的随机数,并更新 JLabel 的显示内容。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

public class DiceSimulator extends JFrame {
    private JButton rollButton;
    private JLabel die1Label;
    private JLabel die2Label;

    private Random random;

    public DiceSimulator() {
        setTitle("Dice Simulator");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        rollButton = new JButton("Roll Dice");
        add(rollButton);

        die1Label = new JLabel();
        add(die1Label);

        die2Label = new JLabel();
        add(die2Label);

        random = new Random();

        rollButton.addActionListener(e -> {
            int die1 = random.nextInt(6) + 1;
            int die2 = random.nextInt(6) + 1;
            die1Label.setText("Die 1: " + die1);
            die2Label.setText("Die 2: " + die2);
        });

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(DiceSimulator::new);
    }
}
6.10 纸牌发牌器
  • 功能概述 :该应用程序随机从一副扑克牌中选择一张牌并显示,每次选择后将牌从牌堆中移除,当牌堆中没有牌时显示消息。
  • 实现步骤
    1. 创建一个 JFrame 作为主窗口。
    2. 在窗口中添加一个 JButton ,点击时触发选牌操作。
    3. 添加一个 JLabel 用于显示选中的牌。
    4. 初始化一副扑克牌,并存储在列表中。
    5. 为按钮添加监听器,点击时从列表中随机选择一张牌,显示在 JLabel 中,并将该牌从列表中移除。
    6. 当列表为空时,显示消息提示。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CardDealer extends JFrame {
    private JButton dealButton;
    private JLabel cardLabel;

    private List<String> deck;

    public CardDealer() {
        setTitle("Card Dealer");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        dealButton = new JButton("Deal Card");
        add(dealButton);

        cardLabel = new JLabel();
        add(cardLabel);

        deck = new ArrayList<>();
        String[] suits = {"Hearts", "Diamonds", "Clubs", "Spades"};
        String[] ranks = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"};
        for (String suit : suits) {
            for (String rank : ranks) {
                deck.add(rank + " of " + suit);
            }
        }
        Collections.shuffle(deck);

        dealButton.addActionListener(e -> {
            if (!deck.isEmpty()) {
                String card = deck.remove(0);
                cardLabel.setText(card);
            } else {
                cardLabel.setText("No more cards left in the deck.");
            }
        });

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(CardDealer::new);
    }
}
6.11 井字棋模拟器
  • 功能概述 :该应用程序模拟井字棋游戏,使用二维数组模拟游戏板,显示游戏结果。
  • 实现步骤
    1. 创建一个 JFrame 作为主窗口。
    2. 在窗口中添加九个 JLabel 用于显示 X 和 O。
    3. 添加一个 JButton 用于开始新游戏。
    4. 使用二维数组模拟游戏板。
    5. 为按钮添加监听器,点击时开始新游戏,随机填充数组并更新 JLabel 的显示内容。
    6. 检查游戏是否有胜者或平局,并显示相应的消息。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

public class TicTacToeSimulator extends JFrame {
    private JLabel[][] boardLabels;
    private JButton newGameButton;
    private JLabel resultLabel;

    private int[][] board;
    private Random random;

    public TicTacToeSimulator() {
        setTitle("Tic Tac Toe Simulator");
        setSize(300, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        JPanel boardPanel = new JPanel(new GridLayout(3, 3));
        boardLabels = new JLabel[3][3];
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                boardLabels[i][j] = new JLabel();
                boardLabels[i][j].setHorizontalAlignment(JLabel.CENTER);
                boardLabels[i][j].setFont(new Font("Arial", Font.BOLD, 48));
                boardPanel.add(boardLabels[i][j]);
            }
        }
        add(boardPanel, BorderLayout.CENTER);

        newGameButton = new JButton("New Game");
        add(newGameButton, BorderLayout.SOUTH);

        resultLabel = new JLabel();
        add(resultLabel, BorderLayout.NORTH);

        board = new int[3][3];
        random = new Random();

        newGameButton.addActionListener(e -> newGame());

        setVisible(true);
    }

    private void newGame() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                board[i][j] = random.nextInt(2);
                if (board[i][j] == 0) {
                    boardLabels[i][j].setText("O");
                } else {
                    boardLabels[i][j].setText("X");
                }
            }
        }
        checkResult();
    }

    private void checkResult() {
        // Check rows
        for (int i = 0; i < 3; i++) {
            if (board[i][0] == board[i][1] && board[i][1] == board[i][2]) {
                if (board[i][0] == 0) {
                    resultLabel.setText("Player O won!");
                    return;
                } else {
                    resultLabel.setText("Player X won!");
                    return;
                }
            }
        }
        // Check columns
        for (int j = 0; j < 3; j++) {
            if (board[0][j] == board[1][j] && board[1][j] == board[2][j]) {
                if (board[0][j] == 0) {
                    resultLabel.setText("Player O won!");
                    return;
                } else {
                    resultLabel.setText("Player X won!");
                    return;
                }
            }
        }
        // Check diagonals
        if (board[0][0] == board[1][1] && board[1][1] == board[2][2]) {
            if (board[0][0] == 0) {
                resultLabel.setText("Player O won!");
                return;
            } else {
                resultLabel.setText("Player X won!");
                return;
            }
        }
        if (board[0][2] == board[1][1] && board[1][1] == board[2][0]) {
            if (board[0][2] == 0) {
                resultLabel.setText("Player O won!");
                return;
            } else {
                resultLabel.setText("Player X won!");
                return;
            }
        }
        resultLabel.setText("It's a tie!");
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(TicTacToeSimulator::new);
    }
}

总结

通过以上内容,我们全面了解了高级 GUI 应用程序开发的相关知识,包括更改 GUI 外观与感觉、避免常见错误、完成复习问题与练习、解答简答题以及实现多个编程挑战。在开发过程中,我们需要注意各种细节,如组件的使用、事件处理、布局管理等。同时,通过编程挑战的实践,我们可以进一步提高自己的编程能力和解决问题的能力。希望这些内容对大家在高级 GUI 应用程序开发方面有所帮助。


流程图示例

graph TD;
    A[开始] --> B[选择编程挑战,如体积转换];
    B --> C[创建 JFrame 主窗口];
    C --> D[添加组件,如 JSlider、JLabel 等];
    D --> E[为组件添加监听器];
    E --> F[处理事件,如计算结果、更新显示];
    F --> G[结束];

表格总结

编程挑战 功能概述 关键组件
体积转换 将升转换为加仑,使用滑块调整体积 JSlider、JLabel
图像查看器 选择并显示图像文件 JButton、JFileChooser、JLabel
宿舍和膳食计划计算器 选择宿舍和膳食计划,计算总费用 JComboBox、JLabel
滑板设计师 选择滑板组件和杂项产品,计算费用 JComboBox、JList、JLabel
购物车系统 选择书籍添加到购物车,结算费用 JList、JButton、JLabel
手机套餐 选择套餐、手机和选项,显示价格 JComboBox、JLabel
遮阳帘设计师 选择遮阳帘样式、尺寸、颜色和数量,计算费用 JComboBox、JLabel
会议注册系统 选择注册类型、晚宴和研讨会,计算费用 JComboBox、JCheckBox、JList、JLabel
骰子模拟器 模拟掷骰子 JButton、JLabel
纸牌发牌器 随机发牌,牌发完显示消息 JButton、JLabel
井字棋模拟器 模拟井字棋游戏,显示结果 JLabel、JButton
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值