Qt --- 系统相关---事件、文件操作、多线程编程、网络编程、多媒体

news2024/11/18 17:22:10

虽然Qt是跨平台的C++开发框架,Qt的很多能力其实是操作系统提供的。只不过Qt封装了系统API。程序是运行在操作系统上的,需要系统给我们提供支撑。

事件、文件操作、多线程编程、网络编程、多媒体(音频、视频)。

一、事件

信号槽,用户进行的各种操作,就可能会产生信号,可以给某个信号指定槽函数,当信号触发时,就能够自动的执行到对应的槽函数。

事件也是非常类似的,用户进行的各种操作,也会产生事件,程序员同样可以给事件关联上处理函数(处理的逻辑)当事件触发的时候,就能够执行到对应的代码。

事件本身是操作系统提供的机制,Qt也同样把操作系统事件机制进行了封装,拿到了Qt中。但是由于事件对应的代码编写起来不是很方便,Qt对于事件机制又进行了进一步的封装,就得到了信号槽。信号槽就是对于事件的进一步封装。事件是信号槽的底层机制。实际Qt开发程序过程中,绝大部分和用户之间进行的交互都是通过“信号槽”来完成的,有些特殊情况下,信号槽不一定能搞定(某个用户的动作行为,Qt没有提供对应的信号……)此时就需要通过重写事件处理函数的形式,来手动处理事件的响应逻辑。开发事件机制给咱们程序员,咱们就可以根据实际的需要进行更深度的定制化diy操作了。

用户进行了很多操作,就会产生很多的事件(当然也会产生很多的信号)

子类代表各种具体的事件。不同场景下,要关注的点是不一样,这些事件的子类中就会包含一些对应的不同属性。

 事件的处理

 让一段代码和某个事件关联起来,当事件触发的时候,就能指定到这段代码,之前信号槽这里通过connect来完成上述关联的。对于事件来说,还不太一样。

让当前的类,重写某个事件处理函数。这里用到的是多态机制。创建子类继承自Qt已有的类。在子类中重写父类的事件处理函数。后续事件触发过程中,就会通过多态这样的机制。执行到咱们自己写的子类的函数中。

处理一下鼠标进入和鼠标离开的事件。enterEvent和leaveEvent。

代码:这里需要创建QLabel的子类重写enterEvent和leaveEvent

上述代码虽然重写了这两函数,但是还有点问题。当前在界面上创建的这个lable是一个咱们自己定义的Label类的实例。才会执行到。我们可以提升类。

一定要确保你的类名以及头文件的名字和上述自定义的类名头文件都匹配。通过提升为这样的方式,就可以把Qt Designer中拖上去的控件的类型,转换成自定义的控件类型。

给女神表白的程序,鼠标一进去按钮就跑了。可以自己试着实现一下。

代码:

处理鼠标事件

通过事件获取到鼠标点击的位置

mousePressEvent这个函数,按下左键,右键,滚轮都能触发。有的鼠标还带有前进后退侧键。也是可以触发。但是还有的鼠标,有更多的按键,更多的按键就不一定了。

mouseReleaseEvent释放鼠标事件

像clicked这样的信号,就相当于一次按下和释放事件。

mouseDoubleClickEvent双击鼠标事件

比如有的程序,可能是单击有一些逻辑,双击有另一些逻辑。如果我们没注意,可能双击操作就能触发单机的逻辑,可能就有bug

mouseMoveEvent移动鼠标事件

刚才重写鼠标事件的操作,都是在自定义的Label中完成的,此时鼠标只有在Label范围内进行动作的时候,才能捕获到。

也可以把这些操作直接放到Widget(QWidget子类)来完成,这样的化,鼠标在整个窗口中进行各种动作都能获取到了。

鼠标移动不同于鼠标按下,随便移动一下鼠标,就会产生出大量的鼠标移动事件,当你进行捕获事件的时候,尤其是在这里再进行一些复杂逻辑的时候,程序负担就很重,很容易产生卡顿之类的情况。Qt为了保证程序的流畅性。默认情况下不会对鼠标移动进行追踪,鼠标移动的时候不会调用mouseMoveEvent,除非显示告诉Qt就要追踪鼠标的位置。可以使用setMouseTracing函数设为true。

WheelEvent鼠标滚轮的滚轮动作

代码:

处理键盘事件

QShortCut 这是信号槽机制封装过,获取键盘按键的方式。站在更底层的角度,也可以通过事件获取当前用户键盘按下的情况 

