95、Java Swing编程:从基础到组件应用

Java Swing编程:从基础到组件应用

1. Swing应用中的事件处理

在Swing应用里,为按钮添加事件处理是常见操作。以下代码展示了如何为两个按钮“Alpha”和“Beta”添加事件处理:

jbtnAlpha.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent ae) {
        jlab.setText("Alpha was pressed.");
    }
});

jbtnBeta.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent ae) {
        jlab.setText("Beta was pressed.");
    }
});

从JDK 8开始,也可以使用lambda表达式来实现事件处理,例如为“Alpha”按钮添加事件处理可以写成:

jbtnAlpha.addActionListener( (ae) -> jlab.setText("Alpha was pressed."));

lambda表达式的代码更简洁。后续示例为兼容JDK 8之前的版本,未使用lambda表达式,但在编写新代码时可以考虑使用。

添加事件处理后,将按钮添加到 JFrame 的内容面板:

jfrm.add(jbtnAlpha);
jfrm.add(jbtnBeta);

最后,将标签添加到内容面板并使窗口可见。运行程序后,每次按下按钮,标签会显示相应的消息。

需要注意的是,所有事件处理方法(如 actionPerformed() )都在事件调度线程上调用,因此事件处理方法必须快速返回,避免减慢应用程序。若应用程序在事件发生后需要执行耗时操作,必须使用单独的线程。

2. 创建Swing小程序

Swing小程序是另一种常见的Swing程序类型。与基于AWT的小程序不同,Swing小程序继承自 JApplet 而非 Applet JApplet 继承自 Applet ,包含了 Applet 的所有功能,并增加了对Swing的支持。

Swing小程序使用与之前章节描述相同的四个生命周期方法: init() start() stop() destroy() ,只需重写小程序需要的方法即可。Swing中的绘图方式与AWT不同,Swing小程序通常不会重写 paint() 方法。

以下是一个简单的Swing小程序示例:

// A simple Swing-based applet
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/*
This HTML can be used to launch the applet:
<applet code="MySwingApplet" width=220 height=90>
</applet>
*/

public class MySwingApplet extends JApplet {
    JButton jbtnAlpha;
    JButton jbtnBeta;
    JLabel jlab;

    // Initialize the applet.
    public void init() {
        try {
            SwingUtilities.invokeAndWait(new Runnable () {
                public void run() {
                    makeGUI(); // initialize the GUI
                }
            });
        } catch(Exception exc) {
            System.out.println("Can’t create because of "+ exc);
        }
    }

    // Set up and initialize the GUI.
    private void makeGUI() {
        // Set the applet to use flow layout.
        setLayout(new FlowLayout());

        // Make two buttons.
        jbtnAlpha = new JButton("Alpha");
        jbtnBeta = new JButton("Beta");

        // Add action listener for Alpha.
        jbtnAlpha.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent le) {
                jlab.setText("Alpha was pressed.");
            }
        });

        // Add action listener for Beta.
        jbtnBeta.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent le) {
                jlab.setText("Beta was pressed.");
            }
        });

        // Add the buttons to the content pane.
        add(jbtnAlpha);
        add(jbtnBeta);

        // Create a text-based label.
        jlab = new JLabel("Press a button.");

        // Add the label to the content pane.
        add(jlab);
    }
}

这个小程序有两个要点:一是 MySwingApplet 继承自 JApplet ;二是 init() 方法通过 invokeAndWait() 在事件调度线程上初始化Swing组件,确保在初始化完成后才返回,保证GUI完全构建好后才调用 start() 方法。

3. Swing中的绘图

Swing组件功能强大,还允许直接在框架、面板或其他组件(如 JLabel )的显示区域进行绘图。虽然很多Swing应用可能不会直接在组件表面绘图,但对于有此需求的应用是可行的。

3.1 绘图基础

Swing的绘图机制基于原始的AWT机制,但提供了更精细的控制。在AWT中, Component 类定义了 paint() 方法用于直接在组件表面绘制输出,该方法通常由运行时系统调用,而非程序主动调用。

Swing的轻量级组件继承了 paint() 方法,但不会直接重写它来绘图。Swing采用更复杂的绘图方法,包含三个不同的方法: paintComponent() paintBorder() paintChildren() 。要在Swing组件表面绘图,需创建组件的子类并重写 paintComponent() 方法,该方法用于绘制组件内部。重写 paintComponent() 时,首先要调用 super.paintComponent() ,确保组件正确绘制。

protected void paintComponent(Graphics g)

参数 g 是用于输出的图形上下文。

要在程序控制下使组件绘图,可调用 repaint() 方法,它在Swing中的工作方式与在AWT中相同。调用 repaint() 会使系统尽快调用 paint() 方法,在Swing中调用 paint() 会导致调用 paintComponent()

3.2 计算可绘制区域

在组件表面绘图时,要确保输出限制在边框内。虽然Swing会自动裁剪超出组件边界的输出,但仍可能绘制到边框上。为避免这种情况,需要计算组件的可绘制区域,即组件当前大小减去边框占用的空间。

