qt 进度条控件

目录

​编辑

1.概要

2.内容

1. QProgressBar(基础进度条)

基本用法

样式调整

2. QProgressDialog(带对话框的进度条)

基本用法

结合异步任务

3. 多线程安全更新

4. 常见问题

3.关联链接

4.关联知识

1.QProgressDialog举例

​编辑

关键点说明

扩展用法:结合异步任务

注意事项

2.QCoreApplication::processEvents

作用

使用场景

注意事项

完整示例

替代方案示例(多线程)

总结

1. Qt 事件循环的基本原理

2. 界面冻结的原因

3. processEvents() 的作用

4. 工作流程示例

5. 副作用与注意事项

6. 替代方案(推荐)

总结原理

3.QProgressDialog 定周期显示进度,并在进度完成后执行一个槽函数

实现步骤

完整代码示例

​编辑

关键点解释

扩展:结合真实任务

注意事项

封装成一个类 


1.概要

2.内容

在Qt中,进度条控件主要通过 QProgressBar 和 QProgressDialog 实现。以下是详细说明和示例:


1. QProgressBar(基础进度条)

用于显示简单进度,可嵌入窗口或对话框。

基本用法

// 创建进度条
QProgressBar *progressBar = new QProgressBar(this);
progressBar->setRange(0, 100);   // 设置范围(0-100)
progressBar->setValue(50);       // 设置当前值
progressBar->setTextVisible(true); // 显示百分比文本

// 连接信号(值变化时触发)
connect(progressBar, &QProgressBar::valueChanged, [](int value) {
    qDebug() << "当前进度:" << value << "%";
});
样式调整
  • 颜色:通过样式表修改
     

    progressBar->setStyleSheet(
        "QProgressBar { border: 2px solid grey; border-radius: 5px; }"
        "QProgressBar::chunk { background-color: #4CAF50; }"
    );
  • 方向
     

    progressBar->setOrientation(Qt::Vertical); // 垂直方向


2. QProgressDialog(带对话框的进度条)

用于长时间任务,自动显示进度对话框并支持取消操作。

基本用法

QProgressDialog progress("正在处理...", "取消", 0, 100, this);
progress.setWindowTitle("任务进度");
progress.setLabelText("正在处理文件...");
progress.setCancelButtonText("终止");

// 模拟任务循环
for (int i = 0; i <= 100; ++i) {
    progress.setValue(i);
    QThread::msleep(50); // 模拟耗时操作
    if (progress.wasCanceled()) {
        qDebug() << "用户取消了操作";
        break;
    }
}
结合异步任务

使用 QtConcurrent 实现非阻塞更新:

void MyClass::startTask() {
    QFuture<void> future = QtConcurrent::run([this]() {
        for (int i = 0; i <= 100; ++i) {
            QThread::msleep(50);
            emit updateProgress(i); // 发送信号更新进度
        }
    });

    QProgressDialog progress("处理中...", "取消", 0, 100, this);
    connect(&progress, &QProgressDialog::canceled, &future, &QFuture::cancel);
    
    while (!future.isCanceled() && !future.isFinished()) {
        progress.setValue(m_currentProgress); // 通过信号更新的值
        QCoreApplication::processEvents(); // 处理事件循环
    }
}

3. 多线程安全更新

在子线程中更新进度条需通过信号槽:

// 工作线程类
class Worker : public QObject {
    Q_OBJECT
public slots:
    void doWork() {
        for (int i = 0; i <= 100; ++i) {
            emit progressUpdated(i); // 发送进度信号
            QThread::msleep(50);
        }
    }
signals:
    void progressUpdated(int value);
};

// 主窗口连接信号
Worker *worker = new Worker;
QThread *thread = new QThread;
worker->moveToThread(thread);
connect(worker, &Worker::progressUpdated, progressBar, &QProgressBar::setValue);
thread->start();
QMetaObject::invokeMethod(worker, "doWork");

4. 常见问题

  • 进度条不显示:检查 setRange() 是否正确设置范围,确保 value() 在范围内。
  • 样式不生效:确认样式表语法正确,或使用 QProxyStyle 自定义样式。
  • 性能问题:频繁更新进度时,使用 QCoreApplication::processEvents() 确保界面响应。