keyPressEvent(QKeyEvent*); 看你捕获键盘按键是在哪个控件的范围内。

如果组合键呢,把这些用来搭配组合键的功能键,单独拎出来了,modifiers(修饰符)。

定时器事件

QTimer实现了定时器功能。再QTimer背后是QTimerEvent定时器事件进行支撑的。QObject提供了一个timerEvent这个函数。搭配startTimer启动定时器和killTimer关闭定时器。

代码:

使用timeEvent比QTimer还是要更复杂一些。需要手动管理timerId,还需要区分这次函数调用是哪个timer引起的。后续实际开发中,还是使用QTimer即可。

窗口移动和大小改变事件

moveEvent窗口移动时触发的事件

resizeEvent窗口大小改变时触发的事件

事件分发/事件过滤属于Qt事件机制背后的一些逻辑,Qt也把这部分内容提供了一些API让程序员有更多的可操作空间。重写event函数,直接获取到所有的事件。杀伤力比较广,不当使用可能对现有的逻辑(现有的事件体系造成一些负面影响)。

二、文件

C语言中,fopen打开文件,fread fwrite读写文件,fclose关闭文件。C++中,fstream打开文件,<< >> 读写文件。close关闭文件。Linux中,open打开文件,read,write读写文件。close关闭文件。系统调用一般开发的时候很少会直接使用,主要时理解文件操作背后的原理。

Qt也提供了一套文件操作。Qt中使用上述的集中方案来读写文件,也是完全可以的(Linux这一套,局限于Linux系统,Windows上的Qt就需要使用Windows API)。但Qt还是又封装了一套。Qt诞生的太早了,C++还没有标准化的概念。咱们在编写Qt程序的时候,更推荐使用Qt自己提供的这一套文件操作,可以和QString和Qt内置的类可以很好的配合。

Qt中的文件操作,核心操作也是这几个部分,打开,读,写,关闭。

QFile类,完成上述文件操作。

QTemporaryFile这个对象销毁,对应的文件就自动删除了。要写入大量的数据,写文件的时候,往往会把旧的文件先清空,再写。万一新的数据写一半,结果出错了,新的数据用不了,旧的数据也无了。如果你要想写一个文件,会自动的把内容先写到临时文件里(不会破坏原有的文件),等到所有内容写完了之后,再把旧文件自动删掉。并且用新的文件替换旧的文件

QFile类的使用

1、打开 open

2、读 read/readline/readall

QByteArray很方便的转成QString

3、写 write

4、关闭 close

关闭本质上是要释放文件描述符表中的表项。文件描述符表存在上限,如果一直打开,不关闭的话就可能会使文件描述符表被占满,后续再尝试打开,就打开不了了。

代码:

QString text = file.readAll()。

需要确保打开的文件是一个文本文件才可以,如果是二进制文件,交给QString就不合适了。

QFileInfo的使用

它可以获取到Qt的文件的相关属性,类似于这样的功能,在C/C++标准库本来是没有的所以要想使用类似的功能往往要使用系统api。C++17引入了模块,filesystem。

代码:

三、Qt多线程

Qt多线程和Linux中的线程本质是一个东西。

Qt中的多线程的API,Linux中学过的多线程API,Linux系统提供的pthread库。Qt中针对系统提供的线程API重新封装了。C++11中,也引入了线程std::thread。Qt中的多线程API,还要更好一点,其实参考了Java中的线程库API 的设计方式。

QThread要想创建线程,就需要创建这样类的实列。创建线程的时候,需要重点指定线程的入口函数,创建一个QThread的子类,重写其中的run函数,起到指定入口函数的方式(多态)。

start这个操作就是真正调用系统API创建线程。新的线程创建出来之后自然就会自动的执行run函数。

代码:之前基于定时器,写过倒计时这样的程序。也可以通过线程,来完成类似的功能。定时器内部本质上也是可以基于多线程来实现的。

由于存在线程安全问题。多个线程同时对于界面的状态进行修改,此时就会导致界面就出错了。Qt选择了一刀切,针对界面的空间状态进行任何修改,务必在主线程中执行。 

QThread应用场景

