QT的学习笔记 (一)

文章目录

  • 前言
  • 一、信号和槽
  • 二、控件
  • 总结


前言

软件:Qt Creator 4.10

QT是做UI的,主要做PC的UI界面

特点:

1.跨平台(windows  linux macos..)  2.开源

3.面向对象的,使用C++开发,执行效率高。

(qt 改进了C++)提供了全套的方法: UI  进程 线程  文件  数据 网络...


一、信号和槽

信号和槽:QT 特有的信号传输机制,用于对象之间的通信

信号signal:对象因为某种事件发出信号

槽slot  :信号的接收者,处理信号的对象 

一个信号可以发送给多个接收者,一个接收者可以接受多个信号

发送者发送信号---->接受者收到信号后,使用槽函数来处理信号

#include "widget.h"
#include "ui_widget.h"
#include    "signalslot.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)   //执行父亲背景
    , ui(new Ui::Widget) //创建ui对象:用户所有控件
{
    ui->setupUi(this);      //生成用户的拖拽

    ui->btnSure->setText("sure");
    /*
        这里你可以写 操作UI的代码

         this指向当前对象,就是 main{ Widget  w;}
         this->ui

    */
    ui->lineEdit->setText("hello world");


    /*信号和槽的演示,实现两个类(发送和接收类)  */
    class sender    snd;
    class receiver recv;

    //绑定了,当发送者发送指定信号的时候, qt会自动寻找接受者,并调用接收者的槽函数
    connect(&snd, SIGNAL( signal_snd(void)    )  ,&recv,  SLOT( slot_handle(void)    )    );
    connect(&snd, SIGNAL( signal_snddata(int) )  ,&recv,  SLOT( slot_handle_int(int) )    );
    connect(&snd, SIGNAL( signal_sndString(QString)),&recv,SLOT(slot_handle_string(QString)) );

    /*如何发送信号呢
        emit 发送者对象.信号函数();
    */

    emit snd.signal_snd();          /*  接受者对象recv的slot_handle被执行.    */
    emit snd.signal_snddata(56);
    emit snd.signal_sndString("hello world");
}

Widget::~Widget()
{
    delete ui;
}
#ifndef SIGNALSLOT_H
#define SIGNALSLOT_H

/*
    信号和槽,需要qt提供支持
    如何让类支持 信号和槽,
    1.你的class 要继承 QObject类---qt的基类:1.实现了信号和槽 2.
        当然你要包含他的头文件  #include <QObject>
    2.添加qt对C++的扩展
        在你的类中添加 宏 Q_OBJECT
*/

/*
	发送者,要发送信号
    信号,是一个特殊的函数
    如何实现信号函数:

*/

#include <QObject>

class sender :public QObject{
    Q_OBJECT

public:
    sender();

private:

signals:        //关键字,说明下面的都是 信号函数
    void signal_snd(void);      //信号,从来不需要##实现##的.  没有数据传递的
    void signal_snddata(int);   //信号,传递一个整数给对方
    void signal_sndString(QString);  //信号没有返回值
};

class receiver:public QObject{
    Q_OBJECT
public:
    receiver();

private:

public slots:  //关键字,声明下面的函数 是slot函数,专门用来处理信号的
    void slot_handle(void);  //slot 函数,专门用于处理 接收到的信号的,必须有实现
    void slot_handle_int(int);  //slot函数 ,绑定了发送者的 void signal_snddata(int);
    void slot_handle_string(QString);
};

#endif // SIGNALSLOT_H
#include "signalslot.h"
#include <qDebug>

sender::sender()  {}

receiver::receiver()  {}

void receiver::slot_handle()
{
    qDebug()<<"in slot_handle(void)"<<endl;
}

void receiver::slot_handle_int(int val)
{
    qDebug()<<"in slot_handle_int(int) "<<val<<endl;
}

void receiver::slot_handle_string(QString str)
{
    qDebug()<<"in slot_handle_string(QString) "<<str<<endl;
}

效果展示:

二、控件

1.按钮  QPushbutton

信号:    clicked() ---点击鼠标弹起的时候触发信号

                pressed()---mouse press down

                release()---鼠标释放的时候,和clicked一样