通过上述方法,可以灵活实现进度条功能,适应不同场景需求。

3.关联链接

4.关联知识

1.QProgressDialog举例

以下是一个使用 QProgressDialog 的完整示例,包含详细注释和说明:

#include <QApplication>
#include <QProgressDialog>
#include <QThread>
#include <QDebug>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 创建进度对话框
    QProgressDialog progress("正在处理任务...", "取消", 0, 100);
    progress.setWindowTitle("任务进度");
    progress.setLabelText("正在处理文件,请稍候...");
    progress.setCancelButtonText("终止操作");
    progress.setMinimumDuration(0); // 立即显示,不等待

    // 模拟长时间任务(实际开发中替换为真实任务)
    for (int i = 0; i <= 100; ++i) {
        // 更新进度值
        progress.setValue(i);

        // 模拟耗时操作(例如:文件读写、网络请求等)
        QThread::msleep(50); // 暂停50毫秒

        // 检查用户是否点击取消
        if (progress.wasCanceled()) {
            qDebug() << "用户终止了操作!";
            break;
        }

        // 处理事件循环,确保界面响应
        QCoreApplication::processEvents();
    }

    // 任务完成后的提示
    if (!progress.wasCanceled()) {
        qDebug() << "任务完成!";
    }

    return app.exec();
}

关键点说明

  1. 初始化对话框

    QProgressDialog progress("正在处理任务...", "取消", 0, 100);
    • 第一个参数:对话框标签文本(显示进度下方)。
    • 第二个参数:取消按钮文本。
    • 第三、四个参数:进度范围(0到100)。
  2. 设置属性

    progress.setWindowTitle("任务进度"); // 窗口标题
    progress.setLabelText("正在处理文件..."); // 标签文本
    progress.setCancelButtonText("终止操作"); // 取消按钮文本
    progress.setMinimumDuration(0); // 立即显示,不等待
  3. 任务循环

    for (int i = 0; i <= 100; ++i) {
        progress.setValue(i);                    // 更新进度值
        QThread::msleep(50);                     // 模拟耗时操作
        if (progress.wasCanceled()) break;       // 检查取消
        QCoreApplication::processEvents();       // 保持界面响应
    }
  4. 取消处理

    • 用户点击取消后,wasCanceled() 返回 true
    • 需在循环中及时检查此状态以中断任务。

扩展用法:结合异步任务

若需在子线程中执行任务,可使用 QtConcurrent

#include <QtConcurrent>
#include <QFutureWatcher>

void startTask() {
    QProgressDialog progress("处理中...", "取消", 0, 100);
    
    // 使用QtConcurrent运行异步任务
    QFuture<void> future = QtConcurrent::run([&progress]() {
        for (int i = 0; i <= 100; ++i) {
            QThread::msleep(50);
            QMetaObject::invokeMethod(&progress, "setValue", Qt::QueuedConnection, Q_ARG(int, i));
            if (progress.wasCanceled()) break;
        }
    });

    // 连接取消信号
    QObject::connect(&progress, &QProgressDialog::canceled, &future, &QFuture::cancel);

    // 等待任务完成(非阻塞,需结合事件循环)
    while (!future.isFinished() && !future.isCanceled()) {
        QCoreApplication::processEvents();
    }
}

注意事项

  • 界面响应:在长时间循环中调用 QCoreApplication::processEvents() 以保持界面交互。
  • 线程安全:若任务在子线程中,需通过信号槽或 QMetaObject::invokeMethod 更新进度。
  • 取消逻辑:及时检查 wasCanceled() 以避免无效操作。

2.QCoreApplication::processEvents

QCoreApplication::processEvents() 是 Qt 中用于强制处理挂起事件的函数,常用于避免界面冻结。以下是详细说明和示例:


作用

  • 保持界面响应:在长时间循环或阻塞操作中,允许 Qt 处理用户输入、重绘界面等事件。
  • 避免界面冻结:替代直接阻塞主线程的方案(如 while(true) 循环)。

