目录
一、QT的特点和优势:
二、Qt的缺点:
三、QT中的信号和槽是什么?如何使用?
四、QT中的文件流(QTextStream)和数据流(QDataStream)的区别
五、描述Qt下Tcp通信的整个流程
六、描述QT下udp通信的整个流程
七、QT如何使用HTTP协议
八、自定义控件的实现方法:
九、QSS使用方法:
十、QT的常见事件机制:
十一、QT事件机制的五种级别的事件过滤
十二、描述QT下多线程的两种使用方法, 以及注意事项
十三、线程同步的方法
十四、多线程编程中,常见的锁:
十五、死锁,以及死锁如何产生
一、QT的特点和优势:
1、信号槽是什么:
信号和槽是QT中的一个重要机制,用于对象之间的通信。信号是对象发出的事件,槽是对象接收事件的方法。
2、信号槽的优缺点:
(1)优点:
(2)缺点:
3、信号槽如何使用—步骤:
4、信号槽的第五个参数,如何控制:
(1)Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。
(2)Qt::DirectConnection:槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。
(3)Qt::QueuedConnection:槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。
(4)Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。
(5)Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。
他们都能帮助我们完成一些什么事情.:
(1)QTextStream – 文本流, 操作轻量级数据(int, double, QString), 数据写入文件中之后以文本的方式呈现。
(2)QDataStream – 数据流, 通过数据流可以操作各种数据类型, 包括类对象, 存储到文件中数据可以还原到内存。
QTextStream, QDataStream可以操作磁盘文件, 也可以操作内存数据, 通过流对象可以将数据打包到内存, 进行数据的传输。
QT如果要进行网络编程首先需要在.pro中添加如下代码:QT += network
1、服务器端:
(1)创建用于监听的套接字
(2)给套接字设置监听
(3)如果有连接到来, 监听的套接字会发出信号newConnected
(4)接收连接, 通过nextPendingConnection()函数, 返回一个QTcpSocket类型的套接字对象(用于通信)
(5)使用用于通信的套接字对象通信
1>. 发送数据: write
2>. 接收数据: readAll/read
2、客户端:
(1)创建用于通信的套接字
(2)连接服务器: connectToHost
(3)连接成功与服务器通信
1>. 发送数据: write
2>. 接收数据: readAll/read
QT下udp通信服务器端和客户端的关系是对等的, 做的处理也是一样的.
1. 创建套接字对象
2. 如果需要接收数据, 必须绑定端口
3. 发送数据: writeDatagram
4. 接收数据: readDatagram
1、HTTP协议,QT5中使用的相关联的主要的几个类:
(1)QNetworkAccessManager
(2)QNetworkRequest
(3)QNetworkReply。
1、从外观设计上:QSS、继承绘制函数重绘、继承QStyle相关类重绘、组合拼装等等;
2、从功能行为上:重写事件函数、添加或者修改信号和槽等等
1、将QSS统一写在一个文件中,通过程序给主窗口加载;
2、写成一个字符串中,通过程序给主窗口加载;
3、需要使用的地方,写一个字符串,加载给对象;
4、QT Designer中填写;
1、键盘事件: 按键按下和松开
2、鼠标事件: 鼠标移动,鼠标按键的按下和松开
3、拖放事件: 用鼠标进行拖放
4、滚轮事件: 鼠标滚轮滚动
5、绘屏事件: 重绘屏幕的某些部分
6、定时事件: 定时器到时
7、焦点事件: 键盘焦点移动
8、进入和离开事件: 鼠标移入widget之内,或是移出
9、移动事件: widget的位置改变
10、大小改变事件: widget的大小改变
11、显示和隐藏事件: widget显示和隐藏
12、窗口事件: 窗口是否为当前窗口
根据对Qt事件机制的分析, 我们可以得到5种级别的事件过滤,处理办法. 以功能从弱到强, 排列如下:
1、重载特定事件处理函数.
最常见的事件处理办法就是重载象mousePressEvent(), keyPressEvent(), paintEvent() 这样的特定事件处理函数.
2、重载event()函数.
通过重载event()函数,我们可以在事件被特定的事件处理函数处理之前(象keyPressEvent())处理它. 比如, 当我们想改变tab键的默认动作时,一般要重载这个函数. 在处理一些不常见的事件(比如:LayoutDirectionChange)时,evnet()也很有用,因为这些函数没有相应的特定事件处理函数. 当我们重载event()函数时, 需要调用父类的event()函数来处理我们不需要处理或是不清楚如何处理的事件.
3、在Qt对象上安装事件过滤器.
安装事件过滤器有两个步骤: (假设要用A来监视过滤B的事件)
首先调用B的installEventFilter( const QOject *obj ), 以A的指针作为参数. 这样所有发往B的事件都将先由A的eventFilter()处理.
然后, A要重载QObject::eventFilter()函数, 在eventFilter() 中书写对事件进行处理的代码.
4、给QAppliction对象安装事件过滤器.
一旦我们给qApp(每个程序中唯一的QApplication对象)装上过滤器,那么所有的事件在发往任何其他的过滤器时,都要先经过当前这个 eventFilter(). 在debug的时候,这个办法就非常有用, 也常常被用来处理失效了的widget的鼠标事件,通常这些事件会被QApplication::notify()丢掉. ( 在QApplication::notify() 中, 是先调用qApp的过滤器, 再对事件进行分析, 以决定是否合并或丢弃)
5、继承QApplication类,并重载notify()函数.
Qt是用QApplication::notify()函数来分发事件的.想要在任何事件过滤器查看任何事件之前先得到这些事件,重载这个函数是唯一的办法. 通常来说事件过滤器更好用一些, 因为不需要去继承QApplication类. 而且可以给QApplication对象安装任意个数的事件。
1、第一种方法:
(1)创建一个类从QThread类派生
(2)在子线程类中重写 run 函数, 将处理操作写入该函数中
(3)在主线程中创建子线程对象, 启动子线程, 调用start()函数
2、第二种方法:
(1)将业务处理抽象成一个业务类, 在该类中创建一个业务处理函数
(2)在主线程中创建一QThread类对象
(3)在主线程中创建一个业务类对象
(4)将业务类对象移动到子线程中
(5)在主线程中启动子线程
(6)通过信号槽的方式, 执行业务类中的业务处理函数
多线程使用注意事项:
(1)业务对象, 构造的时候不能指定父对象
(2)子线程中不能处理ui窗口(ui相关的类)
(3)子线程中只能处理一些数据相关的操作, 不能涉及窗口
1、互斥量(QMutex)
QMutex m_Mutex; m_Mutex.lock(); m_Mutex.unlock();
2、互斥锁(QMutexLocker)
QMutexLocker mutexLocker(&m_Mutex);
从声明处开始(在构造函数中加锁),出了作用域自动解锁(在析构函数中解锁)。
3、等待条件(QWaitCondition)
QWaitCondtion m_WaitCondition;
m_WaitConditon.wait(&m_muxtex, time);
m_WaitCondition.wakeAll();
4、 QReadWriteLock类
(1)一个线程试图对一个加了读锁的互斥量进行上读锁,允许;
(2)一个线程试图对一个加了读锁的互斥量进行上写锁,阻塞;
(3)一个线程试图对一个加了写锁的互斥量进行上读锁,阻塞;、
(4)一个线程试图对一个加了写锁的互斥量进行上写锁,阻塞。
读写锁比较适用的情况是:需要多次对共享的数据进行读操作的阅读线程。
QReadWriterLock 与QMutex相似,除了它对 "read","write"访问进行区别对待。它使得多个读者可以共时访问数据。使用QReadWriteLock而不是QMutex,可以使得多线程程序更具有并发性。
5、信号量QSemaphore
但是还有些互斥量(资源)的数量并不止一个,比如一个电脑安装了2个打印机,我已经申请了一个,但是我不能霸占这两个,你来访问的时候如果发现还有空闲的仍然可以申请到的。于是这个互斥量可以分为两部分,已使用和未使用。
6、QReadLocker便利类和QWriteLocker便利类对QReadWriteLock进行加解锁
1、 互斥锁(Mutex):用于保护临界区,同一时间只允许一个线程访问临界区。
2、 读写锁(Reader-Writer Lock):用于读多写少的场景,允许多个线程同时读取共享数据,但只允许一个线程写入共享数据。
3、 自旋锁(Spin Lock):使用忙等待的方式来实现锁,适用于锁的持有时间非常短暂的场景。
4. 条件变量(Condition Variable):用于线程间的通信,允许线程在特定条件下等待或唤醒。
5、 信号量(Semaphore):用于控制并发访问数量的锁,可以限制同时访问某个资源的线程数量。
6、屏障(Barrier):用于同步多个线程的执行,当所有线程都到达屏障时才能继续执行。
7、递归锁(Recursive Lock):允许同一个线程多次获取同一个锁,避免死锁的发生。
注意:windows里边还有一种是临界区
死锁的产生有如下四个必要条件
1、资源是互斥的,同一时刻只能有一个进程占有该资源
2、资源的释放只能有该进程自己完成
3、线程在获取到需要资源之前,不会释放已有资源
4、存在这么一条循环等待的队列,线程T1,T2,T3…, Tn
T1持有自己的资源请求T2的资源,….Tn持有自己的资源请求T1的资源