为了账号安全,请及时绑定邮箱和手机立即绑定

Qt框架入门:新手必读的简单教程

标签:
C++
概述

本文介绍了Qt框架入门的相关知识,包括Qt框架的基本特点和适用场景,详细讲解了开发环境的搭建过程,以及如何使用基础控件和布局管理器。此外,还提供了创建窗口和对话框的方法,并通过一个简单的计算器项目实践了Qt应用程序的开发流程。

Qt框架简介

Qt是一个跨平台的C++图形用户界面应用程序开发框架,它提供了大量的类和功能,使得开发者能够轻松地创建用户界面、网络通信、数据库访问等功能。Qt框架是开源的,支持多种操作系统,包括Windows、macOS、Linux等。Qt框架旨在简化应用程序的开发流程,提供高度可移植的代码库。

Qt的主要特点
  • 跨平台性:Qt支持多种操作系统,开发者可以编写一次代码,然后在多个平台上运行。
  • 丰富的控件集:Qt提供了丰富的控件,如按钮、标签、输入框等,方便开发者快速构建用户界面。
  • QML支持:Qt支持QML(Qt Meta Language),一种声明式的语言,用于描述用户界面,提供了更简洁的界面开发方式。
  • 良好的文档和社区支持:Qt提供了详细的文档和活跃的社区,开发者可以轻松地获取帮助。
  • 强大的网络功能:Qt内置了网络功能,支持HTTP、FTP、WebSocket等协议。
  • 数据库访问:Qt提供了QSql模块,方便开发者访问各种数据库。
  • 国际化支持:Qt对国际化和本地化提供了良好的支持,方便开发者应对不同语言的需求。
Qt的适用场景
  • 桌面应用程序:Qt非常适合开发桌面应用程序,如文件管理器、媒体播放器等。
  • 嵌入式系统:Qt可以用于开发嵌入式系统,如工业控制、车载娱乐系统等。
  • 移动应用:Qt支持开发移动应用,可以使用Qt for Android或Qt for iOS开发跨平台的移动应用。
  • Web应用:Qt支持开发Web应用,如使用Qt WebEngine模块开发基于Web的桌面应用。
  • 游戏开发:Qt提供了丰富的图形和音频功能,适合开发2D游戏。
  • 科学计算:Qt支持OpenGL,可以用于开发科学计算和可视化应用。
开发环境搭建

开发Qt应用程序需要安装Qt Creator和对应的Qt库。以下是具体步骤。

安装Qt Creator

Qt Creator是一个集成开发环境(IDE),专门用于Qt应用程序的开发。安装步骤如下:

  1. 访问Qt的官方网站并下载Qt安装程序。当前最新版本为Qt 6.4.1。
  2. 运行安装程序,选择需要安装的组件。可以选择安装Qt库、示例代码、文档等。
  3. 安装完成后,启动Qt Creator。
配置Qt Creator开发环境
  1. 打开Qt Creator,选择“工具”菜单,然后选择“选项”。
  2. 在“构建和运行”选项卡下,选择“Qt版本”子选项卡,点击“添加”按钮,选择安装的Qt库路径。
  3. 在“构建和运行”选项卡下,选择“构建套件”子选项卡,点击“添加”按钮,选择需要的Qt套件。
  4. 在“构建和运行”选项卡下,选择“构建配置”子选项卡,点击“添加”按钮,选择需要的构建配置。
  5. 在“构建和运行”选项卡下,选择“环境”子选项卡,点击“添加”按钮,配置所需的环境变量。
  6. 完成以上配置后,点击“确定”按钮保存设置。
创建第一个Qt项目
  1. 打开Qt Creator,选择“文件”菜单,然后选择“新建文件或项目”。
  2. 在“文件和项目”对话框中,选择“应用程序”,然后选择“Qt Widgets应用程序”,点击“下一步”按钮。
  3. 在“设置”对话框中,输入项目名称,选择项目保存路径,选择要使用的Qt版本,点击“下一步”按钮。
  4. 在“类设置”对话框中,选择主窗口类名,然后点击“完成”按钮。
  5. Qt Creator将创建一个简单的Qt Widgets应用程序项目,包括主窗口类和主函数。
  6. 在Qt Creator中打开主窗口类文件(例如mainwindow.hmainwindow.cpp),可以看到默认的主窗口代码。
  7. 在Qt Creator中打开主函数文件(例如main.cpp),可以看到默认的主函数代码。
  8. 编译并运行项目,可以看到一个空的主窗口。
