QT 界面编程中使用协程

QT 界面编程中使用协程

  • 一、概述
  • 二、集成
    • 2.1、编译 Acl
    • 2.2、将 Acl 库集成到 QT 项目中
    • 2.3、开始编写代码
      • 2.3.1、QT 程序初始化时初始化 Acl 协程
      • 2.3.2、在界面中创建协程
      • 2.3.3、界面程序退出前需要停止协程调度
      • 2.3.4、在界面线程中下载数据
      • 2.3.5、在协程中延迟创建窗口
    • 2.4、效果展示
    • 2.5、小结

一、概述

人们在谈论协程编程时,往往与编写命令行网络程序有关,如编写网络客户端与网络服务器程序,很少涉及到客户端 UI 相关的界面编程。Acl 协程库是支持在 Windows 下的 UI 界面编程的,因为 Acl 协程的事件引擎支持了界面消息传递过程。最近学习了一下 QT UI 编程,轻松将 Acl 协程与 QT UI 集成在一起,从而实现了 QT 界面协程化,使开发人员在使用 QT 编写界面程序时,编写网络模块变得非常简单。

本文结合 Acl 中 lib_fiber/samples-gui/QtFiber 示例,演示了如何将 Acl 协程功能集成到 QT 界面中,实现了网络模块与界面模块的融合。

二、集成

2.1、编译 Acl

目前 QT IDE 还无法直接使用 Acl 里的 CMakeLists.txt 文件编译 ACL,可以借助于 VC2019 打开 Acl 里的 acl_cpp_vc2019.sln 工程编译 Acl 五个库的动态库,分别为:lib_acl.dll, lib_protocol.dll, lib_acl_cpp.dll, libfiber.dll, libfiber_cpp.dll 及静态导出库:lib_acl.lib, lib_protocol.lib lib_acl_cpp.lib, libfiber.lib, libfiber_cpp.lib。

2.2、将 Acl 库集成到 QT 项目中

参考 lib_fiber/samples-gui/QtFiber/CMakeLists.txt 文件,将 Acl 库的头文件包含进去,如下:

set(acl_path ../../..)include_directories(${acl_path}/lib_acl/include${acl_path}/lib_acl_cpp/include${acl_path}/lib_fiber/c/include${acl_path}/lib_fiber/cpp/include
)

然后设定编译条件:

add_definitions("-DACL_DLL""-DACL_CPP_DLL""-DHTTP_DLL""-DICMP_DLL""-DSMTP_DLL""-DFIBER_CPP_DLL""-D_CRT_SECURE_NO_WARNINGS""-D_WINSOCK_DEPRECATED_NO_WARNINGS"
)

添加库到工程中,如下:

if (CMAKE_BUILD_TYPE STREQUAL "RELEASE")set(acl_libs_path ${CMAKE_CURRENT_SOURCE_DIR}/../../../x64/ReleaseDll)
else()set(acl_libs_path ${CMAKE_CURRENT_SOURCE_DIR}/../../../x64/DebugDll)
endif()set(lib_all ${acl_libs_path}/libfiber_cpp.lib${acl_libs_path}/lib_acl_cpp.lib${acl_libs_path}/lib_protocol.lib${acl_libs_path}/lib_acl.lib${acl_libs_path}/libfiber.lib)target_link_libraries(QtFiber PRIVATE Qt5::Widgets ${lib_all} Ws2_32)add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E copy_if_different"${acl_libs_path}/libfiber_cpp.dll""${acl_libs_path}/libfiber.dll""${acl_libs_path}/lib_acl_cpp.dll""${acl_libs_path}/lib_acl.dll""${acl_libs_path}/lib_protocol.dll"$<TARGET_FILE_DIR:${PROJECT_NAME}>
)

2.3、开始编写代码

经过摸索研究,想要集成 Acl 协程到 QT UI 程序中,需要采用以下方法(主要是协程的初始化及退出):

2.3.1、QT 程序初始化时初始化 Acl 协程

