Java Swing初学者教程

作者 : 慕源网 本文共11223个字,预计阅读时间需要29分钟 发布时间: 2022-04-11 共395人阅读

在本教程中,我们将了解如何构建一个基本的Java Swing(桌面)应用程序。我们还将了解初学者对挥杆最困惑的方面之一。使用事件在独立组件之间进行通信。

本教程假设您对Java有很好的了解。如果您没有,请在这里查看我丰富的免费基础Java课程。

Hello World Swing应用程序

Swing应用程序的基础是扩展JFrame类的单个窗口。请看下面的代码。
import javax.swing.JFrame;


public class MainFrame extends JFrame {
    public MainFrame() {
        super("Hello World");
        
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(800, 600);
        setVisible(true);
    }
}

我们创建了一个名为Mainframe的类,它扩展了JFrame。良好的实践表明,应用程序中应该只有一个JFrame,因为通常应该只有一个主窗口。构造函

数初始化此窗口。对超类构造函数(JFrame构造函数)的调用将窗口的标题设置为“Hello World”。

下一行设置“默认关闭操作”;它决定了当您通过单击角上的十字来关闭窗口时会发生什么。在本例中,我们告诉Swing在主窗口关闭时退出应用程序,这是您通常希望的。

然后,我们将窗口的大小设置为800像素宽和600像素高(根据喜好进行调整!),最后,我们使窗口真正可见,因为不可见的窗口没有多大用处。

一切都很好,但我们如何使用这个窗口?为此,我们需要一个带有main方法的类。这里有一个例子。

import javax.swing.SwingUtilities;

public class App {

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new MainFrame();
            }
        });
    }

}

它实际上比看起来要简单。要创建窗口,我们只需使用“new”创建一个Mainframe对象。我们甚至不需要创建一个变量来引用它,因为Mainframe的构

造函数将处理我们需要处理的一切。唯一的变化是SwingUtilities.invokeLater。尽管应用程序通常不需要它,但Oracle建议您在InvokeLater创建的特殊

Swing线程中运行Swing应用程序。从理论上讲,如果没有这一点,它可能会在某些情况下无法正常工作。

我们在这里使用匿名类语法来运行线程。这实际上看起来很像在Java中运行普通线程。你真的不需要详细了解这一点,但如果你想了解更多关于多线程

的知识,你可以在这里找到我关于多线程的免费课程。

添加按钮和文本区域

我们可以继续使用JFrame的构造函数向Swing应用程序添加组件。我不会在本教程中详细介绍所有不同的Swing组件;如果您想要一份详细的Swing指

南,我希望您可以考虑在这里查看我的精通Java Swing课程。但我们将看一看几个示例组件。

在下面的代码中,我在主窗口的中心添加了一个JTextArea(一个大的白色区域,您可以在其中键入文本),占据了大部分空间。我还在窗口底部添加

了一个按钮。有关说明,请参阅下面的代码。

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;


public class MainFrame extends JFrame {
    
    private JTextArea textArea;
    private JButton button;
    
    public MainFrame() {
        // Set the title
        super("Events Example");
        
        // Set the layout. BorderLayout lets you
        // add components at the centre, north, south
        // east and west positions.
        setLayout(new BorderLayout());
        
        // We need a new text area and a new button
        // Set the text on the button to "click me"
        textArea = new JTextArea();
        button = new JButton("Click Me");
        
        // Add the text area in the centre of the window.
        add(textArea, BorderLayout.CENTER);
        
        // Add the button to the bottom of the window (south)
        add(button, BorderLayout.SOUTH);
            
        // Make the app quit when we close the window.
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        
        // Set the window to 800 pixels wide and 600 high
        setSize(800, 600);
        
        // Make the window visible.
        setVisible(true);
    }
}

请注意,按钮的大小已调整为整个窗口的宽度。这是因为我们将其添加到窗口的方式。

使用JFrame add()方法向Swing窗口添加组件时,必须首先设置要使用的“布局管理器”。我们在这里使用的是BorderLayout,它允许您在屏幕的中心或在北(顶部)、南(底部)、西(左侧)或东(右侧)的位置添加组件。BorderLayout实际上只用于定义应用程序的大致轮廓,而不是添加按钮,但为了简单起见,我在这里使用了它。