之前学习多线程,主要还是站在服务器开发的角度来看待的。当时谈到的多线程,最主要的目的,是为了充分利用多核CPU的计算资源。双路CPU(一个主板上面有两个CPU)在客服端多线程仍然有意义,侧重点不同了。相比之下,客户端中的多线程主要是用于通过多线程的方式,执行一些耗时的等待IO的操作,避免主线程被卡死,避免对用户造成一些不好的体验。客户端经常会和服务器进行网络通信,比如客户端要上传/下载一个很大的文件,传输需要消耗好久。密集的IO操作。这种密集IO就会使程序被系统阻塞,挂起。一旦进程被挂起了,此时意味着用户进行的各种操作,程序就无法响应。因此相比之下更好的做法,使用单独的线程,来处理这种密集的IO操作,要挂起也是挂起这个新的线程,主线程要负责事件循环,负责处理用户的各种操作。此时主线程仍然可以继续工作,继续响应用户的各种操作。

Qt中的锁

线程安全问题,多线程程序太复杂了。加锁 把多个线程要访问的公共资源,通过锁保护起来 =》把并发执行编程串行执行。Linux中mutex为互斥量。C++11引入了std::mutex。Qt同样也提供了对应的锁,来针对系统提供的锁进行封装。QMutex lock方法加锁,unlock解锁。

代码:

注意这里的锁需要使用static进行修饰,否则两个线程访问到的就不是同一个锁的资源。就无法起到互斥的作用。

这里的锁很容易忘记释放,忘记unlock,实际开发中,加锁之后,设计到的逻辑可能很复杂。下面很容易就忘记释放锁。C++中引入智能指针来解决上述问题的。C++11引入了std::lock_guard相当于是std::mutex的智能指针,借助RAII机制。

上述机制Qt也继承过来了。QMutexLocker

Qt的锁和C++标准库中的锁,本质上都是封装的系统提供的锁。编写多线程程序的时候,可以使用Qt的锁,也可以使用Qt的锁,也可以使用C++的锁。C++的锁能不能锁Qt的线程,也是可以的。虽然混着用也行,一般不建议。还提供了读写锁的问题。

条件变量和信号量

条件变量和信号量,和Linux中谈到的条件变量和信号量完全一致。多个线程之间的调度是无序的,为了能够一定程度的干预线程之间的执行顺序,引入条件变量,QWaitConditon,wait,wake,wakeAll,mutex.lock();wait中就会先释放锁 + 等待。要想释放锁,前提就是先获取到锁。

这里要使用while判定而不是if,唤醒之后需要再确认一下,当前条件是否真的成立了,wait可能被提前唤醒(可能被信号打断了)

信号量,其实还可以进行进程之间的控制,当然也同样可以作为同一个进程内部的线程之间通信方式。计数器,描述了可用资源的个数。QSemaphore semaphore(2),

分别代表PV操作。

四、网络编程

Qt网络编程,网络编程操作系统提供的一组提供API(Socket API)C++标准库中,并没有提供网络编程的api的封装。进行网络编程的时候,本质上是在编写应用层代码,需要传输层提供支持。Qt提供了两套API,UDP和TCP。使用Qt网络编程的API,需要现在.pro文件中添加network模块。之前学过的Qt的各种控件,各种内容,都是包含在QtCore模块中(已经添加到.pro文件中Q)。

为什么Qt要划分出这些模块呢?

Qt本身是一个非常庞大,包罗万象的框架。如果把所有的Qt的功能放到一起,即使咱们就只是写一个简单的hello world,此时生成的可执行程序也会非常庞大。所以我们进行了模块化处理,其他的功能分别封装成不同的模块,默认情况下这些额外的模块不会参与编译。需要在.pro文件中,引入对应的模块,才能把对应功能给编译加载进来。

Qt其实提供了静态库的版本和动态库的版本。

UDPSocket

当socket收到请求的时候,QUdpSocket就会触发这个信号,此时可以在槽函数里完成读取请求的操作了。基于信号槽,就天然达成了事件驱动这样的一种网络编程方式。

代码:写一个带有界面的Udp回显服务器,Qt也是完全可以编写控制台程序的。

server

client

quint16 端口号本质上是一个2字节的无符号整数。本质上就是一个unsigned short。虽然short通常都是2个字节,但是C++标准中没有明确规定这一点,只是说short不应该少于2个字节。所以为了规避这个问题,Qt中引入了quint16这样的类型。

 

TCPSocket

TCP有连接,可靠传输,面向字节流,全双工。因此TCP的代码,要比UDP的代码要复杂。

事件循环: 简单理解,可以认为是Qt程序内部,带有一个生物钟这样的东西,周期性的执行一些逻辑。

代码:TCP回显服务器

