Java Swing调色板程序的实现与实践

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文详细介绍了Java Swing调色板程序的设计,它是一个基于Java图形用户界面框架的应用。程序涉及的关键知识点包括颜色知识、Swing组件、滚动控件、事件监听与处理、I/O流、布局管理以及Swing线程模型。这些知识点的综合运用,使得用户可以轻松选择和自定义颜色,并且能够持久保存个性化设置。 java swing调色板程序

1. 颜色表示与自定义

在现代计算机系统中,颜色的表示和自定义是图形用户界面(GUI)设计与开发的基础,对于提升用户体验至关重要。本章将带您深入了解颜色模型的基本原理,探索Java语言中颜色的表示方式,并实现一个颜色选择器,为开发提供实用的工具。

1.1 颜色模型基础

颜色模型是通过数学方法来精确描述色彩的系统。了解颜色模型的基础是自定义颜色和颜色选择器实现的前提。

1.1.1 RGB颜色模型的原理

RGB(红绿蓝)模型是最常见的颜色模型之一,它通过红(R)、绿(G)、蓝(B)三种颜色的不同强度组合来表示广泛的色彩范围。每种颜色都可以用一个介于0到255之间的整数来表示,RGB模型的组合效果如下:

Color rgbColor = new Color(int red, int green, int blue);

1.1.2 HSB颜色模型的介绍

HSB模型(色相Hue、饱和度Saturation、亮度Brightness)提供了一种更接近人类视觉感知的颜色表示方法。HSB模型利用圆形色轮来描述颜色,其中色相是角度,饱和度和亮度分别对应半径和强度。

在Java中,可以通过调整HSB值来获得颜色:

Color hsbColor = Color.getHSBColor(float hue, float saturation, float brightness);

接下来,我们将深入了解Java中的颜色表示及其在Swing组件中的应用。

2. Java Swing组件使用

2.1 Swing组件基础

Swing是Java的一个用于开发图形用户界面的工具包。它提供了一组丰富的组件,让开发者能够创建出功能完备的应用程序界面。本节将深入探讨Swing组件的基础知识,包括组件架构以及常用组件的使用方法。

2.1.1 Swing组件架构概述

Swing是基于抽象窗口工具包(AWT)之上构建的,并提供了一套完整的图形用户界面组件。Swing组件架构支持多种特性,包括复杂的用户界面、高度可定制化以及丰富的事件处理机制。它由三层结构组成:核心层、组件层和扩展层。

  • 核心层 :定义了基础的图形用户界面元素,如窗口、按钮和文本框等。
  • 组件层 :提供了可重用的用户界面控件,如表格、列表和树形控件等。
  • 扩展层 :包含了一些增强的、特定于应用的控件,这些控件并不是GUI开发的必需品,但可以在某些特定场景下提供帮助。

Swing采用了一种“轻量级组件”的设计,这表示其组件是用Java代码完全实现的,不依赖于本地操作系统的用户界面。这种设计使得Swing在跨平台方面具有独特的优势,因为同一个Swing应用可以在多个不同的操作系统上运行,而且外观和行为一致性很高。

2.1.2 常用组件的介绍与使用

Swing库中包含多种常用的组件,下面将介绍几种最为基本且常见的组件及其使用方法。

JFrame

JFrame 是Swing中最基本的顶层容器,用于创建一个窗口。以下是一个简单的示例代码,展示了如何创建一个包含一些文本和按钮的基本窗口:

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JButton;

public class SimpleJFrame extends JFrame {
    public SimpleJFrame() {
        setTitle("Simple JFrame Example");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JLabel label = new JLabel("Hello, Swing!");
        JButton button = new JButton("Click Me");
        add(label);
        add(button);
    }

    public static void main(String[] args) {
        SimpleJFrame frame = new SimpleJFrame();
        frame.setVisible(true);
    }
}