显示:

        setText( QString txt)

        setEnable(bool,show)        //  0/1   

手工UI :

        首先创建一个QPushbutton 对象,让对象显示在背景上

下面是代码,我把头文件和函数放在一起了,并让信号(点击、释放、按压)和槽函数建立连接    

// 头文件里面的槽函数
/*
    public slots:
    void btnLogClickedSlotFun();
    void btnLogpressedSlotFun();
    void btnLogreleasedSlotFun();

    void btnEnableSlotFun();

*/

 //########### you code ############
    ui->btnlog->setText("Sure");
    connect(ui->btnlog,SIGNAL(clicked()),this,SLOT(btnLogClickedSlotFun()));
    connect(ui->btnlog,SIGNAL(pressed()),this,SLOT(btnLogpressedSlotFun() ));
    connect(ui->btnlog,SIGNAL(released()),this,SLOT(btnLogreleasedSlotFun() ));

    connect(ui->btnEnable,SIGNAL(clicked()),this,SLOT(btnEnableSlotFun() ));

    connect(ui->btn1,SIGNAL(clicked()),this,SLOT(btn1Btnlog1SlotFun()));
    connect(ui->btn2,SIGNAL(clicked()),this,SLOT(btn2Btnlog2SlotFun()));


    // ########### manual--手工的 UI######
    ptStart = new QPushButton;
    ptStart->setParent(this);  //设置父对象

    //ptStart->setGeometry(int x,int y,int widht,int height);
    ptStart->setGeometry(30,40,80,60);

    ptStart->setText("munnul");
    //ptStart->show();  可以不写,父对象在显示的时候,
    connect(ptStart,SIGNAL(clicked()), this,SLOT( btnManualuiSlotFun()     ));

void Widget::btnLogClickedSlotFun()
{
    //__func__LINE__,分别是两个宏,编译器 遇到他们分别替换为 当前所在的函数和  行号
    qDebug()<<__func__<<__LINE__<<endl;
}

void Widget::btnLogpressedSlotFun()
{
    qDebug()<<__func__<<__LINE__<<endl;
}

void Widget::btnLogreleasedSlotFun()
{
    qDebug()<<__func__<<__LINE__<<endl;
}

void Widget::btnEnableSlotFun()
{
    qDebug()<<__func__<<__LINE__<<endl;
    static int cnt=0;
    cnt++;
    if(cnt%2==1){
        ui->btnlog->setEnabled(false);
    }else{
        ui->btnlog->setEnabled(true);

    }

}

void Widget::btnManualuiSlotFun()
{
    qDebug()<<"hello"<<endl;
}

 效果展示:

2.标签  QLabel

显示文本/图片,使用者不能修改内容

显示: setText( QString name);

        显示图片:

                qt创建资源管理器,把图片加入该资源source,每张图片都有一个内部路径

然后添加图片文件

定义png图像 对象,指定源文件图片

QPixmap pix("图片对象路径");

.setPixmap(QPixmap  &pix), 给label 设定要显示的图像

.setScaledContends(bool);   是否允许内容缩放

代码展示:     

//########### 设置 lable显示内容#######
    ui->labelName->setText("username");
    QString str = ui->labelName->text();  //显示lable内容
    qDebug()<<"get lable text:"<< str<<endl;
    QString strshow = "123454344-=dsls dkklakfkjkdjn你好sjkdsjkdjfjkdjfkdfjkdfdkfgkkkffjjj";
    ui->labelName->setWordWrap(true);  //根据文本内容,调整显示,换行
    ui->labelName->setText(strshow);
    /*
        1.定义png图像对象,指定源文件图片
        2.lable设置要显示的图片
            根据情况,是否允许缩放内容
    */

    QPixmap pix(":/rs/Weather 512x512.png");  //:表示是qt 内部路径
    ui->labelimage->setPixmap(pix);
    // 允许lable 里面的内容缩放 scale--缩放 content-内容
    ui->labelimage->setScaledContents(true);

    //手工写代码
    //  ptLblManual = new QLabel(this); ptLblManual->setParent(this);
   ptLblManual = new QLabel(this);
   ptLblManual->setGeometry(20,300,200,200); //x,y ,width,height

    QPixmap pixManual(":/rs/Mail 512x512.png");
    ptLblManual->setPixmap(pixManual);
    ptLblManual->setScaledContents(true);

