Skip to content

Commit 943b019

Browse files
committed
完成第四章“异步任务执行”这一节内容
1 parent 2eed216 commit 943b019

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

md/04同步操作.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,3 +1005,102 @@ void task(){
10051005
![进度条](../image/第四章/进度条.png)
10061006

10071007
在启动进度条后,能够正常点击“**测试**”按钮然后触发弹窗,就是没有问题,你也可以尝试不创建线程,那么界面将会卡主,你点击不了“**测试**”按钮,也移动不了这个窗口。
1008+
1009+
我们的项目是使用 visual studio 编写的,你可以直接安装 Qt 插件后使用它打开。此项目很小,为了简洁,所有的的界面与设置均是代码控制,而没有进行别的 ui 操作,也就是说,你只需要注意 `async_progress_bar.h`、`async_progress_bar.cpp`、`main.cpp` 这三个文件即可。它们存放在仓库以及目录 **`code`** 文件夹中。
1010+
1011+
```cpp
1012+
class async_progress_bar : public QMainWindow{
1013+
Q_OBJECT
1014+
1015+
public:
1016+
async_progress_bar(QWidget *parent = nullptr);
1017+
~async_progress_bar();
1018+
1019+
void task(){
1020+
future = std::async(std::launch::async, [=] {
1021+
QMetaObject::invokeMethod(this, [this] {
1022+
// 这里显示的线程 ID 就是主线程,代表这些任务就是在主线程,即 UI 线程执行
1023+
QMessageBox::information(nullptr, "线程ID", std::to_string(_Thrd_id()).c_str());
1024+
button->setEnabled(false);
1025+
progress_bar->setRange(0, 1000);
1026+
button->setText("正在执行...");
1027+
});
1028+
for (int i = 0; i <= 1000; ++i) {
1029+
std::this_thread::sleep_for(10ms);
1030+
QMetaObject::invokeMethod(this, [this, i] {
1031+
progress_bar->setValue(i);
1032+
});
1033+
}
1034+
QMetaObject::invokeMethod(this, [this] {
1035+
button->setText("start");
1036+
button->setEnabled(true);
1037+
});
1038+
// 不在 invokeMethod 中获取线程 ID,这里显示的是子线程的ID
1039+
auto s = std::to_string(_Thrd_id());
1040+
QMetaObject::invokeMethod(this, [=] {
1041+
QMessageBox::information(nullptr, "线程ID", s.c_str());
1042+
});
1043+
});
1044+
}
1045+
private:
1046+
QString progress_bar_style =
1047+
"QProgressBar {"
1048+
" border: 2px solid grey;"
1049+
" border-radius: 5px;"
1050+
" background-color: lightgrey;"
1051+
" text-align: center;" // 文本居中
1052+
" color: #000000;" // 文本颜色
1053+
"}"
1054+
"QProgressBar::chunk {"
1055+
" background-color: #7FFF00;"
1056+
" width: 10px;" // 设置每个进度块的宽度
1057+
" font: bold 14px;" // 设置进度条文本字体
1058+
"}";
1059+
QString button_style =
1060+
"QPushButton {"
1061+
" text-align: center;" // 文本居中
1062+
"}";
1063+
QProgressBar* progress_bar{};
1064+
QPushButton* button{};
1065+
QPushButton* button2{};
1066+
Ui::async_progress_barClass ui{};
1067+
std::future<void>future;
1068+
};
1069+
// 创建控件 设置布局、样式 连接信号
1070+
async_progress_bar::async_progress_bar(QWidget *parent)
1071+
: QMainWindow{ parent }, progress_bar{ new QProgressBar(this) },
1072+
button{ new QPushButton("start",this) },button2{ new QPushButton("测试",this) } {
1073+
ui.setupUi(this);
1074+
1075+
progress_bar->setStyleSheet(progress_bar_style);
1076+
progress_bar->setRange(0, 1000);
1077+
1078+
button->setMinimumSize(100, 50);
1079+
button->setMaximumWidth(100);
1080+
button->setStyleSheet(button_style);
1081+
button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
1082+
1083+
button2->setMinimumSize(100, 50);
1084+
button2->setMaximumWidth(100);
1085+
button2->setStyleSheet(button_style);
1086+
button2->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
1087+
1088+
QVBoxLayout* layout = new QVBoxLayout;
1089+
layout->addWidget(progress_bar);
1090+
layout->addWidget(button, 0, Qt::AlignHCenter);
1091+
layout->addWidget(button2, 0, Qt::AlignHCenter);
1092+
// 设置窗口布局为垂直布局管理器
1093+
centralWidget()->setLayout(layout);
1094+
1095+
connect(button, &QPushButton::clicked, this, &async_progress_bar::task);
1096+
connect(button2, &QPushButton::clicked, []{
1097+
QMessageBox::information(nullptr, "测试", "没有卡界面!");
1098+
});
1099+
}
1100+
```
1101+
1102+
为了展示 `QMetaObject::invokeMethod` 中的 lambda 是在主线程运行,我们打印了线程 ID,因为 C++11 的 `std::this_thread::get_id()` 返回的那个内部类型没办法直接转换为 `unsigned int`,我们就直接使用了 win32 的 API *`_Thrd_id()`* 了。如果您是 Linux 之类的环境,使用 [POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/) 接口 [*`pthread_self()`*](https://pubs.opengroup.org/onlinepubs/009696699/functions/pthread_self.html)。
1103+
1104+
这个例子其实很好的展示了多线程异步的作用,因为有 UI,所以很直观,毕竟如果你不用线程,那么不就卡界面了,用了就没事。
1105+
1106+
建议打开此项目自己编译运行,并尝试修改,如有必要,建议自己也写一遍,代码较为简单,就不再介绍了。

0 commit comments

Comments
 (0)