使用场景

  1. 耗时循环任务

    for (int i = 0; i < 100; ++i) {
        // 执行耗时操作(如计算、文件读写)
        doHeavyWork();
        
        // 更新进度条
        progressBar->setValue(i);
        
        // 处理事件,保持界面响应
        QCoreApplication::processEvents();
    }
  2. 等待异步操作完成

     

    for (int i = 0; i < 100; ++i) {
        // 执行耗时操作(如计算、文件读写)
        doHeavyWork();
        
        // 更新进度条
        progressBar->setValue(i);
        
        // 处理事件,保持界面响应
        QCoreApplication::processEvents();
    }

注意事项

  1. 性能影响
    • 频繁调用会降低性能(每次调用需遍历所有事件队列)。
    • 优化方法:在循环中减少调用频率,或在关键位置调用。
  2. 递归事件风险
    • 避免在事件处理函数(如按钮点击槽)中调用 processEvents(),可能导致递归触发。
  3. 替代方案
    • 多线程:将耗时任务移至子线程(推荐),避免阻塞主线程。
    • QTimer:拆分任务为小块,用定时器分步执行。

完整示例

#include <QApplication>
#include <QProgressDialog>
#include <QThread>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QProgressDialog progress("Processing...", "Cancel", 0, 100);
    progress.setMinimumDuration(0);

    // 模拟耗时任务
    for (int i = 0; i <= 100; ++i) {
        // 更新进度
        progress.setValue(i);

        // 模拟耗时操作(如文件处理)
        QThread::msleep(50);

        // 处理事件,保持界面响应
        QCoreApplication::processEvents();

        // 检查用户是否取消
        if (progress.wasCanceled()) {
            qDebug() << "Operation canceled by user!";
            break;
        }
    }

    return app.exec();
}

替代方案示例(多线程)

// 使用QtConcurrent运行异步任务
void startTask() {
    QProgressDialog progress("Processing...", "Cancel", 0, 100);
    
    QFuture<void> future = QtConcurrent::run([&progress]() {
        for (int i = 0; i <= 100; ++i) {
            QThread::msleep(50);
            QMetaObject::invokeMethod(&progress, "setValue", Qt::QueuedConnection, Q_ARG(int, i));
            if (progress.wasCanceled()) break;
        }
    });

    // 连接取消信号
    QObject::connect(&progress, &QProgressDialog::canceled, &future, &QFuture::cancel);

    // 等待任务完成(非阻塞)
    while (!future.isFinished() && !future.isCanceled()) {
        QCoreApplication::processEvents();
    }
}

总结

  • 何时使用:在无法避免阻塞主线程时(如快速原型开发)。
  • 何时避免:优先使用多线程或异步编程模型。
  • 关键点:平衡性能与响应性,避免滥用。

3.QCoreApplication::processEvents避免界面冻结的原理 

QCoreApplication::processEvents() 避免界面冻结的原理与 Qt 的事件循环机制密切相关。以下是分步解释:


1. Qt 事件循环的基本原理

  • 事件驱动模型:Qt 应用程序通过主线程的事件循环(Event Loop)运行。主线程不断监听事件队列(如用户输入、定时器、网络响应等),并依次处理。
  • 阻塞问题:如果主线程被长时间任务(如循环计算、文件读写)阻塞,它无法及时处理事件队列中的事件,导致界面无响应(冻结)。

2. 界面冻结的原因

  • 主线程被占用:当主线程忙于执行耗时操作时,事件队列中的事件(如重绘请求、用户点击)无法被及时处理。
  • 操作系统判定:如果应用程序长时间不响应事件,操作系统会标记其为“无响应”(如 Windows 的“程序未响应”对话框)。

3. processEvents() 的作用

  • 强制处理事件:调用 QCoreApplication::processEvents() 时,主线程会立即中断当前任务,遍历事件队列,处理所有挂起的事件(如重绘界面、响应用户输入)。
  • 插入事件处理机会:在耗时操作的循环中插入 processEvents(),确保主线程定期处理事件,保持界面响应。

4. 工作流程示例

假设有以下代码:

for (int i = 0; i < 100; ++i) {
    doHeavyWork();       // 耗时操作(如计算)
    progressBar->setValue(i); // 更新进度条
    QCoreApplication::processEvents(); // 关键调用
}
  • 步骤 1:执行 doHeavyWork(),主线程被阻塞。
  • 步骤 2:更新进度条的值,但界面尚未重绘。
  • 步骤 3:调用 processEvents(),主线程开始处理事件队列:
    • 处理界面重绘事件,更新进度条显示。
    • 处理用户输入事件(如点击按钮)。
    • 处理其他异步事件(如定时器、网络回调)。

