QT学习之路.docx
- 文档编号:10911009
- 上传时间:2023-02-23
- 格式:DOCX
- 页数:53
- 大小:860.45KB
QT学习之路.docx
《QT学习之路.docx》由会员分享,可在线阅读,更多相关《QT学习之路.docx(53页珍藏版)》请在冰豆网上搜索。
QT学习之路
Qt学习之路
(1):
前言
Qt是一个著名的C++库——或许并不能说这只是一个GUI库,因为Qt十分庞大,并不仅仅是GUI。
使用Qt,在一定程序上你获得的是一个“一站式”的服务:
不再需要研究STL,不再需要C++的
或许这样说很偏激,但Qt确实是一个“伟大的C++库”。
我们所使用的Qt,确切地说也就是它的GUI编程部分。
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++库。
但是它的语法很类似于Java的Swing,十分清晰,而且SIGNAL/SLOT机制使得程序看起来很明白——这也是我首先选择Qt的一个很重要的方面,因为我是学Java出身的。
不过,所谓“成也萧何,败也萧何”,这种机制虽然很清楚,但是它所带来的后果是你需要使用Qt的qmake对程序进行预处理,才能够再使用make或者nmake进行编译。
并且它的界面也不是原生风格的,尽管Qt使用style机制十分巧妙的模拟了本地界面。
另外值得一提的是,Qt不仅仅运行在桌面环境中,Qt已经被Nokia收购,它现在已经会成为Symbian系列的主要界面技术——Qt是能够运行于嵌入式平台的。
以往人们对Qt的授权多有诟病。
因为Qt的商业版本价格不菲,开源版本使用的是GPL协议。
但是现在Qt的开源协议已经变成LGPL。
这意味着,你可以将Qt作为一个库连接到一个闭源软件里面。
可以说,现在的Qt协议的争议已经不存在了——因为wxWidgets或者gtk+同样使用的是类似的协议发布的。
在本系列文章中,我们将使用Qt4进行C++GUI的开发。
我是参照着《C++GUIProgrammingwithQt4》一书进行学习的。
其实,我也只是初学Qt4,在这里将这个学习笔记记下来,希望能够方便更多的朋友学习Qt4。
我是一个Java程序员,感觉Qt4的一些命名规范以及约束同Java有异曲同工之妙,因而从Java迁移到Qt4似乎困难不大。
不过,这也主要是因为Qt4良好的设计等等。
闲话少说,还是尽快开始下面的学习吧!
Qt学习之路
(2):
Hello,world!
任何编程技术的学习第一课基本上都会是Hello,world!
,我也不想故意打破这个惯例——照理说,应该首先回顾一下Qt的历史,不过即使不说这些也并无大碍。
或许有人总想知道,Qt这个单词是什么意思。
其实,这并不是一个缩写词,仅仅是因为它的发明者,TrollTech公司的CEO,HaarardNord和Trolltech公司的总裁EirikChambe-Eng在联合发明Qt的时候并没有一个很好的名字。
在这里,字母Q是Qt库中所有类的前缀——这仅仅是因为在Haarard的emacs的字体中,这个字母看起来特别的漂亮;而字母t则代表“toolkit”,这是在Xt(Xtoolkit)中得到的灵感。
顺便说句,Qt原始的公司就是上面提到的Trolltech,貌似有一个中文名字是奇趣科技——不过现在已经被Nokia收购了。
因此,一些比较旧的文章里面会提到Trolltech这个名字。
好了,闲话少说,先看看Qt的开发吧!
事先说明一下,我是一个比较懒的人,不喜欢配置很多的东西,而Qt已经提供了一个轻量级的IDE,并且它的网站上也有forEclipse和VS的开发插件,不过在这里我并不想用这些大块头
Qt有两套协议——商业版本和开源的LGPL版本。
不同的是前者要收费,而后者免费,当然,后者还要遵循LGPL协议的规定,这是题外话。
Qt的网址是不过我打开这个站点总是很慢,不知道为什么。
你可以找到大大的LGPL/Free和Commercial,好了,我选的是LGPL版本的,下载包蛮大,但是下载并不会很慢。
下载完成后安装就可以了,其它不用管了。
这样,整个Qt的开发环境就装好了——如果你需要的话,也可以把qmake所在的目录添加进环境变量,不过我就不做了。
安装完成后会有个QtCreator的东西,这就是官方提供的一个轻量级IDE,不过它的功能还是蛮强大的。
运行这个就会发现,其实Qt不仅仅是LinuxKDE桌面的底层实现库。
而且是这个IDE的实现
这个IDE就是用Qt完成的。
QtCreator左面从上到下依次是Welcome(欢迎页面,就是一开始出现的那个);Edit(我们的代码编辑窗口);Debug(调试窗口);Projects(工程窗口);Help(帮助,这个帮助完全整合的Qt的官方文档,相当有用);Output(输出窗口)。
下面我们来试试我们的Hello,world!
吧!
在Edit窗口空白处点右键,有Newproject…这里我们选第三项,QtGuiApplication。
然后点击OK,来到下一步,输入工程名字和保存的位置
点击Next,来到选择库的界面。
这里我们系统默认为我们选择了Qtcore和GUI,还记得我们建的是GuiApplication吗?
嗯,就是这里啦,它会自动为我们加上gui这个库。
现在应该就能看出,Qt是多么庞大的一个库,它不仅仅有Gui,而且有Network,OpenGL,XML之类。
不过,现在在这里我们不作修改,直接Next。
下一个界面需要我们定义文件名,我们不修改默认的名字,只是为了清除起见,把generateform的那个勾去掉即可。
Next之后终于到了Finish了——漫长的一系列啊!
检查无误后Finish就好啦!
之后可以看到,IDE自动生成了四个文件,一个.pro文件,两个.cpp和一个.h。
这里说明一下,.pro就是工程文件(project),它是qmake自动生成的用于生产makefile的配置文件。
这里我们先不去管它。
main.cpp里面就是一个main函数,其他两个文件就是先前我们曾经指定的文件名的文件。
现在,我们把main.cpp中的代码修改一下:
#include"QtGui/QApplication"
#include"QLabel"
intmain(intargc,char*argv[])
{
QApplicationa(argc,argv);
QLabel*label=newQLabel("Hello,world!
");
label->show();
returna.exec();
}
好了!
我们的第一个Qt程序已经完成了。
Qt学习之路(3):
Hello,world!
(续)
下面来逐行解释一下前面的那个Hello,world!
程序,尽管很简单,但却可以对Qt程序的结构有一个清楚的认识。
现在再把代码贴过来:
#include"QApplication"
#include"QLabel"
intmain(intargc,char*argv[])
{
QApplicationapp(argc,argv);
QLabel*label=newQLabel("Hello,world!
");
label->show();
returnapp.exec();
}
第1行和第2行就是需要引入的头文件。
和普通的C++程序没有什么两样,如果要使用某个组件,就必须要引入相应的头文件,这类似于Java的import机制。
值得说明的是,Qt中头文件和类名是一致的。
也就是说,如果你要使用某个类的话,它的类名就是它的头文件名。
第3行是空行
第4行是main函数函数头。
这与普通的C++程序没有什么两样,学过C++的都明白。
因此你可以看到,实际上,Qt完全通过普通的main函数进入,这不同于wxWidgets,因为wxWidgets的Hello,world需要你继承它的一个wxApp类,并覆盖它的wxApp:
:
OnInit方法,系统会自动将OnInit编译成入口函数。
不过在Qt中,就不需要这些了。
第5行,噢噢,大括号…
第6行,创建一个QApplication对象。
这个对象用于管理应用程序级别的资源。
QApplication的构造函数要求两个参数,分别来自main的那两个参数,因此,Qt在一定程度上是支持命令行参数的。
第7行,创建一个QLabel对象,并且能够显示Hello,world!
字符串。
和其他库的Label控件一样,这是用来显示文本的。
在Qt中,这被称为一个widget(翻译出来是小东西,不过这个翻译并不好…),它等同于Windows技术里面的控件(controls)和容器(containers)。
也就是说,widget可以放置其他的widget,就像Swing的组件。
大多数Qt程序使用QMainWindow或者QDialog作为顶级组件,但Qt并不强制要求这点。
在这个例子中,顶级组件就是一个QLabel。
第8行,使这个label可见。
组件创建出来之后通常是不可见的,要求我们手动的使它们可见。
这样,在创建出组建之后我们就可以对它们进行各种定制,以避免出现之后在屏幕上面会有闪烁。
第9行,将应用程序的控制权移交给Qt。
这时,程序的事件循环就开始了,也就是说,这时可以相应你发出的各种事件了。
这类似于gtk+最后的一行gtk_main()。
第10行,大括号……程序结束了。
注意,我们并没有使用delete去删除创建的QLabel,因为在程序结束后操作系统会回收这个空间——这只是因为这个QLabel占用的内存比较小,但有时候这么做会引起麻烦的,特别是在大程序中,因此必须小心。
好了,程序解释完了。
按照正常的流程,下面应该编译。
前面也提过,Qt的编译不能使用普通的make,而必须先使用qmake进行预编译。
所以,第一步应该是在工程目录下使用
qmake-project
命令创建.pro文件(比如说是叫helloworld.pro)。
然后再在.pro文件目录下使用
qmakehelloworld.pro(make)
或者
qmake-tpvchelloworld.pro(nmake)
生成makefile,然后才能调用make或者是nmake进行编译。
不过因为我们使用的是IDE,所以这些步骤就不需要我们手动完成了。
值得说明一点的是,这个qmake能够生成标准的makefile文件,因此完全可以利用qmake自动生成makefile——这是题外话。
好了,下面修改一下源代码,把QLabel的创建一句改成
QLabel*label=newQLabel("
red;">Hello,world!
red;">Hello,world!
");
运行一下:
同Swing的JLabel一样,Qt也是支持HTML解析的。
好了,这个Hello,world就说到这里!
明确一下Qt的程序结构,在一个Qt源代码中,一下两条语句是必不可少的:
QApplicationapp(argc,argv);
//...
returnapp.exec();
Qt学习之路(4):
初探信号槽
看过了简单的Hello,world!
之后,下面来看看Qt最引以为豪的信号槽机制!
所谓信号槽,简单来说,就像是插销一样:
一个插头和一个插座。
怎么说呢?
当某种事件发生之后,比如,点击了一下鼠标,或者按了某个按键,这时,这个组件就会发出一个信号。
就像是广播一样,如果有了事件,它就漫天发声。
这时,如果有一个槽,正好对应上这个信号,那么,这个槽的函数就会执行,也就是回调。
就像广播发出了,如果你感兴趣,那么你就会对这个广播有反应。
干巴巴的解释很无力,还是看代码:
#include"QtGui/QApplication"
#include"QtGui/QPushButton"
intmain(intargc,char*argv[])
{
QApplicationa(argc,argv);
QPushButton*button=newQPushButton("Quit");
QObject:
:
connect(button,SIGNAL(clicked()),&a,SLOT(quit()));
button->show();
returna.exec();
}
这是在QtCreator上面新建的文件,因为前面已经详细的说明怎么新建工程,所以这里就不再赘述了。
这个程序很简单,只有一个按钮,点击之后程序退出。
(顺便说一句,Qt里面的button被叫做QPushButton,真搞不明白为什么一个简单的button非得加上push呢?
呵呵)
主要是看这一句:
QObject:
:
connect(button,SIGNAL(clicked()),&a,SLOT(quit()));
QObject是所有类的根。
Qt使用这个QObject实现了一个单根继承的C++。
它里面有一个connect静态函数,用于连接信号槽。
当一个按钮被点击时,它会发出一个clicked信号,意思是,向周围的组件们声明:
我被点击啦!
当然,其它很多组件都懒得理他。
如果对它感兴趣,就告诉QObject说,你帮我盯着点,只要button发出clicked信号,你就告诉我——想了想之后,说,算了,你也别告诉我了,直接去执行我的某某某函数吧!
就这样,一个信号槽就形成了。
具体来说呢,这个例子就是QApplication的实例a说,如果button发出了clicked信号,你就去执行我的quit函数。
所以,当我们点击button的时候,a的quit函数被调用,程序退出了。
所以,在这里,clicked()就是一个信号,而quit()就是槽,形象地说就是把这个信号插进这个槽里面去。
Qt使用信号槽机制完成了事件监听操作。
这类似与Swing里面的listener机制,只是要比这个listener简单得多。
以后我们会看到,这种信号槽的定义也异常的简单。
值得注意的是,这个信号槽机制仅仅是使用的QObject的connect函数,其他并没有什么耦合——也就是说,完全可以利用这种机制实现你自己的信号监听!
不过,这就需要使用qmake预处理一下了!
细心的你或许发现,在QtCreator里面,SIGNAL和SLOT竟然变颜色了!
没错,Qt确实把它们当成了关键字!
实际上,Qt正是利用它们扩展了C++语言,因此才需要使用qmake进行预处理,比便使普通的C++编译器能够顺利编译。
另外,这里的signal和Unix系统里面的signal没有任何的关系!
哦哦,有一点关系,那就是名字是一样的!
信号槽机制是Qt关键部分之一,以后我们还会再仔细的探讨这个问题的。
Qt学习之路(5):
组件布局
同Swing类似,Qt也提供了几种组件定位的技术。
其中就包括绝对定位和布局定位。
顾名思义,绝对定位就是使用最原始的定位方法,给出这个组件的坐标和长宽值。
这样,Qt就知道该把组件放在哪里,以及怎么设置组件的大小了。
但是这样做的一个问题是,如果用户改变了窗口大小,比如点击了最大化或者拖动窗口边缘,这时,你就要自己编写相应的函数来响应这些变化,以避免那些组件还只是静静地呆在一个角落。
或者,更简单的方法是直接禁止用户改变大小。
不过,Qt提供了另外的一种机制,就是布局,来解决这个问题。
你只要把组件放入某一种布局之中,当需要调整大小或者位置的时候,Qt就知道该怎样进行调整。
这类似于Swing的布局管理器,不过Qt的布局没有那么多,只有有限的几个。
来看一下下面的例子:
intmain(intargc,char*argv[])
{
QApplicationapp(argc,argv);
QWidget*window=newQWidget;
window->setWindowTitle("Enteryourage");
QSpinBox*spinBox=newQSpinBox;
QSlider*slider=newQSlider(Qt:
:
Horizontal);
spinBox->setRange(0,130);
slider->setRange(0,130);
QObject:
:
connect(slider,SIGNAL(valueChanged(int)),spinBox,SLOT(setValue(int)));
QObject:
:
connect(spinBox,SIGNAL(valueChanged(int)),slider,SLOT(setValue(int)));
spinBox->setValue(35);
QHBoxLayout*layout=newQHBoxLayout;
layout->addWidget(spinBox);
layout->addWidget(slider);
window->setLayout(layout);
window->show();
returnapp.exec();
}
这里使用了两个新的组件:
QSpinBox和QSlider,以及一个新的顶级窗口QWidget。
QSpinBox是一个有上下箭头的微调器,QSlider是一个滑动杆,只要运行一下就会明白到底是什么东西了。
代码并不是那么难懂,还是来简单的看一下。
首先创建了一个QWidget的实例,调用setWindowTitle函数来设置窗口标题。
然后创建了一个QSpinBox和QSlider,分别设置了它们值的范围,使用的是setRange函数。
然后进行信号槽的链接。
这点后面再详细说明。
然后是一个QHBoxLayout,就是一个水平布局,按照从左到右的顺序进行添加,使用addWidget添加好组件后,调用QWidget的setLayout把QWidget的layout设置为我们定义的这个Layout,这样,程序就完成了!
编译运行一下,可以看到效果:
如果最大化的话:
虽然我并没有添加任何代码,但是那个layout就已经明白该怎样进行布局。
或许你发现,那两个信号槽的链接操作会不会产生无限递归?
因为steValue就会引发valueChanged信号!
答案是不会。
这两句语句实现了,当spinBox发出valueChanged信号的时候,会回调slider的setValue,以更新slider的值;而slider发出valueChanged信号的时候,又会回调slider的setValue。
但是,如果新的value和旧的value是一样的话,是不会发出这个信号的,因此避免了无限递归。
迷糊了吧?
举个例子看。
比如下面的spinBox->setValue(35)执行的时候,首先,spinBox会将自己的值设为35,这样,它的值与原来的不一样了(在没有setValue之前的时候,默认值是0),于是它发出了valueChanged信号。
slider接收到这个信号,于是回调自己的setValue函数,将它的值也设置成35,它也发出了valueChanged信号。
当然,此时spinBox又收到了,不过它发现,这个35和它本身的值是一样的,于是它就不发出信号,所以信号传递就停止了。
那么,你会问,它们是怎么知道值的呢?
答案很简单,因为你的信号和槽都接受了一个int参数!
新的值就是通过这个进行传递的。
实际上,我们利用Qt的信号槽机制完成了一个数据绑定,使两个组件或者更多组件的状态能够同步变化。
Qt一共有三种主要的layout,分别是:
QHBoxLayout-按照水平方向从左到右布局;
QVBoxLayout-按照竖直方向从上到下布局;
QGridLayout-在一个网格中进行布局,类似于HTML的table。
layout使用addWidget添加组件,使用addLayout可以添加子布局,因此,这就有了无穷无尽的组合方式。
我是在Windows上面进行编译的,如果你要是在其他平台上面,应用程序就会有不同的样子:
还记得前面曾经说过,Qt不是使用的原生组件,而是自己绘制模拟的本地组件的样子,不过看看这个截图,它模拟的不能说百分百一致,也可说是惟妙惟肖了…
Qt学习之路(6):
API文档的使用
今天来说一下有关QtAPI文档的使用。
因为Qt有一个商业版本,因此它的文档十分健全,而且编写良好。
对于开发者来说,查看文档时开发必修课之一——没有人能够记住那么多API的使用!
在Qt中查看文档是一件很简单的事情。
如果你使用QtCreator,那么左侧的Help按钮就是文档查看入口。
否则的话,你可以在Qt的安装目录下的bin里面的assistant.exe中看到Qt的文档。
在早期版本中,Qt的文档曾以HTML格式发布,不过在2009.03版中我没有找到HTML格式的文档,可能Qt已经把它全部换成二进制格式的了吧?
——当然,如果你全部安装了Qt的组件,是可以在开始菜单中找到assistant的!
assistant里面的文档有很多项:
其中,第一个是帮助的帮助:
-);第二个是QtDesigner的帮助;第三个是QtLinguist的帮助;第四个是QMake的帮助;最后一个是Qt的API文档,在QtCreator中默认打开的就是这部分。
不过,关于文档的内容这里实在不好阐述,因为整个文档太大了,我也并没有看过多少,很多时候都是随用随查,就好像是字典一样——谁也不会天天没事抱着本字典去看不是?
还有就是这里的文档都是英文的,不过如果是做开发的话,了解一些英文还是很有帮助的,不是吗?
Qt学习之路(7):
创建一个对话框(上)
首先说明一点,在C++GUIProgrammingwithQt4,2nd中,这一章连同以后的若干章一起,完成了一个比较完整的程序——一个模仿Excel的电子表格。
不过这个程序挺大的,而且书中也没有给出完整的源代码,只是分段分段的——我不喜欢这个样子,我想要看到我写出来的是什么东西,这是最主要的,而不是慢慢的过上几章的内容才能看到自己的作
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- QT 学习
![提示](https://static.bdocx.com/images/bang_tan.gif)