(十六)Java GUI(窗口)编程

前言

从学习 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 窗口所有性质和一般性操作,比如:最大化、最小化、可移动、可缩放、可关闭等操作。

Java GUI 编程:从入门到实践

GUI,即图形用户界面,是用户与程序交互的主要方式之一。Java提供了一组GUI工具包,可以帮助开发者创建美观、易于使用的应用程序。GUI(图形用户界面)编程是开发一个应用程序的重要组成部分。它影响了用户与软件的交互方式,使人们能够通过直观的图形界面与程序进行操作。Java 作为一门广泛应用于各领域的编程语言,其 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 工具包

​ AWT 是 Java 中最早的 GUI 工具包,它提供了一组基础的 GUI 组件和窗口管理器,可以用于创建简单的 GUI 应用程序。以下是 AWT 工具包的一些常用组件和用法:

  • Frame(框架):用于创建顶级窗口,可以添加其他组件。
public class MyFrame extends Frame {
    public MyFrame() {
        super("My Frame");
        setSize(400, 300);
        setVisible(true);
    }
    
    public static void main(String[] args) {
        new MyFrame();
    }
}
  • Panel(面板):用于创建中间容器,可以添加其他组件。
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();
    }
}
  • Button(按钮):用于创建按钮,可以添加事件监听器。
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();
    }
}
  • Label(标签):用于创建文本标签。
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();
    }
}
  • TextField(文本框):用于创建文本输入框,可以添加事件监听器。
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 概述

Swing 是 Java 的一个扩展包,包含了丰富的 GUI 组件,用于创建图形用户界面。Swing 组件以 “J” 开头,例如 JFrameJButton 等。与 AWT 相比,Swing 组件更加轻量级,具有更好的可定制性、可移植性和可扩展性。

要使用 Swing 组件,需要导入以下包:

import javax.swing.*;

创建一个简单的 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 组件

Swing 组件是构建 GUI 应用程序的基石。Swing 提供了丰富的组件,如按钮、文本框、标签等。

  • 按钮(JButton)

JButton 是一个标准的按钮组件,用户可以点击它来触发某种操作。下面是一个创建按钮的示例:

JButton button = new JButton("Click me!");
  • 标签(JLabel)

JLabel 是一个用于显示文本、图像或两者的组件。下面是一个创建文本标签的示例:

JLabel label = new JLabel("Hello, Swing!");
  • 文本框(JTextField)

JTextField 是一个允许用户输入单行文本的组件。下面是一个创建文本框的示例:

JTextField textField = new JTextField(20);
  • 文本区域(JTextArea)

JTextArea 是一个允许用户输入多行文本的组件。下面是一个创建文本区域的示例:

JTextArea textArea = new JTextArea(5, 20);
  • 复选框(JCheckBox)

JCheckBox 是一个允许用户通过选中或取消选中来表示二进制选择的组件。下面是一个创建复选框的示例:

JCheckBox checkBox = new JCheckBox("Check me!");
  • 单选按钮(JRadioButton)

JRadioButtonJCheckBox 类似,但一组单选按钮中只能选择一个。要将一组单选按钮关联在一起,需要使用 ButtonGroup。下面是一个创建单选按钮的示例:

JRadioButton radioButton1 = new JRadioButton("Option 1");
JRadioButton radioButton2 = new JRadioButton("Option 2");
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(radioButton1);
buttonGroup.add(radioButton2);
  • 下拉列表(JComboBox)

JComboBox 是一个允许用户从列表中选择一个选项的组件。下面是一个创建下拉列表的示例:

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

以上只是 Swing 组件库中的一部分组件,还有很多其他组件可供开发者使用。

布局管理器

布局管理器(Layout Manager)负责管理组件在容器中的位置和大小。Swing 提供了多种布局管理器,如 BorderLayoutFlowLayoutGridLayoutGridBagLayout等。

  • BorderLayout

BorderLayout 将容器划分为五个区域:NORTHSOUTHEASTWESTCENTER。每个区域只能放置一个组件。以下是一个使用 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 是最简单的布局管理器,它将组件按照添加顺序从左到右、从上到下排列。以下是一个使用 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 将容器划分为指定数量的行和列,组件按照添加顺序从左到右、从上到下填充单元格。以下是一个使用 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

GridBagLayout 是最灵活的布局管理器,可以以任何方式布置组件。

事件处理

事件处理是 GUI 编程的核心。在 Java 中,事件处理使用监听器(Listener)实现。监听器是一个实现了特定接口的对象,用于监听组件的事件。当事件发生时,监听器将执行相应的操作。

Java 提供了许多事件类型,如 ActionEventMouseEventKeyEvent 。我们可以使用事件监听器来处理这些事件。

  • 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()方法获取鼠标当前位置,也可以使用 MouseEventgetPoint()方法获取鼠标当前位置的坐标。以下是示例代码:

      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 方法获取更多事件相关信息,例如事件时间、按键状态等。

  • Lambda 表达式简化代码

在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 线程,导致 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 概述

JavaFX 是 Java 的第三个 GUI 工具包,它是为 Java SE 8及更高版本开发的。JavaFX 提供了许多现代化的 GUI 组件,如 TableView、TreeTableView、TreeView 等。JavaFX 还支持 CSS 样式表和 FXML 文件,使 GUI 设计更加灵活,它用于构建丰富、交互式的图形用户界面和媒体应用程序。相对于 Swing,JavaFX 提供了更现代化的 UI 设计、更好的性能、更丰富的媒体支持和更容易的可视化效果。

以下是一些 JavaFX GUI编程中常用的类和组件:

  • Stage(舞台)

Stage是JavaFX中的顶级容器,表示应用程序的主窗口。可以使用Stage类创建和管理应用程序的主窗口,例如设置标题、大小、位置、图标等。

  • Scene(场景)

Scene是JavaFX中的容器,表示应用程序的一个场景或一个视图。可以在Scene中添加和管理应用程序的UI组件,例如按钮、标签、文本框等。

  • Layouts(布局)

JavaFX提供了多种布局管理器来帮助开发者设计和管理UI界面的布局。例如,HBox和VBox可以用于水平和垂直布局,BorderPane可以用于边框式布局,GridPane可以用于网格布局等。

  • Controls(控件)

JavaFX提供了多种UI控件,例如按钮、标签、文本框、下拉框、列表框、滑块等,可以用于构建应用程序的用户界面。

  • Effects(效果)

JavaFX提供了多种UI效果,例如阴影、模糊、颜色调整等,可以用于改善应用程序的视觉效果。

  • Media(媒体)

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 对象,将布局添加到其中。最后,我们将场景设置为窗口的场景,并将窗口设置为可见。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>