5. 副作用与注意事项

  • 性能开销:频繁调用 processEvents() 会增加 CPU 负担,因为每次调用都要遍历事件队列。
  • 递归风险:如果在事件处理函数(如按钮点击槽)中调用 processEvents(),可能导致递归触发事件。
  • 临时方案processEvents() 是避免界面冻结的“权宜之计”,长期方案应使用多线程或异步编程。

6. 替代方案(推荐)

  • 多线程:将耗时任务移至子线程(如 QThread 或 QtConcurrent),主线程保持空闲处理事件。
  • 异步操作:使用 QTimer 分步执行任务,或利用信号槽机制实现非阻塞更新。

总结原理

QCoreApplication::processEvents() 通过强制主线程立即处理事件队列中的挂起事件,确保即使主线程被长时间任务阻塞,界面仍能响应操作。其核心是“在阻塞任务中插入事件处理机会”,从而避免界面冻结。尽管有效,但应优先考虑多线程或异步设计以提高性能和代码健壮性。

3.QProgressDialog 定周期显示进度,并在进度完成后执行一个槽函数

以下是使用 QProgressDialog 定期更新进度,并在完成后执行槽函数的示例代码和分步说明:


实现步骤

  1. 创建进度对话框:设置范围、标题和取消按钮。
  2. 模拟耗时任务:用 QTimer 定期更新进度值。
  3. 处理完成事件:进度达到最大值时触发槽函数。
  4. 支持用户取消:检查取消状态并执行相应操作。

完整代码示例

 

#include <QApplication>
#include <QProgressDialog>
#include <QTimer>
#include <QDebug>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 1. 创建进度对话框
    QProgressDialog progress("Processing...", "Cancel", 0, 100);
    progress.setMinimumDuration(0); // 立即显示,无需等待
    progress.setWindowTitle("Task Progress");

    // 2. 定义完成后的槽函数
    QObject::connect(&progress, &QProgressDialog::finished, [](int result) {
        if (result == QDialog::Accepted) {
            qDebug() << "Task completed successfully!";
            // 在这里执行完成后的操作(如保存文件、提示用户)
        } else {
            qDebug() << "Task canceled by user.";
        }
    });

    // 3. 模拟耗时任务(用定时器更新进度)
    QTimer timer;
    int progressValue = 0;
    QObject::connect(&timer, &QTimer::timeout, [&]() {
        if (progress.wasCanceled()) {
            timer.stop();
            return;
        }

        progressValue++;
        progress.setValue(progressValue);

        // 模拟任务完成条件
        if (progressValue >= 100) {
            timer.stop();
            progress.setValue(100);
            // 触发完成信号(自动关闭对话框)
            progress.done(QDialog::Accepted);
        }
    });

    // 启动定时器(每100ms更新一次)
    timer.start(100);

    // 4. 进入事件循环
    return app.exec();
}

关键点解释

  1. 进度对话框初始化
    • QProgressDialog 设置范围为 0-100,标题为“Processing...”,取消按钮文本为“Cancel”。
    • setMinimumDuration(0) 确保对话框立即显示,无需等待延迟。
  2. 完成后的槽函数
    • 连接 finished(int) 信号到 Lambda 表达式。
    • 通过 result 参数判断用户是否取消操作(QDialog::Rejected)。
  3. 模拟任务更新
    • 使用 QTimer 每 100ms 增加进度值。
    • 检查 wasCanceled(),若用户点击取消则停止定时器。
    • 当进度达到 100 时,停止定时器并调用 done(QDialog::Accepted) 触发完成信号。
  4. 自动关闭机制
    • QProgressDialog 在调用 setValue(100) 或 done() 时会自动关闭。
    • 通过 finished 信号传递结果(成功或取消)。

扩展:结合真实任务

若需处理真实任务(如文件读取),可将任务移至子线程:

// 使用 QtConcurrent 在子线程中执行任务
void startTask() {
    QProgressDialog progress("Processing...", "Cancel", 0, 100);
    progress.setMinimumDuration(0);

    // 连接完成信号
    QObject::connect(&progress, &QProgressDialog::finished, [](int result) {
        if (result == QDialog::Accepted) {
            qDebug() << "Real task completed!";
        }
    });

    // 在子线程中执行耗时操作
    QFuture<void> future = QtConcurrent::run([&progress]() {
        for (int i = 0; i <= 100; ++i) {
            QThread::msleep(50); // 模拟耗时操作
            QMetaObject::invokeMethod(&progress, "setValue", Qt::QueuedConnection, Q_ARG(int, i));
            if (progress.wasCanceled()) break;
        }
    });

    // 等待任务完成(非阻塞)
    while (!future.isFinished() && !future.isCanceled()) {
        QCoreApplication::processEvents();
    }
}

注意事项

  • 性能优化:避免在主线程中执行阻塞操作,优先使用多线程。
  • 进度更新频率:根据任务复杂度调整定时器间隔(如 100ms vs 500ms)。
  • 取消处理:及时检查 wasCanceled() 以响应用户操作。

封装成一个类 

以下是将进度功能封装成类并支持外部槽函数链接的实现:

#include <QObject>
#include <QProgressDialog>
#include <QTimer>

class ProgressWorker : public QObject
{
    Q_OBJECT
public:
    explicit ProgressWorker(QObject* parent = nullptr)
        : QObject(parent), m_progress(nullptr), m_timer(nullptr), m_value(0)
    {
        // 初始化进度对话框
        m_progress = new QProgressDialog("Processing...", "Cancel", 0, 100, this);
        m_progress->setMinimumDuration(0);  // 立即显示
        m_progress->setWindowTitle("Task Progress");

        // 初始化定时器
        m_timer = new QTimer(this);
        connect(m_timer, &QTimer::timeout, this, &ProgressWorker::updateProgress);

        // 连接对话框完成信号
        connect(m_progress, &QProgressDialog::finished,
                this, &ProgressWorker::handleCompletion);
    }

    // 设置进度范围
    void setRange(int min, int max) {
        m_progress->setRange(min, max);
    }

    // 设置对话框标题
    void setWindowTitle(const QString& title) {
        m_progress->setWindowTitle(title);
    }

    // 设置标签文本
    void setLabelText(const QString& text) {
        m_progress->setLabelText(text);
    }

    // 设置取消按钮文本
    void setCancelButtonText(const QString& text) {
        m_progress->setCancelButtonText(text);
    }

    // 启动进度更新
    void start() {
        m_value = 0;
        m_progress->setValue(0);
        m_progress->show();
        m_timer->start(100);  // 每100ms更新一次
    }

signals:
    // 任务完成信号(参数:是否被取消)
    void taskCompleted(bool canceled);

private slots:
    void updateProgress() {
        if (m_progress->wasCanceled()) {
            m_timer->stop();
            return;
        }

        // 更新进度值
        m_value++;
        m_progress->setValue(m_value);

        // 检查是否完成
        if (m_value >= m_progress->maximum()) {
            m_timer->stop();
            m_progress->setValue(m_progress->maximum());
            m_progress->done(QDialog::Accepted);
        }
    }

    void handleCompletion(int result) {
        bool canceled = (result == QDialog::Rejected);
        emit taskCompleted(canceled);
    }

private:
    QProgressDialog* m_progress;
    QTimer* m_timer;
    int m_value;
};

使用示例:

 

// 创建进度工作器
ProgressWorker* worker = new ProgressWorker;

// 配置参数
worker->setWindowTitle("Data Import");
worker->setLabelText("Importing data...");
worker->setCancelButtonText("Stop");
worker->setRange(0, 100);

// 连接完成信号到外部槽函数
QObject::connect(worker, &ProgressWorker::taskCompleted,
                 [](bool canceled) {
                     if (!canceled) {
                         qDebug() << "Data import completed!";
                         // 在这里执行完成后的操作
                     } else {
                         qDebug() << "Import canceled by user.";
                     }
                 });

// 启动进度更新
worker->start();

// ... 其他代码 ...

// 注意:确保worker对象生命周期有效(可使用智能指针或父对象管理)