在上面的示例中,我们创建了一个 SimpleJFrame 类,该类继承自 JFrame 。在构造函数中,我们设置了窗口的标题、大小、默认关闭操作,并添加了一个标签( JLabel )和一个按钮( JButton )。 main 方法中创建了 SimpleJFrame 的实例,并使其可见。

JButton

JButton 是一个用户界面按钮组件,用于接收用户的点击事件。在Swing中,按钮可以注册监听器来响应用户的交互。以下是如何在上面的 SimpleJFrame 类中处理按钮点击事件的示例:

button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // 这里可以执行点击按钮后的逻辑
        System.out.println("Button clicked!");
    }
});

这段代码创建了一个匿名的 ActionListener 实例,并在点击按钮时打印出一条消息。

JLabel

JLabel 组件用于显示文本或图片。它可以用于向用户提供提示信息,或显示按钮的文本标签等。以下是如何创建和使用 JLabel 的示例代码:

JLabel label = new JLabel("Welcome to Java Swing!");
add(label);

这里,我们创建了一个 JLabel 对象,并将其添加到我们的 JFrame 中。

JTextField 和 JTextArea

文本字段( JTextField )和文本区域( JTextArea )是用于输入和显示文本的组件。 JTextField 用于单行文本输入,而 JTextArea 用于多行文本输入。下面是一个示例,展示了如何添加一个文本字段和文本区域到我们的窗口中:

JTextField textField = new JTextField(20);
JTextArea textArea = new JTextArea(5, 20);

add(new JLabel("Enter some text:"));
add(textField);
add(new JScrollPane(textArea)); // 添加滚动面板以支持文本区域滚动

在这段代码中,我们创建了一个 JTextField 和一个 JTextArea ,并给 JTextField 添加了一个标签。我们还为 JTextArea 添加了 JScrollPane ,以提供滚动功能。

通过本小节的介绍,我们已经对Swing组件架构有了基本的了解,并且学会了如何使用一些常用的Swing组件。接下来,在下一小节中,我们将进一步探讨这些组件的高级特性以及如何通过布局管理器来组织这些组件。

3. 滚动控件与事件监听

3.1 滚动面板的使用

3.1.1 JScrollBar组件的介绍

JScrollBar 是Java Swing中用于提供滚动条的组件。它允许用户通过滑动条来控制某个区间内的值。 JScrollBar 常见于需要显示超出当前视图范围内容的GUI应用程序中,例如文本编辑器、图片查看器等。

在使用JScrollBar时,我们首先需要创建一个实例,并将其添加到GUI中。JScrollBar有五个关键的概念:minimum、maximum、visibleAmount、value和extent。其中,minimum和maximum定义了滚动条的总范围,visibleAmount表示当前视图中可见的部分大小,value是当前滑块所在位置的值,extent则代表如果滑块被按下时,它所覆盖的范围大小。

// 创建垂直滚动条示例
JScrollBar scrollBar = new JScrollBar(JScrollBar.VERTICAL, 0, 10, 0, 100);
// 将滚动条添加到滚动面板中
JPanel scrollPane = new JPanel();
scrollPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
scrollPane.setLayout(new BorderLayout());
scrollPane.add(scrollBar, BorderLayout.LINE_END);

3.1.2 JViewport组件的作用与应用

JViewport 是Swing中用于提供一个视口来查看组件的组件,它可以和滚动面板(JScrollPane)结合起来使用,从而允许用户通过滚动条来浏览大型组件。JViewport创建了一个矩形区域,在这个区域内可以放置其他组件,它定义了一个视图和它的视图位置。

当JViewport与JScrollBar结合时,JViewport会负责显示滚动条所控制的组件的部分内容。调整滚动条的位置,实质上是调整JViewport中组件的可视部分。这样的配合使用,为复杂界面提供了更好的用户体验。

// 创建JViewport示例
JViewport viewport = new JViewport();
JPanel view = new JPanel();
view.add(new JLabel("内容超出可视区域"));
viewport.setView(view);
// 创建带有JViewport的JScrollPane
JScrollPane scrollPane = new JScrollPane(viewport);

