Qt模型视图中的委托

目录

1、模型视图中的委托 

2、自定义委托 

3、改变视图默认的数据显示方式

4、进度条模拟显示


1、模型视图中的委托 

传统的MVC设计模式 

Qt中的模型视图设计模式采用委托处理用户输入

       -视图中集成了处理用户输入的功能 ,视图将用户输入作为内部独立的子功能而实现 

       -委托( Delegate )是视图中处理用户输入的部件,视图可以设置委托对象用于处理用户输入 

       -委托对象负责创建和显示用户输入上下文 。如:编辑框的创建和显示 

模型视图中的委托 

QAbstractItemDelegate类用于显示和编辑模型中的数据项

委托中的编辑器 

      -委托能够提供编辑时需要的上下文环境(编辑器) 

      -不同委托提供的编辑器类型不同(文本框,单选框,等)

      -编辑器用从模型获取数据,并将编辑结果返回模型 

委托中的关键函数 

      -createEditor :需要编辑数据时,创建编辑器组件 

      -updateEditorGeometry :更新编辑器组件的大小 

      -setEditorData :通过索引从模型中获取数据 

      -setModelData :将编辑后的新数据返回模型 

委托中的关键信号 

      - void closeEditor(QWidget* editor) :编辑器组件关闭信号 

      - void commitData(QWidget* editor) :新数据提交信号 

SubStyledItemDelegate.h

#ifndef SUBSTYLEDITEMDELEGATE_H
#define SUBSTYLEDITEMDELEGATE_H

#include <QStyledItemDelegate>

// 新建委托类,重写相关函数
class SubStyledItemDelegate : public QStyledItemDelegate 
{
    Q_OBJECT
protected slots:
    void onCloseEditor(QWidget* editor);
    void onCommitData(QWidget* editor);
public:
    explicit SubStyledItemDelegate(QObject* parent = 0);
    QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    void setEditorData(QWidget *editor, const QModelIndex &index) const;
    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
};

#endif // SUBSTYLEDITEMDELEGATE_H

SubStyledItemDelegate.cpp

#include "SubStyledItemDelegate.h"
#include <QDebug>

SubStyledItemDelegate::SubStyledItemDelegate(QObject *parent) :
    QStyledItemDelegate(parent)
{
    connect(this, SIGNAL(closeEditor(QWidget*)), this, SLOT(onCloseEditor(QWidget*)));
    connect(this, SIGNAL(commitData(QWidget*)), this, SLOT(onCommitData(QWidget*)));
}

QWidget* SubStyledItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    qDebug() << "SubStyledItemDelegate::createEditor";

    return QStyledItemDelegate::createEditor(parent, option, index);
}

void SubStyledItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    qDebug() << "SubStyledItemDelegate::updateEditorGeometry";

    QStyledItemDelegate::updateEditorGeometry(editor, option, index);
}

void SubStyledItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    qDebug() << "SubStyledItemDelegate::setEditorData";

    QStyledItemDelegate::setEditorData(editor, index);
}

void SubStyledItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    qDebug() << "SubStyledItemDelegate::setModelData";

    return QStyledItemDelegate::setModelData(editor, model, index);
}

void SubStyledItemDelegate::onCloseEditor(QWidget* editor)
{
    qDebug() << "SubStyledItemDelegate::onCloseEditor";
}

void SubStyledItemDelegate::onCommitData(QWidget* editor)
{
    qDebug() << "SubStyledItemDelegate::onCommitData";
}

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QtGui/QWidget>
#include <QTableView>
#include <QStandardItemModel>
#include <QPushButton>
#include "SubStyledItemDelegate.h"

class Widget : public QWidget
{
    Q_OBJECT
    
    QTableView m_view;
    QStandardItemModel m_model;
    QPushButton m_testBtn;
    SubStyledItemDelegate m_delegate;

    void initView();
    void initModel();

private slots:
    void onTestBtnClicked();
public:
    Widget(QWidget* parent = 0);
    ~Widget();
};

#endif // WIDGET_H

Widget.cpp

#include "Widget.h"
#include <QModelIndex>
#include <QDebug>

Widget::Widget(QWidget* parent) : QWidget(parent)
{
    initView();
    initModel();

    m_view.setModel(&m_model);

    m_testBtn.setParent(this);
    m_testBtn.move(10, 120);
    m_testBtn.resize(300, 30);
    m_testBtn.setText("Test");

    connect(&m_testBtn, SIGNAL(clicked()), this, SLOT(onTestBtnClicked()));
}