关键点说明:

  1. 封装性
    • 所有进度相关操作封装在ProgressWorker类中
    • 提供配置接口:设置范围、标题、按钮文本等
    • 通过start()方法启动进度更新
  2. 信号机制
    • 定义taskCompleted(bool)信号,携带取消状态
    • 外部可通过QObject::connect链接自定义槽函数
  3. 进度模拟
    • 使用QTimer每100ms自动增加进度值
    • 到达最大值时自动关闭对话框
  4. 取消处理
    • 用户点击取消按钮时停止定时器
    • 通过wasCanceled()检测取消状态
  5. 扩展性
    • 可修改updateProgress()方法实现真实任务逻辑
    • 支持通过多线程处理耗时任务(需添加线程安全更新)

扩展建议:

  1. 添加暂停/恢复功能

    void pause() { m_timer->stop(); }
    void resume() { m_timer->start(); }

  2. 支持自定义更新间隔

    void setInterval(int msec) { m_timer->setInterval(msec); }
  3. 添加进度文本更新

    void setProgressText(const QString& text) {
        m_progress->setLabelText(text);
    }
  4. 支持真实任务(使用多线程):

    void startWithTask(std::function<void()> task) {
        // 使用QtConcurrent在子线程执行任务
        QFuture<void> future = QtConcurrent::run([this, task]() {
            task();  // 执行实际任务
            QMetaObject::invokeMethod(this, "completeTask");
        });
    }

这个实现提供了良好的封装性和扩展性,可根据具体需求进行功能扩展。

4.QProgressBar举例 

以下是一个使用C++和Qt框架的QProgressBar简单示例,演示如何创建并更新进度条:

 

#include <QApplication>
#include <QMainWindow>
#include <QProgressBar>
#include <QTimer>
#include <QVBoxLayout>
#include <QMessageBox>

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
        // 创建进度条
        progressBar = new QProgressBar(this);
        progressBar->setRange(0, 100);    // 设置范围0-100
        progressBar->setValue(0);         // 初始值0
        progressBar->setFormat("%p%");    // 显示百分比格式
        progressBar->setTextVisible(true); // 显示文本

        // 创建定时器模拟进度更新
        timer = new QTimer(this);
        connect(timer, &QTimer::timeout, this, &MainWindow::updateProgress);

        // 设置窗口布局
        QVBoxLayout *layout = new QVBoxLayout;
        layout->addWidget(progressBar);

        QWidget *centralWidget = new QWidget;
        centralWidget->setLayout(layout);
        setCentralWidget(centralWidget);

        // 启动定时器(每100毫秒更新一次)
        timer->start(100);
    }

private slots:
    void updateProgress() {
        int value = progressBar->value() + 1;
        progressBar->setValue(value);

        // 进度完成时停止定时器并提示
        if (value >= progressBar->maximum()) {
            timer->stop();
            QMessageBox::information(this, "完成", "任务已完成!");
        }
    }

private:
    QProgressBar *progressBar;
    QTimer *timer;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    MainWindow window;
    window.setWindowTitle("QProgressBar示例");
    window.resize(300, 100);
    window.show();

    return app.exec();
}

#include "main.moc"

关键点说明:

  1. 创建进度条
    • setRange(0, 100) 设置进度范围为0到100
    • setValue(0) 设置初始值为0
    • setFormat("%p%") 显示百分比格式(如"50%")
    • setTextVisible(true) 显示进度文本
  2. 使用定时器模拟进度更新
    • QTimer 每100毫秒触发一次timeout信号
    • 通过connect将定时器信号连接到updateProgress槽函数
  3. 更新进度逻辑
    • 每次增加1个进度值
    • 当达到最大值时停止定时器并弹出提示框
  4. 窗口布局
    • 使用QVBoxLayout垂直布局管理进度条
    • 设置主窗口的中心部件

编译运行后,你会看到一个逐渐增长的进度条,从0%增长到100%后弹出完成提示。

扩展功能建议:

  • 使用多线程处理真实任务(如文件复制)
  • 添加暂停/继续按钮
  • 自定义进度条样式(颜色、形状等)
  • 支持不确定模式(setIndeterminate(true)
  • 添加进度文字提示(progressBar->setFormat("处理中: %p%")

要编译此程序,需要:

  1. 安装Qt开发环境
  2. 将代码保存为main.cpp
  3. 使用qmake或CMake生成项目文件
  4. 编译运行

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值