在调用 QT APP exec() 前,需要先调用 Acl 协程初始化过程,如下:

static void startupCallback() {acl::fiber::schedule_gui(); // Won't return until schedule finished.
}void main() {QApplication app(argc, argv);MainWindow w;w.show();QTimer::singleShot(0, startupCallback);app.exec();
}

可以看出,在调用 app.exec() 前注入了启动函数 startupCallback(),在里面启动了 acl 在界面模式下的协程调度过程 acl::fiber::schedule_gui(),该方法将进入界面消息循环过程,直到协程调度停止后才会返回。

2.3.2、在界面中创建协程

一旦协程调度器启动,就可以创建并运行协程了,可以在主界面上添加一个按钮,当点击该按钮后的处理函数中便可以创建并启动一个协程。比如在例子中,点击 “Start fiber server” 按钮,在处理函数 MainWindow::onStartServer() 中,可以创建一个网络监听服务器,如下:

void MainWindow::onStartServer() {...server_ = new fiber_server("127.0.0.1", 9001, this);server_->start();...
}

这样在界面里就创建了一个 TCP 监听协程,当有连接连接监听地址时,在监听协程里便可以创建一个客户端连接处理协程进行处理,如下:

    while (true) {SOCKET conn = socket_accept(sock);if (conn == INVALID_SOCKET) {break;}acl::fiber* fb = new fiber_echo(conn);fb->start();}

上面例子的客户端协程启动后,便可以进行网络 IO 读写,如下:

    char buf[8192];while (true) {int ret = acl_fiber_recv(conn_, buf, sizeof(buf) - 1, 0);if (ret == -1) {break;}buf[ret] = 0;if (acl_fiber_send(conn_, buf, ret, 0) != ret) {break;}}

2.3.3、界面程序退出前需要停止协程调度

必须保证在界面程序退出前停止协程调度器,否则界面程序无法正常退出,该步骤也非常重要。可以在主界面处理类里重载基类的 void closeEvent(QCloseEvent *event); 方法,在该方法里停止协程调度器,如下:

void MainWindow::closeEvent(QCloseEvent *event) {acl::fiber::schedule_stop(); // 停止协程调度器event->accept();             // 接受关闭事件
}

2.3.4、在界面线程中下载数据

点击主界面中点击HTTP下载按钮,在事件处理函数中创建协程从后端HTTP服务器下载数据,过程如下:

void MainWindow::onUrlGet() {...go[this] {const char *url = "http://www.baidu.com/";acl::http_request req(url);if (!req.request(nullptr, 0)) {printf("Send HTTP request failed\r\n");return;}acl::string body;if (!req.get_body(body)) {printf("Get HTTP body error\r\n");return;}qDebug() << "Got body:" << body.c_str();...};
}

2.3.5、在协程中延迟创建窗口

如果想某个窗口延迟创建,不必借助定时器,直接在协程中就可以轻松实现:

