qt元对象系统
qt的元对象编译系统MOC是一个预处理器,当qt读取源文件时检测到类中包含有Q_OBJECT宏时,则会创建一个新的文件,将源码转换为C++编译器可以识别的代码写入moc开头的文件,然后C++编译器对其进行编译。使用moc系统的方法:1、继承QObject;2、类中添加Q_OBJECT宏
信号槽机制
信号和槽是用于对象之间进行通信的,是Qt的核心,为此Qt引入了一些关键字,slots,signals,emit。信号槽支持线程间通信,connect函数的第五个参数可以指定信号槽的连接方式
信号槽连接方式:
1、 Qt::AutoConnection:信号的发送者和接收者在同一个线程,默认使用Qt::DirectConnection,不在同一个线程,默认使用Qt::QueuedConnection
2、 Qt::DirectConnection:信号的发送者与信号的接收者在同一线程中执行,当发出信号后,会马上进入槽函数,看上去就像在信号 发送位置调用了槽函数,在多线程下会比较危险,容易造成崩溃。
3、 Qt::QueuedConnection:信号的发送者与信号的接收者不在同一线程中执行,槽函数运行于信号的接收者线程,当发送信号后, 槽函数不会马上被调用,等待信号的接收者把当前函数执行完,进
入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。
4、 Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。
5、Qt::UniqueConnection:可以通过按位或(|)与以上四个结合在一起使用。当设置此参数时,当某个信号和槽已经连接时,再进行重复的连接就会失败,也就是避免了重复连接。
信号槽的优缺点
优点:
1、类型安全:需要关联的信号槽的签名必须是等同的,即信号的参数类型与槽的参数类型是一致的。
2、松散耦合:QT对象只需要在适当时间发送适当信号即可,不需要关心是否被接受。
3、灵活性:一个信号可以关联多个槽,或多个信号关联同一个槽
不足:
速度较慢:和回调函数比,信号槽机制比直接调用非虚函数的速度慢10倍
原因:需要定位接收信号的对象,2、安全遍历所有关联槽,3、编组、解组传递参数、4、多线程时候,信号需要排队。
信号和槽的本质
本质还是回调函数,信号或是传递值,或者是传递动作变化,槽函数响应信号或者接收值
MVD
Qt的MVD包含三个部分Model(模型),View(视图),代理(Delegate)。
model负责保存数据,view负责展示数据,delegate负责item样式绘制或者处理输入。这三部分通过信号槽进行通信。当modle中数据变化时会发送信号到view,在view中编辑数据,delegate负责将编辑的状态发送给model。基类分别为QAbstractItemModel、QAbstractItemView、QAbstractItemDelegate。Qt提供了默认的MVD类,QTableWidget、QListWiget、QTreeWiget
QGraphicsView。
Qt多线程
实现方法:
1、QThread,重写QThread类中的run方法。
优点:实现简单,可以用信号槽通信
缺点:自己管理线程,频繁创建释放的话 效率不高
2、QThread类与MoveToThread,创建对象继承QObject,将对象移动到子线程对象
优点:实现简单,适用于比较复杂的业务场景
缺点:只能通过信号槽的方式进行调用业务接口,且不能给此对象指定父对象
3、QThreadPool和QRunnable,继承QRunnable实现run方法完成业务类创建,由QThreadPool启动业务类
优点:无需关注线程资源管理,不会频繁创建销毁
4、QtConcurrent::run直接将任务丢进子线程执行
优点:调用简单,无需关注线程资源,不会频繁创建销毁
Qt事件处理机制
事件:键盘事件、鼠标事件、拖放事件、滚轮事件、焦点事件、移动事件。。。
QT将产生的消息转为事件,事件被封装为对象,所有的qt事件均继承抽象类QEvent,用于描述程序内部或者外部发生的动作,任意的QObject对象都具备处理QT事件的能力
QInputEvent、QDropEvent、QPaintEvent、QCloseEvent、QTimerEvent
1、QT事件的产生:
1、操作系统事件:鼠标、键盘事件等
2、Qt应用程序自己产生:调用QApplication::postEvent(配在堆上的事件对象)或sendEvent(支持分配在栈上和堆上的事件对象)
2、QT事件通知、派发
从QApplication::notify开发,因为QApplication继承于QObject,所以先检查QApplication对象,如果安装了事件过滤器,先调用事件过滤器,过滤或者合并一些事件,事件被发送到reciver::event上
在reciver::event上,先检查有没有安装事件过滤器,有则调用,然后根据QEvent的类型调用响应的事件处理函数。比如:mousePressEvent(), focusOutEvent(), resizeEvent(), paintEvent(),
resizeEvent()等等。
3、事件的转发
对应某些类别的事件,如果在事件的派发过程后还没有被处理,那么这个事件将向上转发给他的父widget,直到最顶层窗口。
qt中事件通信交互函数有两种:一种是QApplication::notify---QObject::eventFilter---QObject::event 通过bool返回值来判断是否已处理
另一种:QEvent::ignore或QEvent::accept对事件进行标识,只用于event函数和特定事件处理函数之间的沟通,,而且只有用在某些类别事件上是有意义的, 这些事件就是上面提到的那些会被转发的事件,
包括: 鼠标, 滚轮, 按键等事件。
4、事件的处理和过滤
qt提供了5种不同级别的处理和过滤:
1、重写特定事件处理函数
2、重写event函数
3、在事件上安装事件过滤器
4、给QApplication对象安装事件过滤器
5、继承QApplication类,并重载notify函数
QT的TCP通讯流程
服务端(QTcpServer)
1、创建QTcpServer对象
2、监听list需要的参数是地址和端口号
3、当有新的客户端连接成功会发送newConnect信号
4、在newConnection信号槽函数中,调用nextPendingConnection函数获取新连接QTcpSocket对象
5、连接QTcpSocket对象的readRead信号
6、在readRead信号的槽函数使用read接收数据
7、调用write成员函数发送数据
客户端(QTcpSocket)
1、创建QTcpSocket对象
2、当对象与Server连接成功时会发送connected信号
3、调用成员函数connectToHost连接服务器,需要的参数是ip/port
4、connected信号的槽函数开启发送数据
5、使用write发送数据,read接收数据