窗口相关概念

QT中跟GUI相关概念都是QWidget,但是QWidget不等同于窗口。 一个QWidget如果不是嵌入到它的父QWidget中成为QWidget中的一部分的话,就可以把这个QWidget当作一个Window。一个QWidget如果没有父对象,可以认为是一个Window。

QMainWindow是一个特殊的QWidget,通常它没有父QWidget,它也是一个Window。它默认包含了一些常用的组件,比如:状态栏、标题栏、菜单栏、工具栏、浮动工具栏等。通常需要弹出一个新的Window的时候就会用到QDialog,因为QDialog通常不是用来嵌入到父QWidget中来显示的,因此,它也是一个Window。

QT中的对象按照树形来管理,同一个Window如果有两个子Window,需要注意他们有个顺序显示的问题,可能其中一个会挡住另外一个。

事件系统

发送事件

1
2
QApplication::postEvent(_mainWindow, event); 
QApplication::sendEvent(_mainWindow, event);

在消息分发成前就处理

可以重写bool QCoreApplication::notify(QObject *receiver, QEvent *event)虚函数,默认的行为就是调用接收对象的event接口,我们可以改变这个行为,以及阻断这个行为。这也是Qt框架内部处理消息分发的默认接口,postEvent、sendEvent接口后最终都是调用这个接口。

在这里可以处理所有线程的事件。

在消息分发前通过过滤器拦截事件

为QCoreApplication::instance()安装一个事件过滤器。这个事件过滤器就能处理所有控件的所有事件,因此这与重写notify()一样强大;此外,可以有不止一个应用程序全局级的事件过滤器,应用程序全局级事件过滤器甚至可以收到已禁用控件的鼠标事件。

注意:应用程序级事件过滤器仅能用于存活在主线程中的对象。

过滤器的默认接口是如下形式,任何对象只要有如下的接口都可以被安装作为过滤器。Qt窗口相关的类默认已经提供了它的虚函数,我们重新实现就行,但是还得使用installEventFilter(this); 方法来注册过滤器

1
2
// 返回true阻止事件传播,返回false可以继续传播。
bool QObject::eventFilter(QObject *watched, QEvent *event)

给目标对象添加过滤器

针对具体某个对象的事件处理添加过滤器,比全局的影响小很多。

更改目标对象的事件处理逻辑

经过了前面的处理之后,某个对象要处理某个事件,必定是通过它的event方法来分发的,因此可以在这里重写QObject::event()进行控制。

在目标对象内重写事件响应函数

具体某个某个事件通过重重的分发过滤,最终可能到达某个具体的响应函数来达到我们的目的,比如paintEvent()、mousePressEvent,就是针对的具体的事件。我们也可以重写具体的事件来达到控制的目的。

多线程

除了传统的创建多线程方式,Qt还指针将一个对象移动到QThread中,只有独立的QObject对象(没有父QObject)才能被移动进入线程,对象最好是new出来的。这种方式其实本质上就是利用了信号槽的机制。槽函数如果在另外的线程中,触发时将在对方的线程中处理。

资源清理

一旦将一个QObject对象移动到QTread中后,除了在线程中进行删除外,其它地方都无权限进行删除。而在线程中删除的最好时机是用信号,使用如下的代码:
connect(&_thread, &QThread::finished, this, &WzTransientImp::deleteLater);

线程退出

如果线程不涉及到消息循环,仅仅是普通的while循环代码,退出只需要通过控制循环条件来退出即可。

对于涉及到Qt的内部机制的线程退出,暂时还未研究!

使用TIPS

标题栏处理

在属性里面将最大窗口大小和最小的窗口都设置成一样可以使得最大化按钮不可用。

1
this->setWindowFlags(Qt::Dialog|Qt::FramelessWindowHint);

QtableWidget设置列宽

发布程序

Windows平台

你用哪个编译编译的程序就去哪个目录下查找windeployqt.exe。在开始菜单中,可以直接选择对应编译器的CMD,点击后就直接进入了相应的目录。然后进入bin目录,可以尝试运行windeployqt.exe –help 看能否打印帮助。

将你的qtcreator生成的文件拷贝到某个目录下,比如F:\tmp,然后CMD中运行 windeployqt.exe F:\tmp\WzPQMTool.ex即可

嵌入式平台

又分为两种情况:一种是控制台程序、一种是GUI程序。

对于控制台程序,只需要将libQt5Core.so.5文件和preloadable_iconv.so文件拷贝到嵌入式设备。在运行前指定如下的两个变量即可。

1
2
export LD_PRELOAD=/usr/lib/preloadable_libiconv.so
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$QTDIR/lib:/lib:/usr/local/lib

对于GUI程序,目前还没有去研究。但是从已有真的知识可以判断,还需要指定font目录、指定plugin目录。

升级Qt组件

https://mirrors.tuna.tsinghua.edu.cn/qt/online/qtsdkrepository/windows_x86/root/qt/ 下载Updates.xml 以及 qt 目录下的所有文件,同样在你电脑上建立qt目录,将文件原样放入qt目中。

用编辑器打开Updates.xml,替换所有库的URL 到清华镜像站,查找 “http://download.qt.io/” 替换成 “https://mirrors.tuna.tsinghua.edu.cn/qt/ “ (如果是中科大站,使用相应的地址),然后保存。将Updates.xml 以及qt目录放置到你的一个目录下,记录下目录路径, 如我的 “C:/Qt/ “
进入你的MaintenanceTool安装目录,一般是QT的安装目录,删除MaintenanceTool.ini,然后运行MaintenanceTool工具。
选择更新或者“添加或移除组件”,点击左下方设置,进入存储库设置。
取消勾选所有已有的存储库,选中 “用户定义储存库”,点击添加,将你本地的Updates.xml的目录输入,可以点击测试检测目录是否正确,然后点击OK保存。