效果展示:           

3.输入框  QLineEdit--行输入框        QTextLEdit ---多行输入框

QLineEdit:

显示: 默认填充

        setText()  设置内容

        显示有两种方式,一种是明文显示(默认),一种是密文显示

        setEchoMode(QLineEdit :: Password); //以㊙文显示

        QString.text(Qstring)         代码中获取用户输入

        setPlaceholderText();        设置占坑文本

信号: 输入完成信号 

        editFinish()         当用户正在编辑,突然回车或者鼠标点击其他地方(失去焦点),

表示输入完毕

        textChanged(QString &)        只要文本改变就触发信号(每改变)

QTextEdit:

        设置文本: setText( QString );

        获取文本: QString toplainText();

        清空文本:clear();        追加文本: append( QString txt);

//##########  log btn slot fun,handle lineEdit
    connect(ui->btnlog,SIGNAL(clicked()) ,this, SLOT( btnLogClickedSlotFun() ));

    //默认填充
    ui->lineEditName->setText("xiaoming");
    ui->lineEditPassword->setEchoMode(QLineEdit::Password);  //以密文显示
    ui->lineEditPassword->setText("123456");
    //处理密码输入框的  输入完成信号
    connect(ui->lineEditPassword, SIGNAL( editingFinished()) ,this, SLOT( btnEditPasswordFinishedSlotFun()   ));
    //用户名  输入检测: textChanged 信号处理
    connect(ui->lineEditName, SIGNAL( textChanged(const QString&)),\
            this,SLOT(lineEditNameTextchangeSlotFun(const QString&) ));


    //多行文本###############
   connect(ui->btnGet,SIGNAL(clicked()),this,SLOT( btnGetclickedSlotFun() ));
   connect(ui->btnSet,SIGNAL(clicked()),this,SLOT( btnSetClickedSlotFun() ));
   connect(ui->btnClear,SIGNAL(clicked()),this,SLOT( btnClearClickedSlotFun() ));
   connect(ui->btnAppend,SIGNAL(clicked()),this,SLOT( btnAppendSlotFun()));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::btnLogClickedSlotFun()
{
    qDebug()<<ui->lineEditName->text()<<" "<<ui->lineEditPassword->text()<<endl;
}

void Widget::btnEditPasswordFinishedSlotFun()
{
    qDebug()<<__func__<<__LINE__<<endl;
}

void Widget::lineEditNameTextchangeSlotFun(const QString &str)
{
    qDebug()<<__func__<<__LINE__<<str <<endl;

    QChar ch = str[ str.length() -1 ];
    if(ch >='a' && ch <='z'  ){

    }else {
        qDebug()<<"invalid input"<<ch <<endl;

    }

}
void Widget::btnSetClickedSlotFun()
{
    ui->textEdit->setText("欢迎提供建议....");
}
void Widget::btnGetclickedSlotFun()
{
    qDebug()<<"textEdit got:"<<ui->textEdit->toPlainText()<<endl;
}
void Widget::btnClearClickedSlotFun()
{
    ui->textEdit->clear();
    //ui->textEdit->setText("");
}

void Widget::btnAppendSlotFun()
{
    QString strname= ui->lineEditName->text();
    //ui->textEdit->append(strname);

    //另一种实现
    QString strText = ui->textEdit->toPlainText();
    QString newStr = strText + "\n" +strname;  //strText.operator +( strname)
    ui->textEdit->setText(newStr);
}

效果展示:

4.多选框--QCheckBox        单选框---QRadioButton        分组框---QGroupBox

QCheckBox:

        信号:

        stateChanged(int sel); 当前某个多选按钮改变,发出该信号,信号会包含当前的

状态(被选中--2  未选中--0)

        显示:setText( QString);

        bool  isChecked();  判断是否被选中        setChecked(bool ); 设置状态