基础控件使用

在Qt中,控件是构成用户界面的基本元素,如按钮、标签、输入框等。Qt提供了丰富的控件,可以通过布局管理器进行布局。

布局管理器简介

布局管理器是Qt中用于管理控件布局的重要工具。它可以根据控件的大小和位置进行自动调整,使得应用程序在不同大小的窗口中显示效果一致。Qt提供了多种布局管理器,如QVBoxLayoutQHBoxLayoutQGridLayout等。

QVBoxLayout

QVBoxLayout用于垂直排列控件。

#include <QVBoxLayout>

void MainWindow::setupUi() {
    QVBoxLayout *layout = new QVBoxLayout(this);
    QPushButton *button1 = new QPushButton("Button 1", this);
    QPushButton *button2 = new QPushButton("Button 2", this);

    layout->addWidget(button1);
    layout->addWidget(button2);
}

QHBoxLayout

QHBoxLayout用于水平排列控件。

#include <QHBoxLayout>

void MainWindow::setupUi() {
    QHBoxLayout *layout = new QHBoxLayout(this);
    QPushButton *button1 = new QPushButton("Button 1", this);
    QPushButton *button2 = new QPushButton("Button 2", this);

    layout->addWidget(button1);
    layout->addWidget(button2);
}

QGridLayout

QGridLayout用于网格布局。

#include <QGridLayout>

void MainWindow::setupUi() {
    QGridLayout *layout = new QGridLayout(this);
    QPushButton *button1 = new QPushButton("Button 1", this);
    QPushButton *button2 = new QPushButton("Button 2", this);
    QPushButton *button3 = new QPushButton("Button 3", this);

    layout->addWidget(button1, 0, 0);
    layout->addWidget(button2, 0, 1);
    layout->addWidget(button3, 1, 0, 1, 2);
}
添加和使用基本控件

在Qt中,可以通过Qt Designer或直接在代码中添加控件。以下是几种常见的控件及其使用方法。

按钮

按钮是最常用的控件之一,可以通过QPushButton类创建。

QPushButton *button = new QPushButton("Click Me", this);

标签

标签用于显示文本,可以通过QLabel类创建。

QLabel *label = new QLabel("Hello, World!", this);

输入框

输入框用于接收用户输入,可以通过QLineEdit类创建。

QLineEdit *lineEdit = new QLineEdit(this);

文本编辑框

文本编辑框用于编辑多行文本,可以通过QTextEdit类创建。

QTextEdit *textEdit = new QTextEdit(this);

列表框

列表框用于显示列表项,可以通过QListWidget类创建。

QListWidget *listWidget = new QListWidget(this);
listWidget->addItem("Item 1");
listWidget->addItem("Item 2");
控件事件和信号槽机制

Qt的信号槽机制是用于事件处理的重要机制。控件可以发出信号,槽函数可以接收信号并处理。以下是一个简单的例子,展示了如何使用信号槽机制。

#include <QPushButton>
#include <QLabel>

void MainWindow::setupUi() {
    QPushButton *button = new QPushButton("Click Me", this);
    QLabel *label = new QLabel("Not Clicked", this);

    // 连接信号和槽
    connect(button, &QPushButton::clicked, label, &QLabel::setText, "Clicked");
}
完整的控件事件处理示例

以下是一个完整的控件事件处理示例,展示了如何为按钮添加点击事件处理。

#include <QDialog>
#include <QFormLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>

class MyDialog : public QDialog {
    Q_OBJECT
public:
    MyDialog(QWidget *parent = nullptr) : QDialog(parent) {
        QVBoxLayout *layout = new QVBoxLayout(this);

        QLineEdit *lineEdit = new QLineEdit(this);
        QPushButton *okButton = new QPushButton("OK", this);
        QPushButton *cancelButton = new QPushButton("Cancel", this);

        layout->addWidget(lineEdit);
        layout->addWidget(okButton);
        layout->addWidget(cancelButton);

        // 连接信号和槽
        connect(okButton, &QPushButton::clicked, this, &MyDialog::accept);
        connect(cancelButton, &QPushButton::clicked, this, &MyDialog::reject);
    }
};
窗口和对话框的创建