在设置布局管理器之后,您必须为add()方法指定一些进一步的信息,以告诉布局管理器您已经设置了将组件添加到哪个位置。

Handling Events

我们可以通过向按钮添加“listener”来处理按钮单击。侦听器必须是实现ActionListener接口的类的对象。有多种可能性,但我将简单地让MainFrame实现该接口,并在这里将其用作侦听器。

请看下面的代码。我们使用按钮的addActionListener()方法将大型机本身作为侦听器添加到按钮(传入“this”)。Mainframe实现了ActionListener接口,它强制我们添加一个actionPerformed方法。此方法在单击按钮时被调用。

在actionPerformed()中,我们调用了JTextArea append方法,将文本“Hello”添加到JTextArea中,后面跟着换行符。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;


public class MainFrame extends JFrame implements ActionListener {
    
    private JTextArea textArea;
    private JButton button;
    
    public MainFrame() {
        // Set the title
        super("Events Example");
        
        // Set the layout. BorderLayout lets you
        // add components at the centre, north, south
        // east and west positions.
        setLayout(new BorderLayout());
        
        // We need a new text area and a new button
        // Set the text on the button to "click me"
        textArea = new JTextArea();
        button = new JButton("Click Me");
        
        // Add the text area in the centre of the window.
        add(textArea, BorderLayout.CENTER);
        
        // Add the button to the bottom of the window (south)
        add(button, BorderLayout.SOUTH);
        
        // Add a listener to the button.
        button.addActionListener(this);
            
        // Make the app quit when we close the window.
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        
        
        // Set the window to 800 pixels wide and 600 high
        setSize(800, 600);
        
        // Make the window visible.
        setVisible(true);
    }

