1. QEvent当事件产生被发送到对应的窗口之后,窗口并不会直接处理这个事件,而是对这些事件进行细分,然后根据事件的类型再次进行分发(相当于公司接了个项目,对项目进行查分之后分发给各个职能部门,由各个部门进行模块的开发),对应的事件处理器函数得到这个分发的事件之后就开始处理这个事件。
关于窗口事件的分发,对应一个事件分发器,叫做event
1[override virtual protected] bool QWidget::event(QEvent *event);
通过事件分发器的函数原型可以得知,关于事件类型的判断是基于参数完成的,这个参数是一个QEvent类型的对象,下面来看一下这个类中常用的一些API函数:
1void QEvent::accept();
该函数的作用是让窗口接受传递过来的事件,事件不会向上层窗口(父窗口)传递。
1void QEvent::ignore();
该函数的作用是让窗口忽略传递过来的事件,事件被传递给父窗口(向上传递)。
12bool QEvent::isAccepted() const;void QEvent::setAccept ...
1. 事件众所周知Qt是一个基于C++的框架,主要用来开发带窗口的应用程序(不带窗口的也行,但不是主流)。我们使用的基于窗口的应用程序都是基于事件,其目的主要是用来实现回调(因为只有这样程序的效率才是最高的)。所以在Qt框架内部为我们提供了一些列的事件处理机制,当窗口事件产生之后,事件会经过:事件派发 -> 事件过滤->事件分发->事件处理几个阶段。Qt窗口中对于产生的一系列事件都有默认的处理动作,如果我们有特殊需求就需要在合适的阶段重写事件的处理动作。
事件(event)是由系统或者 Qt 本身在不同的场景下发出的。当用户按下/移动鼠标、敲下键盘,或者是窗口关闭/大小发生变化/隐藏或显示都会发出一个相应的事件。一些事件在对用户操作做出响应时发出,如鼠标/键盘事件等;另一些事件则是由系统自动发出,如计时器事件。
每一个Qt应用程序都对应一个唯一的 QApplication应用程序对象,然后调用这个对象的exec()函数,这样Qt框架内部的事件检测就开始了(程序将进入事件循环来监听应用程序的事件)。
1234567int main ...
数据库
未读我们启动redis服务器的时候,经常要指定配置文件以便加载文件中的配置项,这个配置文件叫做redis.conf,如果是源码安装,配置文件被存放在源码安装包目录里边,如下图:
在这个配置文件redis.conf中有很多的配置项,并且redis配置文件中对内存大小单位不区分大小写,并且使用的时候要注意:k != kb,m!=mb,g!=gb,区别如下:
1234567891011# Note on units: when memory size is needed, it is possible to specify# it in the usual form of 1k 5GB 4M and so forth:## 1k => 1000 bytes# 1kb => 1024 bytes# 1m => 1000000 bytes# 1mb => 1024*1024 bytes# 1g => 1000000000 bytes# 1gb => 1024*1024*1024 bytes## units are case insensitive so 1GB ...
自Qt5发布7年以后,Qt官方于2020年12月8日正式发布了Qt6,这将是一个里程碑式的版本。Qt 6将是我们Qt 5系列的延续,因此不会对用户造成干扰。但是这个新的版本将拥有更高的灵活性来实现新的特性和功能,和目前的Qt 5系列相比,它能更好地支持当下和未来的需求。
1. 下载安装器从Qt5.15开始,官方网站上已经不再提供离线安装包了,官网描述如下:
We recommend you use the Qt Online Installer for first time installations and the Qt Maintenance Tool for changes to a current install。
也就是说,官方建议我们使用Qt维护工具( Qt Maintenance Tool)在线安装Qt,官方提供的在线安装器地址如下:
1https://download.qt.io/archive/online_installers/
直接跳转,下载在线安装器
根据自己的需求选择一个版本,进入到对应的目录中,这里选择4.1版本进入
可以看到官方提供了不同平 ...
1. 密码1.1 发送者、接收者和窃听者
请想象一个Alice向Bob发送电子邮件的场景。在这个场景中,发出邮件的Alice称为 发送者(sender),而收到邮件的Bob则称为 接收者(receiver)。
在讲解发送者、接收者的概念时,用邮件这个例子会比较便于理解,但实际上发送者和接收者这两个术语的使用范围并不仅仅局限于邮件。当某个人向另一个人发送信息时,发出信息的人称为发送者,而收到信息的人称为接收者。另外,被发送的信息有时也统称为 消息(message)。
Alice向Bob发送邮件
邮件是通过互联网从Alice的计算机发送到Bob的计算机的。在发送邮件时,邮件会经过许多台计算机和通信设备进行中转,在这个过程中,就存在被恶意窃听者(eavesdropper)偷看到的可能性。
Eve(窃听者)看到邮件的内容
窃听者Eve并不一定是人类,有可能是安装在通信设备上的某种窃听器,也可能是安装在邮件软件和邮件服务器上的某些程序。
尽管邮件内容原本应该只有发送者和接收者两个人知道,但如果不采取相应的对策,就存在被第三方知道的风险。
1.2 加密和解密
Alice不 ...
在标准C++没有提供专门用于套接字通信的类,所以只能使用操作系统提供的基于C的API函数,基于这些C的API函数我们也可以封装自己的C++类 C++套接字类的封装。但是Qt就不一样了,它是C++的一个框架并且里边提供了用于套接字通信的类(TCP、UDP)这样就使得我们的操作变得更加简单了(当然,在Qt中使用标准C的API进行套接字通信也是完全没有问题的)。下面,给大家讲一下如果使用相关类的进行TCP通信。
使用Qt提供的类进行基于TCP的套接字通信需要用到两个类:
QTcpServer:服务器类,用于监听客户端连接以及和客户端建立连接。
QTcpSocket:通信的套接字类,客户端、服务器端都需要使用。
这两个套接字通信类都属于网络模块network。
1. QTcpServerQTcpServer类用于监听客户端连接以及和客户端建立连接,在使用之前先介绍一下这个类提供的一些常用API函数:
1.1 公共成员函数
构造函数
1QTcpServer::QTcpServer(QObject *parent = Q_NULLPTR);
给监听的套接字设置监听
1234567boo ...
在掌握了基于TCP的套接字通信流程之后,为了方便使用,提高编码效率,可以对通信操作进行封装,本着有浅入深的原则,先基于C语言进行面向过程的函数封装,然后再基于C++进行面向对象的类封装。
1. 基于C语言的封装基于TCP的套接字通信分为两部分:服务器端通信和客户端通信。我们只要掌握了通信流程,封装出对应的功能函数也就不在话下了,先来回顾一下通信流程:
服务器端
创建用于监听的套接字
将用于监听的套接字和本地的IP以及端口进行绑定
启动监听
等待并接受新的客户端连接,连接建立得到用于通信的套接字和客户端的IP、端口信息
使用得到的通信的套接字和客户端通信(接收和发送数据)
通信结束,关闭套接字(监听 + 通信)
客户端
创建用于通信的套接字
使用服务器端绑定的IP和端口连接服务器
使用通信的套接字和服务器通信(发送和接收数据)
通信结束,关闭套接字(通信)
1.1 函数声明通过通信流程可以看出服务器和客户端有些操作步骤是相同的,因此封装的功能函数是可以共用的,相关的通信函数声明如下:
123456789101112131415161718192021///////////// ...
Linux
未读1. 背锅侠TCP在前面介绍套接字通信的时候说到了TCP是传输层协议,它是一个面向连接的、安全的、流式传输协议。因为数据的传输是基于流的所以发送端和接收端每次处理的数据的量,处理数据的频率可以不是对等的,可以按照自身需求来进行决策。
TCP协议是优势非常明显,但是有时也会给我们造成困扰,正所谓:成也萧何败萧何。假设我们有如下需求:
客户端和服务器之间要进行基于TCP的套接字通信
通信过程中客户端会每次会不定期给服务器发送一个不定长度的有特定含义的字符串。
通信的服务器端每次都需要接收到客户端这个不定长度的字符串,并对其进行解析
根据上面的描述,服务器在接收数据的时候有如下几种情况:
一次接收到了客户端发送过来的一个完整的数据包
一次接收到了客户端发送过来的N个数据包,由于每个包的长度不定,无法将各个数据包拆开
一次接收到了一个或者N个数据包 + 下一个数据包的一部分,还是很悲剧,无法将数据包拆开
一次收到了半个数据包,下一次接收数据的时候收到了剩下的一部分+下个数据包的一部分,更悲剧,头大了
另外,还有一些不可抗拒的因素:比如客户端和服务器端的网速不一样,发送和接收的数据量也 ...
Linux
未读在手把手教你写C语言线程池中,已经实现了C语言版的线程池,如果我们也学过C++的话,可以将其改为C++版本,这样代码不管是从使用还是从感观上都会更简洁一些。
对这些代码做从C到C++的迁移主要用到了C++三大特性中的封装,因此难度不大,对应C++初学者来说有助于提高编码水平和对面向对象的理解,对于熟练掌握了C++的人来说就是张飞吃豆芽 -- 小菜一碟(so easy)。
关于线程的在此就不再过多阐述,对于前面文章中设计的线程池,按照面向对象的思想进行拆分可以分为两部分(纯属个人见解,有不同的想法也正常):任务队列类 和线程池类。
本文中关于线程池实现和编写步骤相关细节,请观看视频
手把手教你撸一个线程池 - C++版
1. 任务队列1.1 类声明123456789101112131415161718192021222324252627282930313233343536373839404142// 定义任务结构体using callback = void(*)(void*);struct Task{ Task() { function ...
Linux
未读本文中关于线程池实现和编写步骤相关细节,请观看视频
手把手教你撸一个线程池 - C语言版,这里把相关的代码贴出来,以供参考。
1. 线程池原理我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。
那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务呢?
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
在各个编程语言的语种中都有线程池的概念,并且很多 ...