Qt提供了丰富的窗口和对话框类,方便开发者创建各种窗口和对话框。本节将介绍主窗口的创建、对话框的创建和窗口属性的设置。

创建主窗口

主窗口是应用程序的主要界面,通常包含菜单栏、工具栏、状态栏等。可以通过QMainWindow类创建主窗口。

#include <QMainWindow>
#include <QMenuBar>
#include <QStatusBar>

class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
        QMenuBar *menuBar = new QMenuBar(this);
        QStatusBar *statusBar = new QStatusBar(this);

        // 设置菜单栏
        menuBar->addAction("File");
        menuBar->addAction("Edit");
        menuBar->addAction("View");
        menuBar->addAction("Help");

        // 设置状态栏
        statusBar->addWidget(new QLabel("Ready", this));

        // 设置窗口标题
        this->setWindowTitle("Main Window");

        // 设置窗口图标
        this->setWindowIcon(QIcon("path/to/icon.png"));

        // 设置窗口大小
        this->resize(800, 600);

        // 设置窗口位置
        this->move(100, 100);
    }
};
创建和显示对话框

对话框用于获取用户输入或显示信息,可以通过QDialog类创建。以下是一个简单的对话框示例。

#include <QDialog>
#include <QFormLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>

class MyDialog : public QDialog {
    Q_OBJECT
public:
    MyDialog(QWidget *parent = nullptr) : QDialog(parent) {
        QVBoxLayout *layout = new QVBoxLayout(this);

        QLineEdit *lineEdit = new QLineEdit(this);
        QPushButton *okButton = new QPushButton("OK", this);
        QPushButton *cancelButton = new QPushButton("Cancel", this);

        layout->addWidget(lineEdit);
        layout->addWidget(okButton);
        layout->addWidget(cancelButton);

        // 连接信号和槽
        connect(okButton, &QPushButton::clicked, this, &MyDialog::accept);
        connect(cancelButton, &QPushButton::clicked, this, &MyDialog::reject);
    }
};
窗口属性设置与调整

Qt提供了多种窗口属性,可以通过设置这些属性调整窗口的行为和外观。以下是一些常用窗口属性的设置方法。

设置窗口标题

this->setWindowTitle("My Application");

设置窗口图标

this->setWindowIcon(QIcon("path/to/icon.png"));

设置窗口大小

this->resize(800, 600);

设置窗口位置

this->move(100, 100);

设置窗口最小大小

this->setMinimumSize(400, 300);

设置窗口最大大小

this->setMaximumSize(1024, 768);

设置窗口边框样式

this->setWindowFlags(Qt::FramelessWindowHint);
资源文件管理

Qt资源文件(.qrc文件)用于管理和存储应用程序使用的资源文件,如图片、字体、样式表等。资源文件可以方便地在应用程序中使用,并且可以在编译时嵌入到可执行文件中。

Qt的资源文件介绍

Qt资源文件是一个XML格式的文件,文件扩展名为.qrc。资源文件定义了资源文件的路径和别名,可以在代码中通过别名访问这些资源。例如,以下是一个简单的资源文件示例:

<RCC>
    <qresource prefix="/icons">
        <file>icons/icon1.png</file>
        <file>icons/icon2.png</file>
    </qresource>
</RCC>
如何添加资源文件
  1. 创建一个.qrc文件,例如resources.qrc
  2. .qrc文件中定义资源文件的路径和别名。
  3. 在Qt Creator中,右键点击项目文件夹,选择“添加新文件”,选择“Qt”类别下的“Qt资源文件”,然后选择创建的.qrc文件。
  4. .qrc文件中添加资源文件路径。
<RCC>
    <qresource prefix="/icons">
        <file>icons/icon1.png</file>
        <file>icons/icon2.png</file>
    </qresource>
</RCC>
资源文件的使用方法

在代码中,可以通过QFileQPixmap等类访问资源文件。例如,以下是一个加载图片资源的例子:

#include <QFile>
#include <QPixmap>

void MainWindow::setupUi() {
    QPixmap pixmap(":/icons/icon1.png");

    // 使用图片
    QLabel *label = new QLabel(this);
    label->setPixmap(pixmap);
}
小项目实践

本节将通过一个简单的示例项目来介绍Qt应用程序的开发过程。示例项目是一个简单的计算器应用程序,包含基本的加减乘除功能。

设计一个小应用的需求

计算器应用程序的需求如下:

  1. 界面包含数字按钮(0-9)、运算符按钮(+、-、*、/、=)和清除按钮(C)。
  2. 用户可以输入数字并选择运算符进行计算。
  3. 计算结果显示在界面的某个区域。
分析并实现功能模块
  1. 界面设计:使用Qt Designer设计主窗口界面,包含数字按钮、运算符按钮和显示结果的标签。
  2. 按钮事件处理:为每个按钮设置点击事件,处理数字输入和运算符选择。
  3. 计算逻辑:实现计算逻辑,根据用户输入的数字和运算符进行计算,并显示结果。

界面设计

使用Qt Designer设计主窗口界面,包含数字按钮、运算符按钮和显示结果的标签。

<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QWidget" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>300</width>
    <height>400</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Calculator</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <property name="spacing">
    <number>10</number>
   </property>
   <property name="leftMargin">
    <number>10</number>
   </property>
   <property name="topMargin">
    <number>10</number>
   </property>
   <property name="rightMargin">
    <number>10</number>
   </property>
   <property name="bottomMargin">
    <number>10</number>
   </property>
   <item>
    <widget class="QLineEdit" name="lineEditResult">
     <property name="readOnly">
      <bool>true</bool>
     </property>
    </widget>
   </item>
   <item>
    <widget class="QPushButton" name="pushButton0">
     <property name="text">
      <string>0</string>
     </property>
    </widget>
   </item>
   <item>
    <widget class="QPushButton" name="pushButton1">
     <property name="text">
      <string>1</string>
     </property>
    </widget>
   </item>
   <item>
    <widget class="QPushButton" name="pushButton2">
     <property name="text">
      <string>2</string>
     </property>
    </widget>
   </item>
   <item>
    <widget class="QPushButton" name="pushButton3">
     <property name="text">
      <string>3</string>
     </property>
    </widget>
   </item>
   <item row="0" column="0">
    <widget class="QPushButton" name="pushButton4">
     <property name="text">
      <string>4</string>
     </property>
    </widget>
   </item>
   <item row="0" column="1">
    <widget class="QPushButton" name="pushButton5">
     <property name="text">
      <string>5</string>
     </property>
    </widget>
   </item>
   <item row="0" column="2">
    <widget class="QPushButton" name="pushButton6">
     <property name="text">
      <string>6</string>
     </property>
    </widget>
   </item>
   <item row="1" column="0">
    <widget class="QPushButton" name="pushButton7">
     <property name="text">
      <string>7</string>
     </property>
    </widget>
   </item>
   <item row="1" column="1">
    <widget class="QPushButton" name="pushButton8">
     <property name="text">
      <string>8</string>
     </property>
    </widget>
   </item>
   <item row="1" column="2">
    <widget class="QPushButton" name="pushButton9">
     <property name="text">
      <string>9</string>
     </property>
    </widget>
   </item>
   <item row="0" column="3">
    <widget class="QPushButton" name="pushButtonPlus">
     <property name="text">
      <string>+</string>
     </property>
    </widget>
   </item>
   <item row="1" column="3">
    <widget class="QPushButton" name="pushButtonMinus">
     <property name="text">
      <string>-</string>
     </property>
    </widget>
   </item>
   <item row="2" column="0">
    <widget class="QPushButton" name="pushButtonMultiply">
     <property name="text">
      <string>*</string>
     </property>
    </widget>
   </item>
   <item row="2" column="1">
    <widget class="QPushButton" name="pushButtonDivide">
     <property name="text">
      <string>/</string>
     </property>
    </widget>
   </item>
   <item row="2" column="2">
    <widget class="QPushButton" name="pushButtonEqual">
     <property name="text">
      <string>=</string>
     </property>
    </widget>
   </item>
   <item row="2" column="3">
    <widget class="QPushButton" name="pushButtonClear">
     <property name="text">
      <string>C</string>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