    /*
     * This gets called when the button is clicked
     * Notice the code
     * button.addActionListener(this);
     * above.
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        textArea.append("Hello\n");
    }
}
添加子面板

您可以使用更多的标准Swing组件,也可以使用更多的布局管理器。您可以在我的精通Java Swing课程中找到有关它们的更多信息。但是,与其看更多的Swing组件和布局管理器,不如让我们来看看真正让初学者感到困惑的东西。

当您对Swing GUI应用程序进行布局时,通常希望应用程序中有多个面板。例如,我们可能有一个工具栏和包含表单、图表或其他内容的各种面板。

让我们在Swing应用程序中添加一个面板,并添加几个按钮。

在下面的代码中,我创建了一个扩展JPanel的类。JPanel是一个用于构建面板的有用类,我们可以使用它来概述用户界面的基本区域。我已将面板的背景设置为红色,以便在此处容易看到。我还设置了“首选尺寸”。

Swing组件有多种设置大小的方法。SetPreferredSize、SetMinimumSize、SetSize和SetMaximumSize..是否注意它们的任何大小取决于布局管理器。每个布局管理器对于要考虑或忽略哪些位的大小信息都有自己的想法。

import java.awt.Color;
import java.awt.Dimension;

import javax.swing.JPanel;


public class TestPanel extends JPanel {
    
    public TestPanel() {
        // Specify 200 pixels wide and 300 high.
        setPreferredSize(new Dimension(200, 300));
        setBackground(Color.red);
    }

}
现在,我们需要将此面板添加到主窗口。在下面的代码中,我只是用新的面板替换了以前的按钮。我还删除了“Implements ActionListener”代码,并删除了actionPerformed方法。最后,我让add()方法将面板添加到窗口的左侧(西)而不是底部(南)。
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;


public class MainFrame extends JFrame {
    
    private JTextArea textArea;
    private TestPanel panel;
    
    public MainFrame() {
        // Set the title
        super("Events Example");
        
        // Set the layout. BorderLayout lets you
        // add components at the centre, north, south
        // east and west positions.
        setLayout(new BorderLayout());
        
        // Now we use our panel instead of a button
        textArea = new JTextArea();
        panel = new TestPanel();
        
        // Add the text area in the centre of the window.
        add(textArea, BorderLayout.CENTER);
        
        // Add the panel to the left of the window (west)
        add(panel, BorderLayout.WEST);
        
    
        // Make the app quit when we close the window.
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        
        
        // Set the window to 800 pixels wide and 600 high
        setSize(800, 600);
        
        // Make the window visible.
        setVisible(true);
    }
}
这为我们提供了以下信息:

请注意,边框布局管理器会忽略面板的首选高度。它只记录宽度。这是因为边框布局使面板适合窗口的高度,如果我们把它放在左边。

将组件添加到子面板

我们可以使用布局管理器将组件添加到子面板中,其方式与我们之前将组件添加到JFrame子类(MainFrame)中的方式完全相同。

您可以在此处找到Swing布局管理器的可视化指南。这里还有一个关于Swing组件的可视化指南。

在下面的代码中,我使用BoxLayout管理器向面板添加了两个按钮。此布局管理器允许我们水平或垂直布局组件。我还对面板进行了以下更改:

删除了设置面板背景颜色的行

删除了设置面板大小的行–面板将在按钮周围自动调整大小

使面板实现ActionListener

将面板添加为按钮的侦听器

另外,我还添加了代码,使用传递给actionPerformed()的“Event”对象的getSource()方法检查按下了哪个按钮。这将为我们提供触发事件的组件。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;


public class TestPanel extends JPanel implements ActionListener {
    
    private JButton helloButton;
    private JButton goodbyeButton;
    
    public TestPanel() {
        
        // Create the buttons and add text to them.
        helloButton = new JButton("Hello");
        goodbyeButton = new JButton("Goodbye");
        
        // Set the panel itself to listen to the buttons
        helloButton.addActionListener(this);
        goodbyeButton.addActionListener(this);
        
        // Use box layout to add buttons in a vertical column
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        add(helloButton);
        add(goodbyeButton);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        
        // We can use the event "source" to figure
        // out which button was pressed.
        JButton source = (JButton)e.getSource();
        
        if(source == helloButton) {
            System.out.println("Hello");
        }
        else if(source == goodbyeButton) {
            System.out.println("Goodbye");
        }
    }

}
如果我们在Eclipse(或其他IDE)中运行此应用程序,则当我们单击按钮时,文本“Hello”或“Goodbye”会出现在IDE的控制台中,具体取决于我们单击的按钮。
Goodbye
Goodbye
Hello
Hello
使用观察者模式的自定义事件

但现在我们有个问题。假设我们要在单击按钮时将文本添加到文本区域。我们怎样才能得到我们需要的信息到文本区?

执行此操作的错误方法是将文本区域传递给子面板。一个组件与另一个组件以难以追踪的方式进行对话。

我们需要做的是获得一些其他类,例如Mainframe,来处理应用程序中发生的所有事件。我们需要让它充当“控制器”,接收信息并告诉子组件要做什么。

请注意,如果我们只想在单击按钮时更改子面板中的某些内容,则不会出现问题。出现这个问题是因为我们希望在自定义面板组件和单独的组件(文本区域)之间进行通信。

我们可以创建自己的事件,有点像ActionEvent。让我们创建我们自己的ActionEvent接口版本,我们的大型机稍后可以实现该接口。这里是:

public interface MyFormListener {
    public void formEventPerformed();
}
现在MainFrame 可以实现这一点,添加一个formEventpeformed()方法,当我们的一个按钮被点击时,该方法将被调用。

但是主机怎么知道哪个按钮被点击了呢?我们需要指定FormEventPerformed方法可以接受某种携带此信息的参数,就像ActionListener指定ActionPerformed接受有用的ActionEvent参数一样。这里有各种可能性,但我们将向接口添加一个枚举类型,以供FormeVentPerformed()使用。

这是我们的新界面:

public interface MyFormListener {
    
    public enum Type {
        hello,
        goodbye
    }
    
    public void formEventPerformed(MyFormListener.Type type);
}
现在,让我们给我们的子面板一个“setFormeVentListener”方法。我们将在面板中添加以下代码:

在TestPanel.Java中:

private MyFormListener formListener;
    
public void setFormListener(MyFormListener formListener) {
    this.formListener = formListener;
}
这允许我们为面板“设置监听器”。我们还将更改从按钮接收事件的actionPerformed方法,以引发自定义类型的新事件,通知侦听器发生了什么:

 TestPanel.java:

@Override
    public void actionPerformed(ActionEvent e) {

        // We can use the event "source" to figure
        // out which button was pressed.
        JButton source = (JButton) e.getSource();

        if (formListener != null) {
            if (source == helloButton) {
                formListener.formEventPerformed(MyFormListener.Type.hello);
            } else if (source == goodbyeButton) {
                formListener.formEventPerformed(MyFormListener.Type.goodbye);
            }
        }
    }
因此,完成的面板代码如下所示:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;

public class TestPanel extends JPanel implements ActionListener {

    private JButton helloButton;
    private JButton goodbyeButton;

    private MyFormListener formListener;

    public void setFormListener(MyFormListener formListener) {
        this.formListener = formListener;
    }

    public TestPanel() {

        // Create the buttons and add text to them.
        helloButton = new JButton("Hello");
        goodbyeButton = new JButton("Goodbye");

        // Set the panel itself to listen to the buttons
        helloButton.addActionListener(this);
        goodbyeButton.addActionListener(this);

        // Use box layout to add buttons in a vertical column
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        add(helloButton);
        add(goodbyeButton);
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        // We can use the event "source" to figure
        // out which button was pressed.
        JButton source = (JButton) e.getSource();

        if (formListener != null) {
            if (source == helloButton) {
                formListener.formEventPerformed(MyFormListener.Type.hello);
            } else if (source == goodbyeButton) {
                formListener.formEventPerformed(MyFormListener.Type.goodbye);
            }
        }
    }

}
现在,我们可以修改我们的MainFrame 以使用此代码。我们将执行以下操作:

使MainFrame 实现MyFormListener

将MainFrame 作为监听器添加到面板(在使用“新建”创建面板之后)

在MainFrame 的新FormeVentPerformed方法中,检查“type”参数,然后采取适当的操作,在子组件上调用“set”方法,如JTextArea append()

下面是完整的代码。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;


public class MainFrame extends JFrame implements MyFormListener {
    
    private JTextArea textArea;
    private TestPanel panel;
    
    public MainFrame() {
        // Set the title
        super("Events Example");
        
        // Set the layout. BorderLayout lets you
        // add components at the centre, north, south
        // east and west positions.
        setLayout(new BorderLayout());
        
        // Create the panel and text area
        textArea = new JTextArea();
        panel = new TestPanel();
        
        // Now we've created the panel, we can listen to it.
        panel.setFormListener(this);
        
        // Add the text area in the centre of the window.
        add(textArea, BorderLayout.CENTER);
        
        // Add the panel to the window
        add(panel, BorderLayout.WEST);
        
    
        // Make the app quit when we close the window.
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        
        
        // Set the window to 800 pixels wide and 600 high
        setSize(800, 600);
        
        // Make the window visible.
        setVisible(true);
    }

    @Override
    public void formEventPerformed(MyFormListener.Type type) {
        if(type == MyFormListener.Type.hello) {
            textArea.append("hello\n");
        }
        else if(type == MyFormListener.Type.goodbye) {
            textArea.append("goodbye\n");
        }
        
    }
}
请注意,我们的自定义事件没有提到按钮;我们可以在不改变事件的情况下,将按钮更改为复选框或菜单项等。所以事件抽象掉了不必要的细节。

我们在这里所做的是让面板引发一个事件,以响应其按钮被单击。我们的主机监听该事件。这也是“事件冒泡”的一种形式,在某种程度上,我们将按钮事件冒泡到MainFrame ——只不过我们实际上并没有冒泡按钮操作事件,而是将它们转换并合并为一种新类型的事件。

关于事件和监听器的整个事情被称为观察者模式。

总结

您可以在此处以ZIP格式下载整个代码。

在本Java Swing教程中,我们解决了Swing对于初学者来说最困难的一个方面。如何将应用程序拆分为单独的组件,然后在这些组件之间进行通信。Swing还有很多功能,但如果您能掌握其中的窍门,剩下的大部分都相对简单(好吧,除了凶猛的GridBagLayout和错综复杂的JTree)。

别忘了,你可以找到一个完整的Swing视频课程,带你从Swing初学者(假设只有核心Java知识)到Swing大师,就在这里:掌握Java Swing


慕源网 » Java Swing初学者教程

常见问题FAQ

程序仅供学习研究,请勿用于非法用途,不得违反国家法律,否则后果自负,一切法律责任与本站无关。
请仔细阅读以上条款再购买,拍下即代表同意条款并遵守约定,谢谢大家支持理解!

发表评论

开通VIP 享更多特权,建议使用QQ登录