Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1372|回复: 1
打印 上一主题 下一主题

QT学习笔记

[复制链接]

1228

主题

1997

帖子

7582

积分

认证用户组

Rank: 5Rank: 5

积分
7582
跳转到指定楼层
楼主
发表于 2020-1-5 20:35:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Qter 于 2020-1-5 20:37 编辑

Qt学习之路(1):前言
C++GUI编程同Java不同:GUI并不是C++标准的一部分。所以,如果使用Java,那么你最好的选择就是AWT/Swing,或者也可以使SWT/JFace,但是,C++GUI编程给了你更多的选择:wxWidget, gtk++以及Qt。这几个库我都有接触,但是接触都不是很多,只能靠一些资料和自己的一点粗浅的认识说一下它们之间的区别(PS: 更详尽的比较在前面的文章中有)

首先说wxWidget,这是一个标准的C++库,和Qt一样庞大。它的语法看上去和MFC类似,有大量的宏。据说,一个MFC程序员可以很容易的转换到wxWidget上面来。wxWidget有一个很大的优点,就是它的界面都是原生风格的。这是其他的库所不能做到的。wxWidget的运行效率很高,据说在Windows平台上比起微软自家的MFC也不相上下。

gtk++其实是一个C库,不过由于C++C之间的关系,这点并没有很大的关系。但是,gtk++是一个使用C语言很优雅的实现了面向对象程序设计的范例。不过,这也同样带来了一个问题——它的里面带有大量的类型转换的宏来模拟多态,并且它的函数名“又臭又长(不过这点我倒是觉得无所谓,因为它的函数名虽然很长,但是同样很清晰)”,使用下划线分割单词,看上去和Linux如出一辙。由于它是C语言实现,因此它的运行效率当然不在话下。gtk++并不是模拟的原生界面,而有它自己的风格,所以有时候就会和操作系统的界面显得格格不入。

再来看Qt,和wxWidget一样,它也是一个标准的C++库。但是它的语法很类似于JavaSwing,十分清晰,而且SIGNAL/SLOT机制使得程序看起来很明白——这也是我首先选择Qt的一个很重要的方面,因为我是学Java出身的 。不过,所谓“成也萧何,败也萧何”,这种机制虽然很清楚,但是它所带来的后果是你需要使用Qtqmake对程序进行预处理,才能够再使用make或者nmake进行编译。并且它的界面也不是原生风格的,尽管Qt使用style机制十分巧妙的模拟了本地界面。另外值得一提的是,Qt不仅仅运行在桌面环境中,Qt已经被Nokia收购,它现在已经会成为Symbian系列的主要界面技术——Qt是能够运行于嵌入式平台的。
Qt学习之路(2)Hello, world!
字母Q是Qt库中所有类的前缀——这仅仅是因为在Haarard的emacs的字体中,这个字母看起来特别的漂亮;而字母t则代表“toolkit”,这是在Xt( X toolkit )中得到的灵感。
Qt Creator这个IDE就是用Qt完成的。

发送信号
emit salaryChanged(mySalary);
connect()语句的原型类似于:

file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps1.pngconnect(sender, SIGNAL(signal), receiver, SLOT(slot));

这里,sender和receiver都是QObject类型的,singal和slot都是没有参数名称的函数签名。SINGAL()和SLOT()宏用于把参数转换成字符串。

深入的说,信号槽还有更多可能的用法,如下所示。

一个信号可以和多个槽相连:

file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps2.pngconnect(slider, SIGNAL(valueChanged(int)),
              spinBox, SLOT(setValue(int)));
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps3.pngconnect(slider, SIGNAL(valueChanged(int)),
              this, SLOT(updateStatusBarIndicator(int)));

注意,如果是这种情况,这些槽会一个接一个的被调用,但是它们的调用顺序是不确定的。

多个信号可以连接到一个槽:

file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps4.pngconnect(lcd, SIGNAL(overflow()),
              this, SLOT(handleMathError()));
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps5.pngconnect(calculator, SIGNAL(divisionByZero()),
              this, SLOT(handleMathError()));

这是说,只要任意一个信号发出,这个槽就会被调用。

一个信号可以连接到另外的一个信号:

file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps6.pngconnect(lineEdit, SIGNAL(textChanged(const QString &)),
              this, SIGNAL(updateRecord(const QString &)));

这是说,当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式没有什么区别。