</ui>

按钮事件处理

为每个按钮设置点击事件,处理数字输入和运算符选择。

#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    connect(ui->pushButton0, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton1, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton2, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton3, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton4, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton5, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton6, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton7, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton8, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton9, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonPlus, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonMinus, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonMultiply, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonDivide, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonEqual, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonClear, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
}

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

void MainWindow::onPushButtonClicked() {
    QPushButton *button = qobject_cast<QPushButton*>(sender());
    if (button) {
        if (button->text() == "C") {
            ui->lineEditResult->setText("");
        } else {
            ui->lineEditResult->setText(ui->lineEditResult->text() + button->text());
        }
    }
}

计算逻辑

实现计算逻辑,根据用户输入的数字和运算符进行计算,并显示结果。

#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    connect(ui->pushButton0, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton1, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton2, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton3, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton4, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton5, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton6, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton7, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton8, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButton9, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonPlus, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonMinus, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonMultiply, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonDivide, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonEqual, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
    connect(ui->pushButtonClear, &QPushButton::clicked, this, &MainWindow::onPushButtonClicked);
}

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

void MainWindow::onPushButtonClicked() {
    QPushButton *button = qobject_cast<QPushButton*>(sender());
    if (button) {
        if (button->text() == "C") {
            ui->lineEditResult->setText("");
        } else if (button->text() == "=") {
            QString expression = ui->lineEditResult->text();
            QStack<QString> stack;
            QStack<QString> ops;
            QStringList tokens = expression.split(" ");

            for (const auto &token : tokens) {
                if (token == "+") {
                    if (!ops.isEmpty() && (ops.top() == "*" || ops.top() == "/")) {
                        QString op = ops.pop();
                        QString b = stack.pop();
                        QString a = stack.pop();
                        double result = 0;
                        if (op == "*") {
                            result = a.toDouble() * b.toDouble();
                        } else if (op == "/") {
                            result = a.toDouble() / b.toDouble();
                        }
                        stack.push(QString("%1").arg(result));
                    }
                    ops.push("+");
                } else if (token == "-") {
                    if (!ops.isEmpty() && (ops.top() == "*" || ops.top() == "/")) {
                        QString op = ops.pop();
                        QString b = stack.pop();
                        QString a = stack.pop();
                        double result = 0;
                        if (op == "*") {
                            result = a.toDouble() * b.toDouble();
                        } else if (op == "/") {
                            result = a.toDouble() / b.toDouble();
                        }
                        stack.push(QString("%1").arg(result));
                    }
                    ops.push("-");
                } else if (token == "*") {
                    ops.push("*");
                } else if (token == "/") {
                    ops.push("/");
                } else {
                    stack.push(token);
                }
            }

            while (!ops.isEmpty()) {
                QString op = ops.pop();
                QString b = stack.pop();
                QString a = stack.pop();
                double result = 0;
                if (op == "+") {
                    result = a.toDouble() + b.toDouble();
                } else if (op == "-") {
                    result = a.toDouble() - b.toDouble();
                } else if (op == "*") {
                    result = a.toDouble() * b.toDouble();
                } else if (op == "/") {
                    result = a.toDouble() / b.toDouble();
                }
                stack.push(QString("%1").arg(result));
            }

            ui->lineEditResult->setText(stack.pop());
        } else {
            ui->lineEditResult->setText(ui->lineEditResult->text() + button->text());
        }
    }
}
测试与调试应用
  1. 编译并运行项目。
  2. 测试各个功能模块,确保按钮操作和计算逻辑正确。
  3. 调试代码,解决发现的问题。

测试步骤

  1. 打开应用程序,点击数字按钮输入数字。
  2. 选择运算符进行运算。
  3. 点击等号按钮查看计算结果。
  4. 点击清除按钮清除输入。

调试

  1. 使用调试工具(如Qt Creator内置的调试器)定位错误。
  2. 通过日志输出辅助调试。
  3. 修复发现的问题,重新编译并测试。

通过以上步骤,可以完成一个简单的计算器应用程序的开发。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消