server

 上述代码其实不够严谨,作为回显服务器是已经够了的。实际使用TCP的过程中,TCP是面向字节流的。一个完整的请求,可能会分成多段字节数组进行传输,这就会导致上层读取不完整的报文,从而导致了粘包问题。

释放文件描述符

client

之前在学习Linux时写的TCP的回显服务器的时候,遇到了问题,多个客户端同时访问的时候就只有一个生效,后来引入了多线程,每个客户端安排一个单独的线程,问题才得到改善。之前写的那个程序,之所以出现上述问题,和TCP,多线程都没啥关系,从来没有说TCP服务器必须使用多线程编写,之前存在那个问题的本质原因是写双重循环,里层循环没有即使结束,导致外层循环不能快速的第二次调用到accept,导致第二个客户端无法进行处理了。引入多线程,本质上就是把双重循环,化简成两个独立的循环。咱们Qt的服务器程序中,其实一个循环也没有写,是通过Qt内置的信号槽机制来驱动的。一个正经的TCP服务器,不太可能会用Qt来写,服务器一般都是不需要图形界面的。

HTTP客户端

HTTP使用比TCP/UDP更多一些。Qt中也提供了HTTP的客户端。HTTP协议本质上也就是基于TCP协议实现的。实现一个HTTP客户端/服务器,本质上也就是基于TCP Socket进行封装的。

Qt只是提供了HTTP客户端,而没有提供HTTP服务器的库。

 代码:

 实际开发中,HTTP Client获取到的数据,也不一定是HTML,更大的可能性是客户端开发和服务器开发约定好交互的数据格式,按照约定的格式,客户端拿到之后,进行解析,并显示到界面上。

五、多媒体操作

播放声音

需要先引入multimedia模块。需要使用到QSound类,play()来进行播放。只能播放.wav格式的音频文件。

代码:

小结:

1、Qt事件机制

2、文件操作

3、多线程

4、网络编程

5、多媒体

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数学期望专题

9.29 - 10.6 更新时间约持续一周 优惠券 Coupons 题目链接&#xff1a;优惠券 Coupons 假设我们某个情况下&#xff0c;我们已经有了 k 种图案&#xff0c;在这个条件下&#xff0c;获得一个新图案需要 天&#xff0c;那我们要求的就是 。由于已经有了 k 种图案&#xff0c…

【热门主题】000002 案例 JavaScript网页设计案例

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

技术速递|Java on Azure Tooling 8月更新 - Java 体验在 Azure 容器应用程序正式发布

作者&#xff1a;Jialuo Gan 排版&#xff1a;Alan Wang 大家好&#xff0c;欢迎阅读 Java on Azure 开发者工具8月份更新。在本次更新中&#xff0c;我们将介绍在 IntelliJ IDEA 中 Azure Toolkit 对 Azure App Service 提供托管身份支持&#xff08;Managed Identity&#xf…

AIGC教程:如何用Stable Diffusion+ControlNet做角色设计?

前言 对于生成型AI的画图能力&#xff0c;尤其是AI画美女的能力&#xff0c;相信同行们已经有了充分的了解。然而&#xff0c;对于游戏开发者而言&#xff0c;仅仅是漂亮的二维图片实际上很难直接用于角色设计&#xff0c;因为&#xff0c;除了设计风格之外&#xff0c;角色设…

class 029 重要排序算法的总结

这篇文章是看了“左程云”老师在b站上的讲解之后写的, 自己感觉已经能理解了, 所以就将整个过程写下来了。 这个是“左程云”老师个人空间的b站的链接, 数据结构与算法讲的很好很好, 希望大家可以多多支持左程云老师, 真心推荐. https://space.bilibili.com/8888480?spm_id_f…

Springboot+PostgreSQL+MybatisPlus存储JSON或List、数组(Array)数据

项目架构 SpringbootPostgreSQLMybatisPlus 从Mongodb转过来的项目&#xff0c;有存储json数据的需求&#xff0c;但是在mybatis-plus上会出点问题 报错&#xff1a; Error updating database. Cause: org.postgresql.util.PSQLException 字段 “” 的类型为 jsonb, 但表达式的…

Junit和枚举ENUM

断言机制&#xff0c;JAVA中的断言机制是一种用于检查程序中某个条件是否为真的机制。它可以在程序运行时检查某个条件是否满足&#xff0c;如果不满足则会抛出AssertionError异常。 在java中,断言机制默认是关闭的。所以会输出u。 断言机制只是为了用来吃调试程序的&#xff0…

【设计模式-中介者模式】