void Widget::initView()
{
    m_view.setParent(this);
    m_view.move(10, 10);
    m_view.resize(300, 100);
    m_view.setItemDelegate(&m_delegate);
}

void Widget::initModel()
{
    QStandardItem* root = m_model.invisibleRootItem();
    QStandardItem* itemA = new QStandardItem();
    QStandardItem* itemB = new QStandardItem();
    QStandardItem* itemC = new QStandardItem();
    QStandardItem* itemD = new QStandardItem();

    itemA->setData("A", Qt::DisplayRole);
    itemB->setData("B", Qt::DisplayRole);
    itemC->setData("C", Qt::DisplayRole);
    itemD->setData("D", Qt::DisplayRole);

    root->setChild(0, 0, itemA);
    root->setChild(0, 1, itemB);
    root->setChild(1, 0, itemC);
    root->setChild(1, 1, itemD);
}

void Widget::onTestBtnClicked()
{
    qDebug() << "Model Data:";

    for(int i=0; i<m_model.rowCount(); i++)
    {
        qDebug() << "Row: " << i;
        for(int j=0; j<m_model.columnCount(); j++)
        {
            QModelIndex index = m_model.index(i, j, QModelIndex());
            QString text = index.data(Qt::DisplayRole).toString();

            qDebug() << text;
        }
        qDebug() << endl;
    }

    qDebug() << "Current View Delegate: " << m_view.itemDelegate();
}

Widget::~Widget()
{
    
}

整个委托经历过程:

        1、创建编辑器

        2、改变编辑器大小,使得编辑器大小和数据项大小一样大

        3、设置编辑器里的数据

        4、回车后,提交数据到模型

        5、模型数据再次返回到编辑器当中(不多于,例如输入5*5得到结果25)

        6、关闭编辑器

2、自定义委托 

委托的本质 

      -为视图提供数据编辑的上下文环境

      -产生界面元素的工厂类 

      -能够使用和设置模型中的数据 

自定义委托时需要重写的函数

1. createEditor 

      -根据索引对应数据的类型创建编辑器组件 。如 布尔数据可以创建复选框,单个字符可以创建下拉选择框

2. updateEditorGeometry       

      -根据参数中数据项的信息设置编辑器的位置和大小 

3. setEditorData         

      -根据参数中的数据索引设置编辑器中的初始数据 。如:通过索引获得的数据类型是布尔型,则将复选框的选择状态设为该值     

4. setModelData            

      -根据参数中的数据索引更改模型中的数据          

5. paint (可选)            

      -根据参数中的信息绘制编辑器              

CustomizedItemDelegate.h

#ifndef CUSTOMIZEDITEMDELEGATE_H
#define CUSTOMIZEDITEMDELEGATE_H

#include <QItemDelegate>
#include <QModelIndex>

//自定义委托类,继承自标准委托类
class CustomizedItemDelegate : public QItemDelegate 
{
    Q_OBJECT

    mutable QModelIndex m_index;
protected slots:
    void onCloseEditor(QWidget*);
public:
    explicit CustomizedItemDelegate(QObject *parent = 0);
    
    // 重写一系列函数
    QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    void setEditorData(QWidget *editor, const QModelIndex &index) const;
    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};

#endif // CUSTOMIZEDITEMDELEGATE_H

CustomizedItemDelegate.cpp

#include "CustomizedItemDelegate.h"
#include <QCheckBox>
#include <QComboBox>

CustomizedItemDelegate::CustomizedItemDelegate(QObject *parent) :
    QItemDelegate(parent)
{
    connect(this, SIGNAL(closeEditor(QWidget*)), this, SLOT(onCloseEditor(QWidget*)));
}

QWidget* CustomizedItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QWidget* ret = NULL;

    m_index = index; // 记录当前被编辑数据项索引

    if( index.data().type() == QVariant::Bool )
    {
        // 当前数据项中的数据类型是bool型,创建复选框组件
        QCheckBox* cb = new QCheckBox(parent);

        cb->setText("Check to TRUE");

        ret = cb; 
    }
    else if( index.data().type() == QVariant::Char )
    {
        // 当前数据项中的数据类型是char型,创建下拉列表框组件
        QComboBox* cb = new QComboBox(parent);

        cb->addItem("A");
        cb->addItem("B");
        cb->addItem("C");
        cb->addItem("D");

        ret = cb;
    }
    else
    {
        // 其它情况,直接使用父类提供的默认创建编辑器组件方式
        ret = QItemDelegate::createEditor(parent, option, index);
    }

    return ret; //返回创建的编辑器组件
}

void CustomizedItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    editor->setGeometry(option.rect);
}

void CustomizedItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    if( index.data().type() == QVariant::Bool )
    {
        QCheckBox* cb = dynamic_cast<QCheckBox*>(editor);  

        if( cb != NULL )
        {
            cb->setChecked(index.data().toBool());//设置设置复选框组件被选中
        }
    }
    else if( index.data().type() == QVariant::Char )
    {
        QComboBox* cb = dynamic_cast<QComboBox*>(editor);

        if( cb != NULL )
        {
            for(int i=0; i<cb->count(); i++)
            {
                if( cb->itemText(i) == index.data().toString() )
                {
                    cb->setCurrentIndex(i); 
                    break;
                }
            }
        }
    }
    else
    {
        QItemDelegate::setEditorData(editor, index); 
    }
}

void CustomizedItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    if( index.data().type() == QVariant::Bool )
    {
        QCheckBox* cb = dynamic_cast<QCheckBox*>(editor);

        if( cb != NULL )
        {
            // 将复选框值(role data )取出,根据索引设置到模型
            model->setData(index, cb->isChecked(), Qt::DisplayRole);
        }
    }
    else if( index.data().type() == QVariant::Char )
    {
        QComboBox* cb = dynamic_cast<QComboBox*>(editor);

        if( cb != NULL )
        {
            model->setData(index, cb->currentText().at(0), Qt::DisplayRole);
        }
    }
    else
    {
        QItemDelegate::setModelData(editor, model, index);
    }
}


void CustomizedItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if( m_index != index ) // 不是当前被编辑数据项索引才进行绘制
    {
        QItemDelegate::paint(painter, option, index);
    }
}

void CustomizedItemDelegate::onCloseEditor(QWidget*)
{
    m_index = QModelIndex(); // 关闭编辑框时将当前记录的索引清空
}

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTableView>
#include <QStandardItemModel>
#include <QPushButton>
#include "CustomizedItemDelegate.h"

class Widget : public QWidget
{
    Q_OBJECT
    
    QTableView m_view;
    QStandardItemModel m_model;
    CustomizedItemDelegate m_delegate;

    void initView();
    void initModel();

public:
    Widget(QWidget* parent = 0);
    ~Widget();
};

#endif // WIDGET_H

Widget.cpp

#include "Widget.h"
#include <QStandardItem>
#include <QModelIndex>
#include <QStringList>
#include <QDebug>

Widget::Widget(QWidget* parent) : QWidget(parent)
{
    initView();
    initModel();

    m_view.setModel(&m_model);

    for(int i=0; i<m_model.columnCount(); i++)
    {
        m_view.setColumnWidth(i, 125);
    }
}

void Widget::initView()
{
    m_view.setParent(this);
    m_view.move(10, 10);
    m_view.resize(500, 200);
    m_view.setItemDelegate(&m_delegate); 
}

void Widget::initModel()
{
    QStandardItem* root = m_model.invisibleRootItem();
    QStringList hl;
    QStandardItem* itemA1 = new QStandardItem();
    QStandardItem* itemB1 = new QStandardItem();
    QStandardItem* itemC1 = new QStandardItem();
    QStandardItem* itemA2 = new QStandardItem();
    QStandardItem* itemB2 = new QStandardItem();
    QStandardItem* itemC2 = new QStandardItem();

    hl.append("Language");
    hl.append("Level");
    hl.append("Script");

    m_model.setHorizontalHeaderLabels(hl);

    itemA1->setData("Delphi", Qt::DisplayRole);
    itemB1->setData(QChar('A'), Qt::DisplayRole);
    itemC1->setData(false, Qt::DisplayRole);

    itemA2->setData("Perl", Qt::DisplayRole);
    itemB2->setData(QChar('B'), Qt::DisplayRole);
    itemC2->setData(true, Qt::DisplayRole);

    root->setChild(0, 0, itemA1);
    root->setChild(0, 1, itemB1);
    root->setChild(0, 2, itemC1);
    root->setChild(1, 0, itemA2);
    root->setChild(1, 1, itemB2);
    root->setChild(1, 2, itemC2);
}