可通过 getInsets() 方法获取边框宽度:

Insets getInsets()

该方法返回一个 Insets 对象,包含边框的尺寸信息,可通过以下字段获取具体值:

int top;
int bottom;
int left;
int right;

结合组件的宽度和高度(通过 getWidth() getHeight() 方法获取),可计算出可用的绘图区域。

3.3 绘图示例

以下程序创建了一个 PaintPanel 类,继承自 JPanel ,用于在面板上随机绘制线条:

// Paint lines to a panel.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

class PaintPanel extends JPanel {
    Insets ins; // holds the panel’s insets
    Random rand; // used to generate random numbers

    // Construct a panel.
    PaintPanel() {
        // Put a border around the panel.
        setBorder(
            BorderFactory.createLineBorder(Color.RED, 5));
        rand = new Random();
    }

    // Override the paintComponent() method.
    protected void paintComponent(Graphics g) {
        // Always call the superclass method first.
        super.paintComponent(g);

        int x, y, x2, y2;

        // Get the height and width of the component.
        int height = getHeight();
        int width = getWidth();

        // Get the insets.
        ins = getInsets();

        // Draw ten lines whose endpoints are randomly generated.
        for(int i=0; i < 10; i++) {
            // Obtain random coordinates that define
            // the endpoints of each line.
            x = rand.nextInt(width-ins.left);
            y = rand.nextInt(height-ins.bottom);
            x2 = rand.nextInt(width-ins.left);
            y2 = rand.nextInt(height-ins.bottom);

            // Draw the line.
            g.drawLine(x, y, x2, y2);
        }
    }
}

class PaintDemo {
    JLabel jlab;
    PaintPanel pp;

    PaintDemo() {
        // Create a new JFrame container.
        JFrame jfrm = new JFrame("Paint Demo");

        // Give the frame an initial size.
        jfrm.setSize(200, 150);

        // Terminate the program when the user closes the application.
        jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Create the panel that will be painted.
        pp = new PaintPanel();

        // Add the panel to the content pane. Because the default
        // border layout is used, the panel will automatically be
        // sized to fit the center region.
        jfrm.add(pp);

        // Display the frame.
        jfrm.setVisible(true);
    }

    public static void main(String args[]) {
        // Create the frame on the event dispatching thread.
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new PaintDemo();
            }
        });
    }
}

PaintPanel 类重写了 paintComponent() 方法,确保线条绘制在可绘制区域内。运行程序后,每次调整窗口大小或隐藏并恢复窗口,都会绘制一组新的线条。

4. 探索Swing组件

Swing提供了丰富的组件,如按钮、复选框、树和表格等,这些组件功能强大且可高度定制。以下是本章介绍的Swing组件类:
| 组件类 | 说明 |
| ---- | ---- |
| JButton | 按钮 |
| JCheckBox | 复选框 |
| JComboBox | 下拉框 |
| JLabel | 标签 |
| JList | 列表 |
| JRadioButton | 单选按钮 |
| JScrollPane | 滚动面板 |
| JTabbedPane | 选项卡面板 |
| JTable | 表格 |
| JTextField | 文本框 |
| JToggleButton | 切换按钮 |
| JTree | 树 |

这些组件都是轻量级的,继承自 JComponent 。此外,还介绍了 ButtonGroup 类用于封装互斥的Swing按钮,以及 ImageIcon 类用于封装图形图像。

5. JLabel和ImageIcon

JLabel 是Swing中最易用的组件,可用于显示文本和/或图标,它是被动组件,不响应用户输入。 JLabel 定义了多个构造函数,例如:

JLabel(Icon icon)
JLabel(String str)
JLabel(String str, Icon icon, int align)

参数 str icon 分别是标签的文本和图标, align 参数指定文本和/或图标在标签内的水平对齐方式,必须是 LEFT RIGHT CENTER LEADING TRAILING 之一。

图标由 Icon 接口指定,可通过 ImageIcon 类获取图标,例如:

ImageIcon(String filename)

该构造函数从指定文件中获取图像。

可通过以下方法获取和设置标签的图标和文本:

Icon getIcon()
String getText()
void setIcon(Icon icon)
void setText(String str)

以下小程序示例展示了如何创建和显示包含图标和字符串的标签:

// Demonstrate JLabel and ImageIcon.
import java.awt.*;
import javax.swing.*;

/*
  <applet code="JLabelDemo" width=250 height=200>
  </applet>
*/

public class JLabelDemo extends JApplet {
    public void init() {
        try {
            SwingUtilities.invokeAndWait(
                new Runnable() {
                    public void run() {
                        makeGUI();
                    }
                }
            );
        } catch (Exception exc) {
            System.out.println("Can't create because of " + exc);
        }
    }

    private void makeGUI() {
        ImageIcon icon = new ImageIcon("hourglass.png");
        JLabel jlab = new JLabel("Hourglass", icon, SwingConstants.CENTER);
        add(jlab);
    }
}