RadioButton:

        信号: clicked()  当你点击某个对象,该对象发出被选中信号

        显示:同多选框

QGroupBox:  可以让每个单选框独立,互相之间不影响

        设置标题 setTitle

代码显示:

 //##############复选框  checkBox#########
    ui->checkBoxWoman->setText("woman");
    ui->checkBoxMoney->setChecked(true);

    connect(ui->checkBoxWoman,SIGNAL(stateChanged(int)), this,SLOT( checkBoxCommonStateChangedSlotFun( int)    ));
     connect(ui->checkBoxMoney,SIGNAL(stateChanged(int)), this,SLOT( checkBoxCommonStateChangedSlotFun( int)    ));
      connect(ui->checkBoxHouse,SIGNAL(stateChanged(int)), this,SLOT( checkBoxCommonStateChangedSlotFun( int)    ));
      connect(ui->checkBoxCar,SIGNAL(stateChanged(int)), this,SLOT( checkBoxCommonStateChangedSlotFun( int)    ));

    //###########   单选框##############
      ui->rbtnSexMan->setChecked(true);
      ui->rbtnSexWoman->setChecked(true);  //只会显示后面一个,前面一个被覆盖
      connect(ui->rbtnSexMan,SIGNAL(clicked()), this,SLOT(  rbtSexClickedSlotFun() ));
      connect(ui->rbtnSexWoman,SIGNAL(clicked()), this,SLOT(  rbtSexClickedSlotFun() ));

    // manual GroupBox  and QRadioBatton  手工创建组合框和单选框
       pGrpBox = new QGroupBox(this);   //指定父对象
       pGrpBox->setTitle("手工 --工作");
       pGrpBox->setGeometry(20,220,141,180);


       //prbtnIt = new QRadioButton(pGrpBox); prbtnIt->setText("程序员");
       prbtnIT = new QRadioButton("程序员",pGrpBox);
       prbtnIT->setGeometry(10,40,100,20); //坐标 相对于 父对象,并不是 外面的大窗体

       prbtnLawyer = new QRadioButton("律师",pGrpBox);
       prbtnLawyer->setGeometry(10,70,100,20);

       prbtnTeacher = new QRadioButton("教师",pGrpBox);
       prbtnTeacher->setGeometry(10,100,100,20);

       prbtnIT->setEnabled(true);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::checkBoxCommonStateChangedSlotFun(int )
{
    qDebug()<<__func__<<"house:"<<ui->checkBoxHouse->isChecked()<<" money:"<<
              ui->checkBoxMoney->isChecked()<<"woman:"<<ui->checkBoxWoman->isChecked()<<"car:"<<ui->checkBoxCar->isChecked()<<endl;
}

void Widget::rbtSexClickedSlotFun()
{
    qDebug()<<"man"<<ui->rbtnSexMan->isChecked()<<" woman"<<ui->rbtnSexWoman->isChecked()<<endl;

}

效果显示:

5.组合框/下拉框  QComboBox

QComboBox:

        构成:

                1.整个下拉框

                addItem( itemName);  添加主题

                int  count();        获取主题个数

                int  currentIndex();   当选选择的是第几个主题

                QString itemText();  当前选择的主题的文本

                信号: 当用户选择某个主题,发出信号

                        currentIndexChanged( const QString &txt)

                2. QComboBoxItem        主题

代码显示:

   ui->comboBoxFruit->addItem("apple");
    ui->comboBoxFruit->addItem("orange");
    connect(ui->pushButtonAdd,SIGNAL(clicked()) ,this, SLOT( btnAddClickedSlotFun() ));
     connect(ui->pushButtonDel,SIGNAL(clicked()) ,this, SLOT( btnDelClickedSlotFun() ));

    // 组合框的 信号: 当用户重新选择 item的时候,发出信号
     connect(ui->comboBoxFruit,SIGNAL(currentIndexChanged( const QString &)),\
              this, SLOT( comboxBoxFruitCurrentIndexChangedSlotFun( const QString &) ));

}

Widget::~Widget()
{
    delete ui;
}