3.1.3 JScrollBar与JViewport结合使用案例

当需要同时使用滚动条和视口时,可以将两者结合起来创建一个完整的滚动面板。以下是一个创建带有滚动条和视口的JScrollPane的实例代码:

// 创建JScrollBar实例
JScrollBar scrollBar = new JScrollBar(JScrollBar.VERTICAL, 0, 10, 0, 100);

// 创建JPanel作为需要滚动查看的内容
JPanel contentPanel = new JPanel();
// 假设contentPanel是一个复杂的组件,不能完全显示在当前视图中
for(int i = 0; i < 100; i++){
    contentPanel.add(new JLabel("内容项 " + i));
}

// 创建JViewport,设置其视图为contentPanel
JViewport viewport = new JViewport();
viewport.setView(contentPanel);

// 创建JScrollPane,将viewport添加到scrollPane中
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
scrollPane.setVerticalScrollBar(scrollBar);
scrollPane.setColumnHeaderView(viewport);

// 将scrollPane添加到JFrame中以显示
JFrame frame = new JFrame("滚动面板示例");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(scrollPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

3.2 事件监听机制

3.2.1 常见事件与监听器类型

在Java中,事件监听是GUI编程的一个核心概念。Swing组件可以产生不同类型的事件,如鼠标事件、键盘事件、动作事件等。为了响应这些事件,Swing使用了事件监听器模式。事件监听器是一种特殊的接口,定义了当特定的事件发生时需要被调用的方法。

例如,当用户点击一个按钮时,会触发一个 ActionEvent ,而监听这个事件的 ActionListener 接口中的 actionPerformed 方法会被调用。开发者可以实现这个接口,并将其实例注册到相应的组件上,以达到处理事件的目的。

// ActionListener接口的一个实现示例
ActionListener actionListener = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("按钮被点击了");
    }
};

// 注册监听器到按钮
JButton button = new JButton("点击我");
button.addActionListener(actionListener);

3.2.2 事件处理与响应流程

事件处理流程大致可以分为以下几个步骤: 1. 事件发生,如用户操作鼠标、键盘等。 2. 事件被事件源(如按钮、文本框)捕获。 3. 事件源将事件对象封装并委托给事件监听器。 4. 事件监听器根据事件类型,调用相应的处理方法。 5. 在处理方法中,开发者编写具体的逻辑代码。

事件的分发机制在Swing中是通过一个叫做事件分发线程(Event Dispatch Thread,EDT)的特殊线程完成的。所有的GUI更新都必须在EDT中执行,以保证线程安全。

// 在事件处理方法中,更新GUI组件的示例代码
ActionListener actionListener = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        // 假设有一个标签用于显示信息
        final JLabel label = (JLabel)e.getSource();
        // 在EDT中更新标签的文本
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                label.setText("点击操作已执行");
            }
        });
    }
};

3.3 事件监听器的高级应用

3.3.1 事件代理模式与自定义监听器

事件代理模式是一种常用的设计模式,用于处理GUI组件的事件。在事件代理模式中,组件不直接处理事件,而是将事件委托给一个单独的监听器来处理。这样做的好处是将组件的视图功能与事件处理逻辑分离,增强了代码的可维护性。

开发者可以根据实际需求创建自定义的监听器,通过继承事件监听器接口并实现其方法来创建。自定义监听器可以处理多种类型的事件,并且可以将特定的业务逻辑放在相应的方法中。

// 自定义监听器的实现示例
public class CustomButtonListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        // 自定义的事件处理逻辑
        System.out.println("自定义按钮被点击");
    }
}

// 将自定义监听器注册到按钮上
JButton customButton = new JButton("自定义监听器按钮");
customButton.addActionListener(new CustomButtonListener());

3.3.2 复合事件的处理策略