定义 中介者模式&#xff08;Mediator Pattern&#xff09;是一种行为设计模式&#xff0c;通过引入一个中介者对象&#xff0c;来降低多个对象之间的直接交互&#xff0c;从而减少它们之间的耦合度。中介者充当不同对象之间的协调者&#xff0c;使得对象之间的通信变得简单且…

fiddler抓包13_响应后断点 - 篡改响应

课程大纲 原理 响应后断点&#xff08;After Response Breakpoint&#xff09;&#xff1a;Fiddler拦截、篡改服务器返回的响应&#xff0c;再返回给客户端。 应用场景 1.分析服务器响应数据 2.测试前端对特定返回的处理、展示 3.模拟网络中断、不稳定场景 单个断点 VS 全局…

信息安全数学基础(22)素数模的同余式

前言 信息安全数学基础中的素数模的同余式是数论中的一个重要概念&#xff0c;它涉及到了素数、模运算以及同余关系等多个方面。 一、基本概念 素数&#xff1a;素数是指只能被1和它本身整除的大于1的自然数。素数在密码学中有着广泛的应用&#xff0c;如RSA加密算法就依赖于大…

2024年企业博客SEO趋势与策略

随着互联网的快速发展和搜索引擎算法的不断演进&#xff0c;企业博客作为内容营销和SEO&#xff08;搜索引擎优化&#xff09;的重要载体&#xff0c;正面临着前所未有的机遇与挑战。进入2024年&#xff0c;企业若想通过博客在激烈的市场竞争中脱颖而出&#xff0c;就必须紧跟S…

verilog实现FIR滤波系数生成(阶数,FIR滤波器类型及窗函数可调)

在以往采用 FPGA 实现的 FIR 滤波功能&#xff0c;滤波器系数是通过 matlab 计算生成&#xff0c;然后作为固定参数导入到 verilog 程序中&#xff0c;这尽管简单&#xff0c;但灵活性不足。在某些需求下&#xff08;例如捕获任意给定台站信号&#xff09;需要随时修改滤波器的…

产品管理- 互联网产品(5):运营知识与技能

了解运营 1、运营的基础是产品认清受众&#xff0c;切实解决问题、用户需求 2、运营活动贯穿产品的整个生命周期 3、找准用户&#xff0c;建立MVP 4、明确产品的应用场景。用户在何场景下基于何种需求使用产品&#xff1f;务必短流程 5、AARRR模型 6、运营管理流程类似产品管理…

【CAM350】使用总结 <一>{ 光绘Gerber 对齐 }

〇、废话&#xff1a; 由于allegro和CAM350之间参数设置的问题&#xff1b;导致钻孔层和数据交付生产出现数据问题&#xff0c;或者同一个工程前后迭代&#xff0c;需要找出差别。 一、打开CAM350,打开两份光绘文件 二、增加工艺边后&#xff0c;不是很方便的找出区别&#x…

水波荡漾效果+渲染顺序+简单UI绘制

创建场景及布置 创建新场景Main,在Main场景中创建一个plane物体&#xff0c;命名为WaterWavePla,具体数值及层级面板排布如下&#xff1a; 编写脚本 创建一个文件夹&#xff0c;用于存放脚本&#xff0c;命名Scripts,创建一个子文件夹Effect,存放特效相关脚本&#xff0c;创建…

[Linux]:线程(二)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;Linux学习 贝蒂的主页&#xff1a;Betty’s blog 与Windows环境不同&#xff0c;我们在linux环境下需要通过指令进行各操作&…

LQR算法核心思想

本章以倒立摆为解决目的 什么是线性二次型控制器&#xff08;LQR&#xff09; 开环系统 即状态变量的倒数 系统的状态空间矩阵A * 系统状态变量x A状态矩阵&#xff1a;描述系统本身物理特性的一个矩阵&#xff0c;它是由系统本身的机械结构、物理结构决定的&#xff0c;无法…

基于单片机8路数字电压表电压采集系统

**单片机设计介绍&#xff0c;基于单片机8路数字电压表电压采集系统 文章目录 前言概要功能设计设计思路 软件设计效果图 程序设计程序文章目录 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技…

【C#】BotSharp:开源机器学习平台

随着人工智能&#xff08;AI&#xff09;和自然语言处理&#xff08;NLP&#xff09;技术的迅速发展&#xff0c;聊天机器人已经成为现代应用和服务的重要组成部分。无论是智能客服、虚拟助手&#xff0c;还是业务自动化和数据分析&#xff0c;智能对话系统正在各个领域发挥重要…