该程序创建了一个 ImageIcon 对象,用于表示 hourglass.png 文件中的图像,并将其作为参数传递给 JLabel 构造函数。最后将标签添加到内容面板。

Java Swing编程:从基础到组件应用

6. JButton 按钮组件

JButton 是 Swing 中常用的组件,用于触发操作。以下是创建和使用 JButton 的示例:

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

public class JButtonExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("JButton Example");
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new FlowLayout());

        JButton button = new JButton("Click Me");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(frame, "Button Clicked!");
            }
        });

        frame.add(button);
        frame.setVisible(true);
    }
}

在这个示例中,创建了一个 JButton 并添加了一个动作监听器。当按钮被点击时,会弹出一个消息对话框。

7. JCheckBox 复选框组件

JCheckBox 用于提供多个选项的选择,用户可以选择一个或多个选项。以下是使用 JCheckBox 的示例:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

public class JCheckBoxExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("JCheckBox Example");
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new FlowLayout());

        JCheckBox checkBox1 = new JCheckBox("Option 1");
        JCheckBox checkBox2 = new JCheckBox("Option 2");

        checkBox1.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    System.out.println("Option 1 selected");
                } else {
                    System.out.println("Option 1 deselected");
                }
            }
        });

        checkBox2.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    System.out.println("Option 2 selected");
                } else {
                    System.out.println("Option 2 deselected");
                }
            }
        });

        frame.add(checkBox1);
        frame.add(checkBox2);
        frame.setVisible(true);
    }
}

在这个示例中,创建了两个 JCheckBox 并为它们添加了项监听器。当复选框的状态改变时,会输出相应的信息。

8. JComboBox 下拉框组件

JComboBox 提供了一个下拉列表,用户可以从中选择一个选项。以下是使用 JComboBox 的示例:

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

public class JComboBoxExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("JComboBox Example");
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new FlowLayout());

        String[] options = {"Option 1", "Option 2", "Option 3"};
        JComboBox<String> comboBox = new JComboBox<>(options);

        comboBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String selectedOption = (String) comboBox.getSelectedItem();
                System.out.println("Selected: " + selectedOption);
            }
        });

        frame.add(comboBox);
        frame.setVisible(true);
    }
}

在这个示例中,创建了一个 JComboBox 并为其添加了一个动作监听器。当用户选择一个选项时,会输出所选的选项。

9. JList 列表组件

JList 用于显示一个列表,用户可以从中选择一个或多个项目。以下是使用 JList 的示例:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ListSelectionEvent;
import java.awt.event.ListSelectionListener;

public class JListExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("JList Example");
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new FlowLayout());

        String[] items = {"Item 1", "Item 2", "Item 3", "Item 4"};
        JList<String> list = new JList<>(items);

        list.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    String selectedItem = list.getSelectedValue();
                    System.out.println("Selected: " + selectedItem);
                }
            }
        });

        JScrollPane scrollPane = new JScrollPane(list);
        frame.add(scrollPane);
        frame.setVisible(true);
    }
}

在这个示例中,创建了一个 JList 并为其添加了一个列表选择监听器。当用户选择一个项目时,会输出所选的项目。

10. JRadioButton 单选按钮组件

JRadioButton 用于提供一组互斥的选项,用户只能选择其中一个选项。通常会使用 ButtonGroup 来管理一组 JRadioButton。以下是使用 JRadioButton 的示例:

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

public class JRadioButtonExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("JRadioButton Example");
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new FlowLayout());

        JRadioButton radioButton1 = new JRadioButton("Option 1");
        JRadioButton radioButton2 = new JRadioButton("Option 2");

        ButtonGroup buttonGroup = new ButtonGroup();
        buttonGroup.add(radioButton1);
        buttonGroup.add(radioButton2);

        radioButton1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Option 1 selected");
            }
        });

        radioButton2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Option 2 selected");
            }
        });

        frame.add(radioButton1);
        frame.add(radioButton2);
        frame.setVisible(true);
    }
}

在这个示例中,创建了两个 JRadioButton 并将它们添加到一个 ButtonGroup 中。当用户选择一个单选按钮时,会输出相应的信息。

11. Swing 组件使用流程总结

以下是使用 Swing 组件的一般流程:
1. 创建 JFrame 或 JApplet 作为容器。
2. 设置容器的大小、布局和关闭操作。
3. 创建所需的 Swing 组件,如 JButton、JCheckBox 等。
4. 为组件添加监听器(如果需要),以处理用户的交互。
5. 将组件添加到容器中。
6. 使容器可见。

graph TD;
    A[创建容器] --> B[设置容器属性];
    B --> C[创建组件];
    C --> D[添加监听器];
    D --> E[添加组件到容器];
    E --> F[使容器可见];

通过以上步骤,可以创建出功能丰富的 Swing 应用程序。不同的组件有不同的特点和用途,根据实际需求选择合适的组件进行组合使用。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值