什么是信号与槽机制?信号和槽的参数必须完全一致吗?
信号与槽都需要在类中声明,信号用signals关键字,槽函数在QT5中可以用public slot,也可以用普通函数或lambda表达式。连接信号与槽要使用QObject的connect函数,格式一般是connect发送者,signal信号,接收者,slot槽函数。当发送者发射信号时,连接的槽函数就会自动执行。而且一个信号可以连接多个槽,多个信号也可以连接同一个槽,还能进行信号与信号的连接
参数不要求完全一致,只要求信号的参数个数大于等于槽的参数,并且对应位置的参数类型必须兼容
信号与槽中的第五个参数有什么作用?
| 连接类型 | 含义 | 适用场景 | |
|---|---|---|---|
Qt::AutoConnection(默认) |
自动判断:1. 若发送者和接收者在同一线程 → 等价于 DirectConnection(同步);2. 若发送者和接收者在不同线程 → 等价于 QueuedConnection(异步)。 |
绝大多数场景(无需手动指定),Qt 自动适配线程。 | |
Qt::DirectConnection(直接连接) |
信号触发时,立即在发送信号的线程中执行槽函数(同步执行),槽函数和信号在同一调用栈中。⚠️ 注意:若接收者在其他线程,槽函数会 "跨线程" 执行(可能导致线程安全问题)。 | 需同步执行、发送 / 接收者同线程,或明确要在发送线程执行槽函数的场景。 | |
Qt::QueuedConnection(队列连接) |
信号触发后,将槽函数调用封装成事件放入接收者的事件循环队列,发送线程不阻塞,槽函数在接收者的线程中异步执行。✅ 线程安全:跨线程信号槽的标准用法。 | 发送者和接收者在不同线程(如主线程发信号给子线程,或子线程发信号给主线程更新 UI)。 | |
Qt::BlockingQueuedConnection(阻塞队列连接) |
类似 QueuedConnection,但发送线程会阻塞,直到接收者的事件循环执行完槽函数后才继续。⚠️ 禁止在 "接收者和发送者同线程" 时使用(会导致死锁)。 |
需等待槽函数执行完成、跨线程且发送线程可阻塞的场景(如子线程请求主线程处理数据,需等结果返回)。 | |
Qt::UniqueConnection(唯一连接) |
不是独立的连接类型,而是修饰符(可和上述 4 种组合,如 `Qt::QueuedConnection | Qt::UniqueConnection`)。作用:确保同一信号 - 槽的连接只创建一次,避免重复 connect 导致槽函数多次执行。 | 防止重复连接(如多次调用 connect 绑定同一信号槽)。 |
什么是事件循环eventloop?
在qt中,QEventloop是事件循环的实现类。你可以创建它来启动一个局部的事件循环,比如在对话框弹出时,它会开启自己的事件循环,让对话框能独立处理用户交互,不阻塞整个应用,当调用exec()方法启动循环后,它会一直运行到调用quit()或exit(),期间不断处理事件队列里的事件
什么是事件机制?
QT的事件机制是一个很灵活的系统,事件可以来自于系统,如鼠标点击、键盘输入,也可以由应用程序或其他对象手动发送。事件从产生到处理有一套完整的流程,先由QApplication或QCoreApplication的notify方法分发,然后经过事件过滤器,最后到达目标对象,调用它的event方法来处理具体的事件类型
cpp
事件对象 → QApplication::notify() → 目标对象的事件过滤器 → 目标对象的event()函数 → 具体事件处理函数
当鼠标点击事件产生后,Qt会先创建一个QMouseEvent对象,然后通过QApplication::notify()函数来分发这个事件。在分发过程中,如果目标对象安装了事件过滤器,会先调用过滤器的eventFilter()函数。如果事件没有被过滤,就会调用目标对象的event()函数,这个函数会根据事件类型调用具体的事件处理函数,比如mousePressEvent()。
想要实现事件过滤有哪几种方式?
有两种常用方式,第一种是让一个对象通过InstallEventFilter方法,给目标对象安装过滤器,然后重写这个对象的eventFilter函数来处理事件。第二种是在目标对象内部重写event方法,在事件分发到具体处理函数前进行拦截
qt当中的线程有哪两种实现方式?两种方式的实现的底层原理有什么区别?
第一种是继承QThead类,重写它的run方法,在run方法中编写线程需要执行的代码,然后通过start方法启动线程。第二种是使用QObject结合QThread,先创建一个QObject的子类,将线程任务写到槽函数里,接着把这个QObject对象移动到一个QThread对象中,通过信号触发槽函数来执行任务。
继承QThread时,run方法是线程入口,默认run里调用exec()启动事件循环,若重写run里没调用exec,线程执行完run就结束。而QObject+QThread方式,QObject移动到线程后,其槽函数会在线程的事件循环中执行,依赖线程的事件循环来调度任务,底层是通过事件的驱动机制来实现的
QT中怎么进行内存管理?线程怎么进行内存回收?
qt中主要使用对象树机制管理内存。当创建一个QObject对象时,如果指定了父对象,这个子对象就会被添加到父对象的子对象列表中。当父对象销毁时,它会自动销毁所有子对象,这样能有效避免内存泄漏,比如Qwidget窗口作为父对象,它上面的按钮、输入框等子控件,会在窗口关闭时一同被销毁
如果这个线程是QThread子类且通过new创建,你可以给它指定父对象,让父对象在销毁时顺带回收它,不过更常用的是在线程的run函数执行完毕后,调用deletelater方法,它会在事件循环中安排线程对象的销毁。movetoThread创建的线程通常通过两种方式释放,一种是线程执行完毕,系统自动回收线程资源,另一种是调用线程的终止方法比如stop,但推荐通过标志位控制循环退出,确保资源正确释放
mvc是什么
mvc是一种软件架构模式,把系统分为模型、视图、控制器三部分。模型负责数据和业务逻辑,比如存储用户信息和计算,视图就是用户看到的界面,控制器是连接两者,接收用户输入,比如点击按钮,然后调用模型处理数据再让视图显示结果,这种分离让代码更易维护和扩展
QPointer设计的意义是什么
QPointer设计的核心意义是管理QObject子类对象的生命周期,避免野指针问题。它像一个智能指针,当指向的QObject对象被销毁时,QPointer会自动置为nullptr。这样在使用前检查是否为空,就能防止访问已销毁对象导致的崩溃。比如在多线程场景中,一个线程销毁了对象,另一个线程通过QPointer能安全判断对象是否存活。
QPointer 不自动释放内存 :它只是 "智能判空",不会像 std::unique_ptr 那样自动 delete 对象,内存仍需手动释放(或通过父对象的父子机制自动释放)。
QPointer 依赖 Qt 的 QObject 销毁机制:
QPointer会监听所指向QObject的destroyed()信号;- 当
QObject对象被delete或父对象销毁导致其被销毁时,QPointer内部的指针会自动变为nullptr; - 访问
QPointer指向的对象前,只需判断是否为空,即可避免访问已销毁对象导致的崩溃。