在复杂的GUI应用程序中,组件可能会产生复合事件,即一次用户操作可能同时触发多种事件。例如,在一个表格组件中选择一个单元格可能同时触发单元格选择事件、行选择事件和列选择事件。

对于复合事件的处理,开发者需要明确每种事件的处理逻辑,并且在监听器的实现中处理这些事件。在某些情况下,可能需要在多个监听器之间共享状态信息或者协调事件处理。

// 处理复合事件的监听器实现示例
public class TableSelectionListener implements ListSelectionListener, ActionListener {
    private JTable table;
    private JLabel statusLabel;

    public TableSelectionListener(JTable table, JLabel statusLabel) {
        this.table = table;
        this.statusLabel = statusLabel;
    }

    @Override
    public void valueChanged(ListSelectionEvent e) {
        // 处理列表选择事件
        int selectedRow = table.getSelectedRow();
        statusLabel.setText("选中了第 " + selectedRow + " 行");
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // 处理点击按钮事件
        statusLabel.setText("按钮被点击");
    }
}

// 注册监听器到表格组件和按钮
JTable table = new JTable();
JLabel statusLabel = new JLabel("状态信息:");
statusLabel.setHorizontalAlignment(JLabel.CENTER);
ActionListener buttonListener = new TableSelectionListener(table, statusLabel);
JButton button = new JButton("触发事件");
button.addActionListener(buttonListener);

// 将监听器添加到列表选择模型
ListSelectionModel selectionModel = table.getSelectionModel();
selectionModel.addListSelectionListener(new TableSelectionListener(table, statusLabel));

// 组装界面
JPanel panel = new JPanel();
panel.add(statusLabel);
panel.add(table);
panel.add(button);

在上面的代码示例中,我们创建了一个 TableSelectionListener ,它实现了 ListSelectionListener ActionListener 接口,用来同时处理列表选择事件和按钮点击事件。当用户在表格中选择一个单元格时, valueChanged 方法会被调用,同时,按钮的点击会触发 actionPerformed 方法。状态标签显示了当前的操作状态。

在处理复合事件时,需要注意不要进行重复的事件处理。如果事件处理的逻辑相同,应考虑使用事件代理模式来减少代码的重复,并且提高程序的可维护性。

4. GUI事件处理

4.1 事件处理概述

4.1.1 GUI事件处理的框架

GUI事件处理是创建用户交互界面不可或缺的一部分,它允许开发者定义当用户与界面元素(如按钮、键盘、鼠标)交互时,应用程序应如何响应。在Java的Swing库中,GUI事件处理是基于观察者设计模式构建的,该模式允许对象在运行时被注册为监听器,以便在特定事件发生时接收通知。

GUI事件处理框架涉及几个核心概念:事件源、事件对象、事件监听器和事件处理方法。事件源是触发事件的对象,如按钮被点击时产生的事件。事件对象则携带有关事件发生的信息,例如鼠标点击的位置。事件监听器是实现了特定事件监听器接口的对象,它们注册于事件源以等待事件发生,并提供方法以响应事件。事件处理方法是在事件监听器接口中定义的方法,用于在特定事件发生时执行特定的动作。

为了更好地理解GUI事件处理,让我们以按钮点击事件为例,探讨其传播和消费过程。当用户点击按钮时,按钮作为事件源生成一个ActionEvent对象,该对象被封装了点击的相关信息,如事件类型和发生时间。接下来,这个事件对象被发送到注册在该按钮上的所有ActionListener监听器。这些监听器的actionPerformed()方法会被调用,并且会接收到事件对象作为参数。在该方法内部,开发者可以编写响应用户点击行为的代码。

4.1.2 事件传播与消费

事件传播是指一个事件从事件源发出,传递到所有注册的监听器的过程。在Java中,事件传播遵循“先注册先通知”的原则,意味着如果多个监听器被注册到同一个事件源,它们将按照注册的顺序被通知。