Widget::~Widget()
{
    
}

main.cpp

#include <QtGui/QApplication>
#include "Widget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    
    return a.exec();
}

 

可以发现改变布尔值时非常不方便,需要改变视图默认的数据显示方式

自定义委托时重写的函数由谁调用? 单步调试可知是视图

总结:自定委托类时需要重写相应的成员函数 ,成员函数的参数携带了数据存取时需要的信息 ,根据需要创建编辑组件并设置组件中的数据 。编辑结束后将数据返回模型 

 

3、改变视图默认的数据显示方式

深度的思考 

      -疑问:委托是视图的构成部分,那么委托是否帮助视图显示具体数据呢? 

      -分析 :Qt中的委托作为视图的内部组件而存在,因此,委托是视图的一部分;必然,委托需要承担数据显示的部分工作。 

结论 

        -视图负责确定数据项的组织显示方式(列表,树形,表格)

        -委托负责具体数据项的显示和编辑(数据值,编辑器) 

        -视图和委托共同完成数据显示功能和数据编辑功能 

自定义委托的默认数据显示方式 

       1. 重写 paint 成员函数 

       2. 在 paint 中自定义数据显示方式 

       3. 重写 editorEvent 成员函数 (当开始对数据项进行编辑时,调用此函数)

       4. 在 editorEvent 中处理交互事件  


class CustomizedItemDelegate : public QItemDelegate
{
    Q_OBJECT

public:
    // ...
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
};
// ...

void CustomizedItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if( index.data().type() == QVariant::Bool )
    {
        bool data = index.data(Qt::DisplayRole).toBool();
        QStyleOptionButton checkBoxStyle; // QStyleOptionButton类用于描述绘制按钮的参数。
        
        // 设置具体的绘制参数
        checkBoxStyle.state = data ? QStyle::State_On : QStyle::State_Off;
        checkBoxStyle.state |= QStyle::State_Enabled;
        checkBoxStyle.rect = option.rect;
        checkBoxStyle.rect.setX(option.rect.x() + option.rect.width() / 2 - 6); //勾选框在中间
        // 根据参数绘制组件
        QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkBoxStyle, painter); 
    }
    else
    {
        QItemDelegate::paint(painter, option, index);
    }
}

bool CustomizedItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
    bool ret = true;

    if( index.data().type() == QVariant::Bool )
    {
        QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event);
        // 是鼠标按下事件,并且范围在具体数据项范围内
        if( (event->type() == QEvent::MouseButtonPress) && option.rect.contains(mouseEvent->pos()) )
        {
            bool data = index.data(Qt::DisplayRole).toBool(); 

            qDebug() << "set model data: " << !data;
            qDebug() << model->setData(index, !data, Qt::DisplayRole); // 重新设置模型中数据
        }
    }
    else
    {
        ret = QItemDelegate::editorEvent(event, model, option, index);
    }

    return ret;
}

 

委托是视图的重要构造部分 ,视图负责数据项的组织显示方式 ,委托负责具体数据项中数值的显示方式 

重写委托的paint函数自定义数据项显示方式 ,重写委托的editorEvent函数处理交互事件 

自定义视图数据显示的方法 

 

4、进度条模拟显示

实现下图效果

改进

'解决方案 

         1. 自定义新的委托类 

         2. 在 paint 成员函数中绘制进度条显示方式 

         3. 在 editorEvent 成员函数中禁止数据编辑操作 

CustomizedItemDelegate.h

#ifndef CUSTOMIZEDITEMDELEGATE_H
#define CUSTOMIZEDITEMDELEGATE_H

#include <QItemDelegate>

class CustomizedItemDelegate : public QItemDelegate
{
    Q_OBJECT
public:
    explicit CustomizedItemDelegate(QObject *parent = 0);
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
};

#endif // CUSTOMIZEDITEMDELEGATE_H

CustomizedItemDelegate.cpp

#include "CustomizedItemDelegate.h"
#include <QApplication>
#include <QEvent>

CustomizedItemDelegate::CustomizedItemDelegate(QObject *parent) :
    QItemDelegate(parent)
{
}

void CustomizedItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if( index.data().type() == QVariant::Int )
    {
        const int DELTA = 4;
        int progress = index.data().toInt();  // 获取进度数据
        QStyleOptionProgressBar progressBarOption; // QStyleOptionProgressBar类用于描述绘制进度条所需的参数。
        
        int top = option.rect.top() + DELTA;    // 距离 视图小部件 的顶部 偏移DELTA 
        int left = option.rect.left() + DELTA;
        int width = option.rect.width() - 2 * DELTA;
        int height = option.rect.height() - 2 * DELTA;

        // 设置绘制参数
        progressBarOption.rect = QRect(left, top, width, height); 
        progressBarOption.minimum = 0;
        progressBarOption.maximum = 100;
        progressBarOption.progress = progress;
        progressBarOption.textVisible = true; // 显示绘制文本信息
        progressBarOption.text = QString().sprintf("%d", progress) + "%";
        progressBarOption.textAlignment = Qt::AlignCenter;

        // 绘制进度条
        QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter);
    }
    else
    {
        QItemDelegate::paint(painter, option, index);
    }
}

bool CustomizedItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
    bool ret = true;

    // 委托中编辑器的双击事件将触发委托进入数据编辑状态 ,所以禁用
    if( event->type() != QEvent::MouseButtonDblClick )
    {
        ret = QItemDelegate::editorEvent(event, model, option, index);
    }

    return ret;
}

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTableView>
#include <QStandardItemModel>
#include <QTimer>
#include "CustomizedItemDelegate.h"

class Widget : public QWidget
{
    Q_OBJECT
    
    QTableView m_view;
    QStandardItemModel m_model;
    CustomizedItemDelegate m_delegate;
    QTimer m_timer;

    void initView();
    void initModel();
private slots:
    void timerTimeout();
public:
    Widget(QWidget* parent = 0);
    ~Widget();
};

#endif // WIDGET_H

Widget.cpp

#include "Widget.h"
#include <QStandardItem>
#include <QModelIndex>
#include <QStringList>
#include <QModelIndex>
#include <QDebug>

Widget::Widget(QWidget* parent) : QWidget(parent)
{
    initView();
    initModel();

    m_view.setModel(&m_model);

    for(int i=0; i<m_model.columnCount(); i++)
    {
        m_view.setColumnWidth(i, 200);
    }

    connect(&m_timer, SIGNAL(timeout()), this, SLOT(timerTimeout()));

    m_timer.setParent(this);
    m_timer.start(500);
}

void Widget::initView()
{
    m_view.setParent(this);
    m_view.move(10, 10);
    m_view.resize(500, 200);
    m_view.setItemDelegate(&m_delegate);
}

void Widget::initModel()
{
    QStandardItem* root = m_model.invisibleRootItem();
    QStringList hl;
    QStandardItem* itemA1 = new QStandardItem();
    QStandardItem* itemB1 = new QStandardItem();
    QStandardItem* itemA2 = new QStandardItem();
    QStandardItem* itemB2 = new QStandardItem();

    hl.append("Task");
    hl.append("Progress");

    m_model.setHorizontalHeaderLabels(hl);

    itemA1->setData("Delphi", Qt::DisplayRole);
    itemB1->setData(70, Qt::DisplayRole);

    itemA2->setData("Perl", Qt::DisplayRole);
    itemB2->setData(60, Qt::DisplayRole);

    root->setChild(0, 0, itemA1);
    root->setChild(0, 1, itemB1);
    root->setChild(1, 0, itemA2);
    root->setChild(1, 1, itemB2);
}

void Widget::timerTimeout()
{
    QModelIndex i1 = m_model.index(0, 1, QModelIndex());
    QModelIndex i2 = m_model.index(1, 1, QModelIndex());
    QVariant v1 = (i1.data().toInt() + 1) % 100;
    QVariant v2 = (i2.data().toInt() + 3) % 100;

    m_model.setData(i1, v1, Qt::DisplayRole);
    m_model.setData(i2, v2, Qt::DisplayRole);
}

Widget::~Widget()
{
    
}

main.cpp

#include <QtGui/QApplication>
#include "Widget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    
    return a.exec();
}

在实际工程项目中,可以使用后台线程根据实际的任务情况更新模型中的数据,从而更新数据的界面显示。 

 

更多详细可以查阅帮助文档

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值