void MainWindow::delayCreate() {go[this] {acl::fiber::delay(5000); // 休眠 5 秒InputDialog dialog(this);dialog.exec();};qDebug() << "Fiber was created to create one window after a while";
}

2.4、效果展示

编译运行 acl/lib_fiber/samples-gui/QtFiber/ 工程,可以得到以下运行界面:
fiber-qt-ui 在前面窗口中,右边请求HTTP服务器时的HTTP请求头,右连接为后端服务器返回的HTTP响应头,该下载过程中在协程中进行,运行结果显示在主界面上;

  • 窗口下方的进度条为客户端协程与服务端协程交互时的交互进度展示。

2.5、小结

以上便是如何编译集成 Acl 协程到 QT 界面程序的方法,主要的要点是:

  • 需要使用 vc2019 编译 Acl 的动态库,并集成至 QT 界面程序的工程文件中;
  • 编程时需要注意:
    • 在启动 QT (即调用 app.exec())前,需要先启动 Acl 协程调度器;
    • 在主界面类里需要重载基类关闭虚方法 closeEvent(),并在该方法里停止 Acl 协程调度器;
    • 因为协程运行在界面的线程空间中,所以可以在协程中直接操作界面上的窗口对象,避免了线程之间的消息传递过程。

注: Acl库下载:https://github.com/acl-dev/acl/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/437248.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[sql-04] 连续出现至少三次的数字

数据准备 CREATE TABLE leecode_01 (id bigint not null AUTO_INCREMENT,num int DEFAULT NULL COMMENT 用户名,primary key(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT leecode(连续出现3次的数字)insert into leecode_01(num) values(12); insert into leecode_01…

C++入门基础 (超详解)

文章目录 前言1. C关键字2. C的第一个程序3. 命名空间3.1 namespace的定义3.2 命名空间的嵌套3.3 命名空间使用3.4 查找优先级总结 4. C输入和输出4.1 标准输入输出 (iostream库)4.2 文件输入输出 (fstream库)4.3 字符串流 (sstream库)4.4 C格式化输出4.5 std::endl和\n的区别 …

废物利用,三百块电脑如何升级并安装双系统便携使用

文章目录 引言最初的配置开始改装更换内存升级硬盘2.5 英寸 sata 固态msata 加装 升级电池其他的升级娱乐大师跑分 双系统安装前提条件设置 Bios安装 win 10安装 Manjaro时间同步问题 屏幕问题黑屏难开 引言 最近浏览 b 站的二手笔记本信息&#xff0c;想要整个二手笔记本玩玩…

imagickd写shell的技术学习

前言 没想到吧哥们&#xff0c;imagickd也能写shell&#xff0c;真是学到了不少&#xff0c;下面会具体分析是如何写shell的 基础知识 Imagick类 参考官方手册https://www.php.net/manual/zh/class.imagick.php 重点关注他的构造方法 (PECL imagick 2, PECL imagick 3) …

c++primer第十三章 类继承

本章内容&#xff1a;单个类就可以提供用于管理对话框的全部资源。通常&#xff0c;类库是以源代码的方式提供的&#xff0c;这意味着可以对其进行修改&#xff0c;以满足需求。但是&#xff0c;C-提供了比修改代码更好的方法来扩展和修改类。这种方法叫作类继承(class inheria…

手机/平板端 Wallpaper 动态壁纸文件获取及白嫖使用指南

Wallpaper 动态壁纸文件获取及使用指南 目录 壁纸文件获取手机 / 平板使用手机 / 平板效果预览注意事项PC/Mac 使用 1. 壁纸文件获取链接 链接&#xff1a;夸克网盘分享 复制链接到浏览器打开并转存下载即可。 &#xff08;主页往期视频的 4K 原图和 mpkg 动态壁纸文件&#xf…

Redis接口访问优化

说明&#xff1a;之前写过一篇使用Redis接口访问的博客&#xff0c;如下。最近有相关需求&#xff0c;把代码拿出来后&#xff0c;做了一些优化&#xff0c;挺有意思的&#xff0c;本文介绍在原基础上 使用Redis实现接口防抖 优化 总的来说&#xff0c;这次使用Redis实现接口…

IDEA 系列产品 下载

准备工作 下载 下载链接&#xff1a;https://www.123865.com/ps/EF7OTd-yVHnH 仅供参考 环境 演示环境&#xff1a; 操作系统&#xff1a;windows10 产品&#xff1a;IntelliJ IDEA 版本&#xff1a;2024.1.2 注意&#xff1a;如果需要其他产品或者版本可以自行下载&#xff0…

ESP32微信小程序SmartConfig配网

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 ESP32&微信小程序SmartConfig配网 前言一、SmartConfig是什么&#xff1f;二、使用乐鑫官方的smart_config例子1.运行照片 三、微信小程序总结 前言 本人是酷爱ESP32S3这…

C++系列-多态

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 多态 多态就是不同类型的对象&#xff0c;去做同一个行为&#xff0c;但是产生的结果是不同的。 比如说&#xff1a; 都是动物叫声&#xff0c;猫是喵喵&#xff0c;狗是汪汪&am…

LC记录二:丑数专题,一文秒解丑数3题

文章目录 263.丑数1264.丑数21201.丑数3 263.丑数1 https://leetcode.cn/problems/ugly-number/description/ 简单题&#xff0c;丑数只包含质因子2、3、5。所以直接使用 n 循环 除 2 3 5最后判断结果是否等于1即可。 代码&#xff1a; class Solution {public boolean isUg…

Java中的顺序控制、分支控制、嵌套分支if-else

if-else 顺序控制分支控制if-else单分支1.基本语法2.说明&#xff1a;3.案例说明4.流程图 双分支1.基本语法2.说明&#xff1a;3.案例说明4.流程图5.练习 多分支1.基本语法2.说明&#xff1a;3.流程图4.练习 嵌套分支1.基本介绍2.基本语法3.练习 顺序控制 1.介绍&#xff1a;程…

AntFlow-Vue3 :一个仿钉钉流程审批,且满足99.8%以上审批流程需求的企业级工作流平台,开源且免费!

在现代企业管理中&#xff0c;流程审批的高效性直接影响到工作的流畅度与生产力。最近&#xff0c;我发现了一个非常有趣的项目—— AntFlow-Vue3 。这个项目不仅提供了一个灵活且可定制的工作流平台&#xff0c;还能让用户以可视化的方式创建和管理审批流程。 如果你是一名前…

【Android 13源码分析】Activity生命周期之onCreate,onStart,onResume-1

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…

【Java 集合】List接口 —— ArrayList 与 LinkedList 详解

List接口继承自Collection接口&#xff0c;是单列集合的一个重要分支。 在List集合中允许出现重复的元素&#xff0c;所有的元素是以一种线性方式进行存储的&#xff0c;在程序中可以通过索引&#xff08;类似于数组中的元素角标&#xff09;来访问集合中的指定元素。另外&…

ESP32 Bluedroid 篇(1)—— ibeacon 广播

前言 前面我们已经了解了 ESP32 的 BLE 整体架构&#xff0c;现在我们开始实际学习一下Bluedroid 从机篇的广播和扫描。本文将会以 ble_ibeacon demo 为例子进行讲解&#xff0c;需要注意的一点是。ibeacon 分为两个部分&#xff0c;一个是作为广播者&#xff0c;一个是作为观…

时序数据库 TDengine 的入门体验和操作记录

时序数据库 TDengine 的学习和使用经验 什么是 TDengine &#xff1f;什么是时序数据 &#xff1f;使用RPM安装包部署默认的网络端口 TDengine 使用TDengine 命令行&#xff08;CLI&#xff09;taosBenchmark服务器内存需求删库跑路测试 使用体验文档纠错 什么是 TDengine &…

【框架篇】过滤器和拦截器的区别以及使用场景

在项目开发中&#xff0c;常常会同时配置拦截器&#xff08;Interceptor&#xff09;和过滤器&#xff08;Filter&#xff09;&#xff0c;以下就是它们两个主要的区别&#xff1a; 过滤器&#xff08;Filter&#xff09; 配置和实现 Filter的实现还是很简单的&#xff0c;可…

【Python语言初识(六)】

一、网络编程入门 1.1、TCP/IP模型 实现网络通信的基础是网络通信协议&#xff0c;这些协议通常是由互联网工程任务组 &#xff08;IETF&#xff09;制定的。所谓“协议”就是通信计算机双方必须共同遵从的一组约定&#xff0c;例如怎样建立连接、怎样互相识别等&#xff0c;…

k8s搭建一主三从的mysql8集群---无坑

一&#xff0c;环境准备 1.1 k8s集群服务器 ip角色系统主机名cpumem192.168.40.129mastercentos7.9k8smaster48192.168.40.130node1centos7.9k8snode148192.168.40.131node2centos7.9k8snode248192.168.40.132node3centos7.9k8snode348 k8s集群操作请参考《K8s安装部署&…