事件消费则是在事件处理方法中对事件做出响应的行为。如果事件处理方法中调用了event.setConsumed(true)或类似机制(尽管Swing中并没有直接的setConsumed方法),那么该事件将不会被进一步传播。这在某些情况下非常有用,例如,当一个组件的事件响应足以处理该事件,且不需要其他组件再进行处理时。

4.2 事件适配器的使用

4.2.1 抽象事件监听器与事件适配器

在Swing中,为了方便开发者实现事件监听器,Java提供了一组抽象事件监听器类。这些抽象类实现了监听器接口的所有方法,但每个方法留空,以便子类进行覆盖。事件适配器类正是基于这个概念,它们作为抽象类存在,为处理常见事件类型提供了一个起点。

事件适配器类通常以其监听器接口的名字作为前缀,后面加上Adapter后缀。例如,对于ActionListener,有一个ActionAdapter类,其中actionPerformed()方法为空,供开发者实现。通过使用事件适配器类,开发者无需实现接口中所有方法,只需要关注需要响应的事件类型。

4.2.2 使用事件适配器处理复杂事件

复杂事件处理涉及到在事件处理方法中协调多个组件的行为,或者需要额外的状态管理。事件适配器在这里能够发挥巨大作用。由于适配器类已经为我们提供了空的事件处理方法的框架,我们可以在这些方法中添加自定义逻辑,以处理多个组件间的复杂交互。

例如,在开发一个文本编辑器时,可能需要处理文本区域内的文本变化事件。如果我们仅仅关心文本的删除事件,那么我们只需要覆盖文本变化事件监听器中的removeUpdate()方法,并在这个方法内实现相应的逻辑,而其他不关心的文本变化事件方法(如insertUpdate()或changedUpdate())可以保持为空。

4.3 鼠标与键盘事件

4.3.1 鼠标事件的种类与响应

鼠标事件包括点击、按下、释放、移动和拖拽等。在Java中,这些都是封装在MouseEvent对象中的不同事件类型。为了响应这些事件,我们实现MouseListener接口或MouseMotionListener接口。这些接口分别包含了多种方法来处理不同类型的鼠标事件。

例如,要处理鼠标点击事件,我们可以通过注册一个MouseListener,并实现mouseClicked()方法。在这个方法中,我们可以检查事件对象,获取点击的坐标,并根据这些信息更新UI或执行相应的逻辑。

4.3.2 键盘事件的处理与监听

键盘事件包括按键按下、释放以及按键重复事件,它们通过KeyEvent对象封装。处理键盘事件通常需要实现KeyListener接口中的三个方法:keyPressed(), keyReleased() 和 keyTyped()。

当按下或释放按键时,keyPressed()和keyReleased()方法将被调用,并可以通过检查KeyEvent对象的keyCode属性来区分是哪个键被操作。而keyTyped()方法则是在用户按下非控制键(如字母、数字或标点符号键)时被触发,它通常是针对字符输入的事件响应。

在实现键盘事件监听时,需要注意的是,Swing组件需要设置为焦点组件(focusable)并且拥有焦点(hasFocus),才能接收键盘事件。在文本输入框中,键盘事件的监听是默认开启的,而在其他组件中,可能需要显式调用requestFocus()方法来获得焦点。

以上就是GUI事件处理的基本框架和一些关键点。在后续章节中,我们将详细探讨事件适配器的具体使用,以及鼠标和键盘事件的高级处理技巧。

5. Java I/O流操作与Swing线程模型

5.1 Java I/O流操作基础

5.1.1 I/O流的概念与分类

I/O流是Java中进行数据输入输出的主要方式,它抽象了数据的读取和写入操作。I/O流分为两大类:字节流和字符流。字节流主要用于处理二进制数据,如图片和音频文件;字符流则处理文本数据,如文档和字符串。流操作通常以“流”作为操作的基本单位,从源头读取数据到目的地,或者反向过程。

5.1.2 文件操作与序列化实践