void Widget::btnAddClickedSlotFun()
{
    QString str = ui->lineEditFruit->text();

    //遍历防止冲突
    for( int i=0; i<=ui->comboBoxFruit->count(); i++){
        QString fruit = ui->comboBoxFruit->itemText(i);
        if( str == fruit){
            qDebug()<<"invalid, conflict"<<endl;
            return ;
        }
    }

    ui->comboBoxFruit->addItem( str );
}

void Widget::btnDelClickedSlotFun()
{
    int curIndex = ui->comboBoxFruit->currentIndex();  //获取当前字符串的位置
    ui->comboBoxFruit->removeItem( curIndex);
}

void Widget::comboxBoxFruitCurrentIndexChangedSlotFun(const QString &itemText)
{
    qDebug()<<"find usr changed item:"<<itemText<<" "<<ui->comboBoxFruit->currentText()<<endl;  //可以直接获取改变的item

    ui->lineEditFruit->setText(itemText);

}

   效果显示:

                  

6.列表小控件  QListWidget

        构成: 

1.QListWidget  整体

                添加Item    addItem( QListWidget  *item)

                删除Item   QListWidgetItem  *takeItem( int row); // row删除第几个

        注意:删除后,ListWidget 内部并没有释放该item的空间,只是返回该item的地址

让你自己去释放  空间 delete  p;

                更改查看模式: 图标模式  列表模式

                        setViewMode ( QListWidget:: IconMode/ QListWidget::ListModde )

                获取当前用户选中的 item:   int currentRow();

         信号:

                 单击某个item  QListWidget  发出信号      itemClicked( QListWidgetItem *item)   

                双击某个item                                           itemDoubleClicked( QListWidgetItem *item)

2.QListWidgetItem :内部的小主题 (成员)

                文本: 设置 setText();     获取 QString text()

                图标: 设置 setIcon( QIcon &icon)        设置大小: setSizeHint( &sz);

        QSize sz(int w, int h);    int sz.width()   int  sz.heigh()

代码显示:

        

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    
    // 创建 item mail phone
    pMailItem = new QListWidgetItem;

    QIcon icon(":/rs/Mail 512x512.ico");     //定义一个图标对象,使用后面的图标进行初始化
    pMailItem->setIcon( icon );  //设置图标
    pMailItem->setText("邮件");

    phoneItem = new QListWidgetItem;
    QIcon icon1(":/rs/iPhone 512x512.ico");
    phoneItem->setIcon( icon1 );
    phoneItem->setText("手机");

    // 在 ListWidget 添加这两个item
    ui->listWidget->addItem(pMailItem);
    ui->listWidget->addItem(phoneItem);

    //按钮动态增加
    ui->lineEditName->setPlaceholderText("请输入item名字...");
    connect(ui->btnAdd,SIGNAL(clicked() ),this, SLOT( btnAddClickedSlotFun() ));

    //模式切换按钮
    connect(ui->btnmode, SIGNAL(clicked()), this, SLOT( btnmodeClickedSLotFun() ));

    //删除按钮
    connect(ui->btnDelect, SIGNAL(clicked() ), this, SLOT( btnDelectClickedSlotFun() ));

    //QListWidget 发出的信号处理
    connect(ui->listWidget, SIGNAL(itemClicked(QListWidgetItem *)) , this, \
            SLOT( listWidgetItemClickedSlotFun( QListWidgetItem *) ) );
    connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem *)) , this, \
            SLOT( listWidgetItemDoubleClickedSlotFun( QListWidgetItem *) ) );


}

Widget::~Widget()
{
    delete ui;
}

void Widget::btnAddClickedSlotFun()
{
    QString name = ui->lineEditName->text();
    QString path = ":/rs/Calculator 512x512.ico";  //默认路径

    if(name == "clock"){
        path=":/rs/Clock 512x512.ico";
    } else if(name =="Maps"){
        path=":/rs/Maps 512x512.ico";
    } else if(name =="Notes"){
        path =":/rs/Notes 512x512.ico";
    }

    QListWidgetItem *p = new QListWidgetItem;
    QIcon icon(path);
    p->setIcon(icon);
    p->setText(name);

    ui->listWidget->addItem(p);
}