槽可以被取消链接:

file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps7.pngdisconnect(lcd, SIGNAL(overflow()),
                 this, SLOT(handleMathError()));

这种情况并不经常出现,因为当一个对象delete之后,Qt自动取消所有连接到这个对象上面的槽。

为了正确的连接信号槽,信号和槽的参数个数、类型以及出现的顺序都必须相同,例如:

file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps8.pngconnect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
              this, SLOT(processReply(int, const QString &)));

这里有一种例外情况,如果信号的参数多于槽的参数,那么这个参数之后的那些参数都会被忽略掉,例如:

file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps9.pngconnect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps10.png            this, SLOT(checkErrorCode(int)));

这里,const QString &这个参数就会被槽忽略掉。
Meta-Object系统
前面说过,Qt使用的是自己的预编译器,它提供了对C++的一种扩展。利用Qt的信号槽机制,就可以把彼此独立的模块相互连接起来,不需要实现知道模块的任何细节。

为了达到这个目的,Qt提出了一个Meta-Object系统。它提供了两个关键的作用:信号槽和内省。

面向对象程序设计里面会讲到Smalltalk语言有一个元类系统。所谓元类,就是这里所说的Meta-Class。如果写过HTML,会知道HTML标签里面也有一个<meta>,这是用于说明页面的某些属性的。同样,Qt的Meta-Object系统也是类似的作用。内省又称为反射,允许程序在运行时获得类的相关信息,也就是meta-information。什么是meta-information呢?举例来说,像这个类叫什么名字?它有什么属性?有什么方法?它的信号列表?它的槽列表?等等这些信息,就是这个类的meta-information,也就是“元信息”。这个机制还提供了对国际化的支持,是QSA(Qt Script for Application)的基础。

标准C++并没有Qt的meta-information所需要的动态meta-information。所以,Qt提供了一个独立的工具,moc,通过定义Q_OBJECT宏实现到标准C++函数的转变。moc使用纯C++实现的,因此可以在任何编译器中使用。

这种机制工作过程是:

首先,Q_OBJECT宏声明了一些QObject子类必须实现的内省的函数,如metaObject(),tr(),qt_metacall()等;

第二,Qt的moc工具实现Q_OBJECT宏声明的函数和所有信号;

第三,QObject成员函数connect()和disconnect()使用这些内省函数实现信号槽的连接。
以上这些过程是qmake,moc和QObject自动处理的,你不需要去考虑它们。如果实现好奇的话,可以通过查看QMetaObject的文档和moc的源代码来一睹芳容。
MainWindow
MainWindow继承自QMainWindow。QMainWindow窗口分成几个主要的区域:

file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps11.jpg

最上面是Window Title,用于显示标题和控制按钮,比如最大化、最小化和关闭等;下面一些是Menu Bar,用于显示菜单;再下面一点事Toolbar areas,用于显示工具条,注意,Qt的主窗口支持多个工具条显示,因此这里是ares,你可以把几个工具条并排显示在这里,就像Word2003一样;工具条下面是Dock window areas,这是停靠窗口的显示区域,所谓停靠窗口就是像Photoshop的工具箱一样,可以在主窗口的四周显示;再向下是Status Bar,就是状态栏;中间最大的Central widget就是主要的工作区了。

事件
事件的调用最终都会调用QCoreApplicationnotify()函数,因此,最大的控制权实际上是重写QCoreApplicationnotify()函数。由此可以看出,Qt的事件处理实际上是分层五个层次:重定义事件处理函数,重定义event()函数,为单个组件安装事件过滤器,为QApplication安装事件过滤器,重定义QCoreApplicationnotify()函数。这几个层次的控制权是逐层增大的

Qt允许你创建自己的事件类型,这在多线程的程序中尤其有用,当然,也可以用在单线程的程序中,作为一种对象间通讯的机制。那么,为什么我需要使用事件,而不是使用信号槽呢?主要原因是,事件的分发既可以是同步的,又可以是异步的,而函数的调用或者说是槽的回调总是同步的。事件的另外一个好处是,它可以使用过滤器。

关联容器类型
典型的关联容器就是散列(Hash Map,哈希表)。Qt提供两种关联容器类型:QMap<K, T>和QHash<K, T>。
[]操作符同样也可以像数组一样取值。但是请注意,如果在一个非const的map中,使用[]操作符取一个不存在的Key的值,则这个Key会被自动创建,并将其关联的value赋予一个空值。如果要避免这种情况,请使用QMap<K, T>的value()函数:

file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps12.pngint val = map.value("dreiundzwanzig");
model-view架构
Smalltalk语言发明了一种崭新的实现,用来解决这个问题,这就是著名的MVC模型。对这个模型无需多言,简单来说,这是一个model-view-controller模型,即模型-视图-控制器。在MVC中,模型负责获取需要显示的数据,并且能够存储这些数据的修改。每种数据类型都有它自己对应的模型,但是这些模型提供一个相同的API,用于隐藏内部实现。视图用于将模型数据显示给用户。对于很大的数据,或许只显示一小部分,这样就能很好的提高性能。控制器是模型和视图之间的媒介,将用户的动作解析成对数据的操作,比如查找数据或者修改数据,然后转发给模型执行,最后再将模型中需要被显示的数据直接转发给视图进行显示。

对于Qt而言,它使用的是一个类似于MVC模型的model-view架构。其中,model就相当于MVC架构中的model,而对于控制器部分,Qt使用的是另外的一种抽象,代理delegate。代理被用来提供对item渲染和编辑的控制。对于每种视图,Qt都提供了一个默认的代理,对于大多数应用来说,我们只需要使用这个默认的代理即可。这其中的类关系如下图所示(出自C++ GUI Programming with Qt 4, 2nd Edition)
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml7028\wps13.jpg
使用Qt的model-view架构,我们可以让model是取回view所要展示的数据,这样就可以在不降低性能的情形下处理大量数据。并且你可以把一个model注册给多个view,让这些view能够显示同样的数据,也就是为同一个数据提供不同的显示方式。Qt会自动地对这些view保持同步,自动刷新所有的view以显示最新的数据。这样,我们就可以只对model进行修改,view会自动更新。

在少量数据的情形下,我们不需要动用model这样重量级的组件。Qt为了方便起见也提供了item view类,分别是QListWidget,QTableWidget和QTreeWidget,使用这些类可以直接对item进行操作。这种实现很像Qt早期版本,组件中包含了相应的item,例如QTableWidget中包含有QTableWidgetItem等。但是对于很大的数据,我们则需要使用Qt的view类,比如QListView,QTabelView和QTreeView,同时需要提供一个model,可以是自定义model,也可以是Qt预置的model。例如,如果数据来自数据库,那么你可以使用QTabelView和QSqlTableModel这两个类。



链接:https://pan.baidu.com/s/1fwNHyYAFCTkYWaRDT03Q2A
提取码:x1ii


回复

使用道具 举报

1228

主题

1997

帖子

7582

积分

认证用户组

Rank: 5Rank: 5

积分
7582
沙发
 楼主| 发表于 2020-1-5 20:35:33 | 只看该作者
其中信号和槽,还有Qt的内存管理,我觉得是掌握Qt的关键,这也是它在技术方面区别与其他c++框架的2个特点。
   Qt是完全组件式编程的,也就是说它把我们常用到的功能模块编成动态库了,我们可以按需要分别去引用,而不用担心会把Qt整个框架加进来。
   比如,你要用Qt写个ftp程序,那只要引用QtCore4.lib和QtNetwork4.lib就可以,然后在发布时带上QtCore4.dll,QtNetwork4.dll。

     Qt的SDK可以直接去它官网下载,上面提供的下载版本很多,如果是在windows上面开发,建议大家下载qt-win-opensource-4.8.2-vs2010.exe
     Qt还提供了vs的插件,插件提供的功能有:新建Qt工程向导、帮助编译资源和moc (Meta Object Compiler)。
     这个插件也很好用,不过我一般不用它,我一般都是自己写脚本控制moc等,这样更灵活一些。脚本也放在邮件的附件里了。


http://qt.digia.com/China/
http://qt-project.org/downloads
https://qt-project.org/downloads
Jump to: Qt libraries Qt Creator Other downloads
Qt libraries 4.8.4 for Windows (VS 2010, 234 MB)
Qt Creator 2.6.2 for Windows (51 MB)
Visual Studio Add-in 1.1.11 for Qt4  
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|firemail ( 粤ICP备15085507号-1 )

GMT+8, 2024-5-2 13:25 , Processed in 0.092219 second(s), 18 queries .

Powered by Discuz! X3

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表