Java I/O流支持多种文件操作,包括读取、写入、追加和复制等。使用FileInputStream和FileOutputStream可以进行字节流的读写操作,而FileReader和FileWriter则用于字符流。序列化是指将对象状态转换为可以存储或传输的形式的过程,在Java中利用ObjectInputStream和ObjectOutputStream类实现对象的序列化和反序列化。

// 文件复制示例
public static void copyFile(File source, File destination) throws IOException {
    try (FileInputStream fis = new FileInputStream(source);
         FileOutputStream fos = new FileOutputStream(destination)) {
        byte[] buffer = new byte[1024];
        int length;
        while ((length = fis.read(buffer)) != -1) {
            fos.write(buffer, 0, length);
        }
    }
}

// 对象序列化示例
public static void serializeObjectToFile(Object obj, File file) throws IOException {
    try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) {
        oos.writeObject(obj);
    }
}

// 对象反序列化示例
public static Object deserializeObjectFromFile(File file) throws IOException, ClassNotFoundException {
    try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
        return ois.readObject();
    }
}

5.2 Swing中的线程模型

5.2.1 线程安全与单线程规则(EDT)

Swing是基于事件分发线程(Event Dispatch Thread, EDT)的图形用户界面工具包。Swing要求所有的UI更新操作必须在EDT中执行以确保线程安全,这是Swing线程模型的核心规则。违反此规则可能导致界面显示不一致、数据竞争等问题。

5.2.2 SwingWorker的使用与案例分析

SwingWorker是Swing提供的用于处理长时间运行的任务,并且可以安全更新UI的一个类。它可以在后台线程上执行计算,完成后通过publish和process方法更新UI,或者直接使用SwingWorker的get方法返回计算结果。

// 使用SwingWorker进行耗时任务处理
public class MySwingWorker extends SwingWorker<String, Void> {
    @Override
    protected String doInBackground() throws Exception {
        // 执行长时间运行的任务
        return "任务完成";
    }

    @Override
    protected void done() {
        try {
            // 在EDT中更新UI
            String result = get();
            JOptionPane.showMessageDialog(null, result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5.3 高级I/O流与Swing集成

5.3.1 字节流与字符流的高级应用

虽然基本的I/O流操作已经足够处理常见的文件操作,但在处理大型文件或需要高效缓冲时,使用高级I/O流可以提升性能。BufferedInputStream和BufferedOutputStream为字节流提供了缓冲功能,而BufferedReader和BufferedWriter则为字符流提供了相同功能。

5.3.2 网络编程与Swing的结合使用

Java提供了强大的网络API,Swing与网络编程结合可以实现客户端与服务器之间的数据交换。使用Socket编程,可以在Swing应用程序中实现网络通信。SwingWorker或事件监听器可以用来处理网络通信中耗时的I/O操作,避免阻塞EDT。

// 网络通信示例,与服务器进行交互
public class ClientServerCommunication {
    private String serverIP = "127.0.0.1";
    private int port = 6666;

    public void connectToServer() {
        new Thread(() -> {
            try (Socket socket = new Socket(serverIP, port);
                 BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                 PrintWriter writer = new PrintWriter(socket.getOutputStream(), true)) {
                String message;
                while ((message = reader.readLine()) != null) {
                    // 在EDT中更新UI
                    SwingUtilities.invokeLater(() -> showServerMessage(message));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }

    private void showServerMessage(String message) {
        // 更新Swing组件显示服务器消息的代码
    }
}

以上章节中的代码块展示了I/O流操作以及Swing与I/O结合的示例。代码解释和逻辑说明帮助读者理解执行过程和上下文中的作用。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文详细介绍了Java Swing调色板程序的设计,它是一个基于Java图形用户界面框架的应用。程序涉及的关键知识点包括颜色知识、Swing组件、滚动控件、事件监听与处理、I/O流、布局管理以及Swing线程模型。这些知识点的综合运用,使得用户可以轻松选择和自定义颜色,并且能够持久保存个性化设置。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值