void Widget::btnmodeClickedSLotFun()
{
    static int cnt =0;
    cnt++;
    if(cnt%2==1){
        ui->listWidget->setViewMode( QListWidget::IconMode );
    } else {
        ui->listWidget->setViewMode( QListWidget::ListMode );
    }
}

void Widget::btnDelectClickedSlotFun()
{
    int pos = ui->listWidget->currentRow();  //获取当前用户选中的是第几个
    QListWidgetItem *p = ui->listWidget->takeItem(pos);
    delete  p; //自己的空间,自己清理
}

void Widget::listWidgetItemClickedSlotFun(QListWidgetItem *it)
{
    qDebug()<<"U clicked"<<it->text();
}

void Widget::listWidgetItemDoubleClickedSlotFun(QListWidgetItem *it)
{
    qDebug()<<"U double clicked"<<it->text();
}

效果展示:        

7.微调框   QSpinBox / QDoubleSpinBox ---double 类型

QSpinBox/QDoubleSpinBox:
                类型 : T (int /double)
        程序获取用户输入    T .value();
        程序设置默认值           .setValue( T val);
        
        设置最大值/最小值 :setMaximum( T val);   setMinimum(int val)
        设置后缀 :   setSuffix();  前缀:  setPrefix
        
        信号: 当内容发生改变的时候,发出一个信号
            valueChanged( T  val );

代码展示:

#include "widget.h"
#include "ui_widget.h"

#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    ui->spinBoxNum->setValue(4);
    ui->spinBoxNum->setMaximum(1000);
    ui->spinBoxNum->setMinimum(25);
    ui->spinBoxNum->setSuffix(" KG");//后缀
    ui->spinBoxNum->setPrefix("# "); //前缀

    connect(ui->spinBoxNum,SIGNAL(  valueChanged(int)),this,SLOT( spinBoxNumValueChangedSlotFun(int)  ))

    ui->doubleSpinBoxPrice->setValue(5.6);
    ui->doubleSpinBoxPrice->setMaximum(56.3);
    ui->doubleSpinBoxPrice->setMinimum(2.3);
    ui->doubleSpinBoxPrice->setPrefix("羊 ");
    ui->doubleSpinBoxPrice->setSuffix(" 元");
    connect(ui->doubleSpinBoxPrice,SIGNAL(valueChanged(double)),this,SLOT(doubleSpinBoxValueChangedSlotFun(double) ));

}

Widget::~Widget()
{
    delete ui;
}

void Widget::spinBoxNumValueChangedSlotFun(int val)
{
    qDebug()<<"spinbox value="<<val<<"  "<<ui->spinBoxNum->value();

    double total = val * ui->doubleSpinBoxPrice->value();
    //snprintf(buf,sizeof(buf),"total:%lf 元",total);
    QString newstr = QString("%1 %2 %3").arg("羊 ").arg(total).arg(" 元");
    ui->lineEdit->setText( newstr   );
}

void Widget::doubleSpinBoxValueChangedSlotFun(double val)
{
    qDebug()<<"double spinbox value="<<val <<" "<<ui->doubleSpinBoxPrice->value();

    double total = val*ui->spinBoxNum->value();
    QString newstr =QString("%1 %2 %3").arg("羊 ").arg(total).arg(" 元");
    ui->lineEdit->setText(newstr);
}

8.滑动条  进度条

滑动条: 水平/垂直  Horizontal Slide   /   Vertical Slider
         QSlider ---滑动输入
            信号: valueChanged(int )   当你拖动的时候,发出信号,包含当前值
            设置:
                    最大值 setMaximum   最小值 setMinimum
                        默认值 : setValue(int)   获取当前值.int value
            
    进度条: QSprogressBar    进度显示,用户不可改动
            setValue(int val)
            int value();
            设置方向的 :setOrientation (QT::Vertical / QT::Horizontal)   //使用QT宏定义
            设置大小: reSize(x,y);
            


总结

        QT的控件很多很杂,遇到了要灵活运用。学习控件主要从两个两个方面学习,一是显示,二就是信号。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值