1、QT学习之路全QT学习之路二维画图中视口坐标与窗口坐标视口坐标系是对物理坐标系而言,也就是我们平常画图使用的坐标系(通常相对屏幕或者父窗口部件);窗口坐标系是我们自己定义的逻辑坐标系,根据画图的方面而自定义的。在默认情况下,视口坐标系与窗口坐标系是一致的。在Qt中我们画图时坐标都是相对于窗口坐标系,而与视口坐标系无关。 比如:比如我们要一个矩形(0,0,320,200)(视口坐标)内画图,而我们可以定义这个矩形的窗口坐标为(-50,-50,100,100);窗口坐标系统相对与视口坐标系做了平移与缩放。在视口坐标系矩形的左上角坐标为(0,0),宽度为320,高度为200的长方形;而在窗口坐标系中
2、这个矩形的左上角坐标为(-50,-50),宽度为100,高度为100的正方形。 坐标的转换公式:(x0-m)*Rx=(X-0) (Y0-n)*Ry=Y-0 Rx为X轴的缩放因子,Ry为Y轴的缩放因子.Qt学习之路(1)Qt是一个著名的C+库或许并不能说这只是一个GUI库,因为Qt十分庞大,并不仅仅是GUI。使用Qt,在一定程序上你获得的是一个“一站式”的服务:不再需要研究STL,不再需要C+的,因为Qt有它自己的QString等等。或许这样说很偏激,但Qt确实是一个“伟大的C+库”。 我们所使用的Qt,确切地说也就是它的GUI编程部分。C+的GUI编程同Java不同:GUI并不是C+标准的一部
3、分。所以,如果使用Java,那么你最好的选择就是AWT/Swing,或者也可以使SWT/JFace,但是,C+的GUI编程给了你更多的选择:wxWidget, gtk+以及Qt。这几个库我都有接触,但是接触都不是很多,只能靠一些资料和自己的一点粗浅的认识说一下它们之间的区别(PS: 更详尽的比较在前面的文章中有)。 首先说wxWidget,这是一个标准的C+库,和Qt一样庞大。它的语法看上去和MFC类似,有大量的宏。据说,一个MFC程序员可以很容易的转换到wxWidget上面来。wxWidget有一个很大的优点,就是它的界面都是原生风格的。这是其他的库所不能做到的。wxWidget的运行效率很
4、高,据说在Windows平台上比起微软自家的MFC也不相上下。 gtk+其实是一个C库,不过由于C+和C之间的关系,这点并没有很大的关系。但是,gtk+是一个使用C语言很优雅的实现了面向对象程序设计的范例。不过,这也同样带来了一个问题它的里面带有大量的类型转换的宏来模拟多态,并且它的函数名“又臭又长(不过这点我倒是觉得无所谓,因为它的函数名虽然很长,但是同样很清晰)”,使用下划线分割单词,看上去和Linux如出一辙。由于它是C语言实现,因此它的运行效率当然不在话下。gtk+并不是模拟的原生界面,而有它自己的风格,所以有时候就会和操作系统的界面显得格格不入。 再来看Qt,和wxWidget一样,
5、它也是一个标准的C+库。但是它的语法很类似于Java的Swing,十分清晰,而且SIGNAL/SLOT机制使得程序看起来很明白这也是我首先选择Qt的一个很重要的方面,因为我是学Java出身的。不过,所谓“成也萧何,败也萧何”,这种机制虽然很清楚,但是它所带来的后果是你需要使用Qt的qmake对程序进行预处理,才能够再使用make或者nmake进行编译。并且它的界面也不是原生风格的,尽管Qt使用style机制十分巧妙的模拟了本地界面。另外值得一提的是,Qt不仅仅运行在桌面环境中,Qt已经被Nokia收购,它现在已经会成为Symbian系列的主要界面技术Qt是能够运行于嵌入式平台的。 以往人们对Q
6、t的授权多有诟病。因为Qt的商业版本价格不菲,开源版本使用的是GPL协议。但是现在Qt的开源协议已经变成LGPL。这意味着,你可以将Qt作为一个库连接到一个闭源软件里面。可以说,现在的Qt协议的争议已经不存在了因为wxWidgets或者gtk+同样使用的是类似的协议发布的。 在本系列文章中,我们将使用Qt4进行C+ GUI的开发。我是参照着C+ GUI Programming with Qt4一书进行学习的。其实,我也只是初学Qt4,在这里将这个学习笔记记下来,希望能够方便更多的朋友学习Qt4。我是一个Java程序员,感觉Qt4的一些命名规范以及约束同Java有异曲同工之妙,因而从Java迁移
7、到Qt4似乎困难不大。不过,这也主要是因为Qt4良好的设计等等。闲话少说,还是尽快开始下面的学习吧!Qt学习之路(2/3):Hello, world!任何编程技术的学习第一课基本上都会是Hello, world!,我也不想故意打破这个惯例照理说,应该首先回顾一下Qt的历史,不过即使不说这些也并无大碍。 或许有人总想知道,Qt这个单词是什么意思。其实,这并不是一个缩写词,仅仅是因为它的发明者,TrollTech公司的 CEO,Haarard Nord和Trolltech公司的总裁Eirik Chambe-Eng在联合发明Qt的时候并没有一个很好的名字。在这里,字母Q是Qt库中所有类的前缀这仅仅是
8、因为在Haarard的emacs的字体中,这个字母看起来特别的漂亮;而字母t则代表“toolkit”,这是在Xt( X toolkit )中得到的灵感。顺便说句,Qt原始的公司就是上面提到的Trolltech,貌似有一个中文名字是奇趣科技不过现在已经被Nokia收购了。因此,一些比较旧的文章里面会提到Trolltech这个名字。好了,闲话少说,先看看Qt的开发吧!事先说明一下,我是一个比较懒的人,不喜欢配置很多的东西,而Qt已经提供了一个轻量级的IDE,并且它的网站上也有for Eclipse 和 VS 的开发插件,不过在这里我并不想用这些大块头。Qt有两套协议商业版本和开源的LGPL版本。不
9、同的是前者要收费,而后者免费,当然,后者还要遵循LGPL协议的规定,这是题外话。安装完成后会有个Qt Creator的东西,这就是官方提供的一个轻量级IDE,不过它的功能还是蛮强大的。运行这个就会发现,其实Qt不仅仅是Linux KDE桌面的底层实现库。而且是这个IDE的实现的这个IDE就是用Qt完成的。Qt Creator左面从上到下依次是Welcome(欢迎页面,就是一开始出现的那个);Edit(我们的代码编辑窗口);Debug(调试窗口);Projects(工程窗口);Help(帮助,这个帮助完全整合的Qt的官方文档,相当有用);Output(输出窗口)。下面我们来试试我们的 Hello
10、, world! 吧!在Edit窗口空白处点右键,有 New project. 这里我们选第三项,Qt Gui Application。然后点击OK,来到下一步,输入工程名字和保存的位置。点击Next,来到选择库的界面。这里我们系统默认为我们选择了Qt core 和 GUI,还记得我们建的是Gui Application吗?嗯,就是这里啦,它会自动为我们加上gui这个库。现在应该就能看出,Qt是多么庞大的一个库,它不仅仅有Gui,而且有 Network,OpenGL,XML之类。不过,现在在这里我们不作修改,直接Next。编缉推荐阅读以下文章 Qt学习之路(10): Meta-Object系统
11、 Qt学习之路(9):深入了解信号槽 Qt学习之路(8): 创建一个对话框(下) Qt学习之路(7): 创建一个对话框(上) Qt学习之路(6): API文档的使用 Qt学习之路(5):组件布局 Qt学习之路(4):初探信号槽 Qt学习之路(3):Hello, world!(续) Qt学习之路(1):前言 下一个界面需要我们定义文件名,我们不修改默认的名字,只是为了清楚起见,把generate form的那个勾去掉即可。Next之后终于到了Finish了漫长的一系列啊!检查无误后Finish就好啦!之后可以看到,IDE(即Qt creator)自动生成了四个文件,一个.pro文件,两个.cpp
12、和一个.h。这里说明一下,.pro就是工程文件 (project),它是qmake自动生成的用于生产makefile的配置文件。这里我们先不去管它。main.cpp里面就是一个main函数,其他两个文件就是先前我们曾经指定的文件名的文件。现在,我们把main.cpp中的代码修改一下:#include #include int main(int argc, char *argv) QApplication app(argc, argv); QLabel *label = new QLabel(Hello, world!); label-show(); return app.exec(); 修改完
13、成后保存。点击左下角的绿色三角键,Run。一个小小的窗口出现了好了!我们的第一个Qt程序已经完成了。PS:截了很多图,说得详细些,以后可就没这么详细的步骤啦,嘿嘿相信很多朋友应该一下子就能看明白这个IDE应该怎么使用了的,无需我多费口舌。呵呵。下面来逐行解释一下前面的那个Hello, world!程序,尽管很简单,但却可以对Qt程序的结构有一个清楚的认识。现在再把代码贴过来:#include #include int main(int argc, char *argv) QApplication app(argc, argv); QLabel *label = new QLabel(Hello
14、, world!); label-show(); return app.exec();第1行和第2行就是需要引入的头文件。和普通的C+程序没有什么两样,如果要使用某个组件,就必须要引入相应的头文件,这类似于Java的import机制。值得说明的是,Qt中头文件和类名是一致的。也就是说,如果你要使用某个类的话,它的类名就是它的头文件名。第3行是空行 第4行是main函数函数头。这与普通的C+程序没有什么两样,学过C+的都明白。因此你可以看到,实际上,Qt完全通过普通的main函数进入,这不同于wxWidgets,因为wxWidgets的Hello, world需要你继承它的一个wxApp类,并覆
15、盖它的wxApp:OnInit方法,系统会自动将OnInit编译成入口函数。不过在Qt中,就不需要这些了。第5行,噢噢,大括号第6行,创建一个QApplication对象。这个对象用于管理应用程序级别的资源。QApplication的构造函数要求两个参数,分别来自main的那两个参数,因此,Qt在一定程度上是支持命令行参数的。第7行,创建一个QLabel对象,并且能够显示Hello, world!字符串。和其他库的Label控件一样,这是用来显示文本的。在Qt中,这被称为一个widget(翻译出来是小东西,不过这个翻译并不好),它等同于Windows技术里面的控件(controls)和容器(c
16、ontainers)。也就是说,widget可以放置其他的 widget,就像Swing的组件。大多数Qt程序使用QMainWindow或者QDialog作为顶级组件,但Qt并不强制要求这点。在这个例子中,顶级组件就是一个QLabel。第8行,使这个label可见。组件创建出来之后通常是不可见的,要求我们手动的使它们可见。这样,在创建出组建之后我们就可以对它们进行各种定制,以避免出现之后在屏幕上面会有闪烁。第9行,将应用程序的控制权移交给Qt。这时,程序的事件循环就开始了,也就是说,这时可以相应你发出的各种事件了。这类似于gtk+最后的一行gtk_main()。第10行,大括号程序结束了。注意
17、!,我们并没有使用delete去删除创建的QLabel,因为在程序结束后操作系统会回收这个空间这只是因为这个QLabel占用的内存比较小,但有时候这么做会引起麻烦的,特别是在大程序中,因此必须小心。好了,程序解释完了。按照正常的流程,下面应该编译。前面也提过,Qt的编译不能使用普通的make,而必须先使用qmake进行预编译。所以,第一步应该是在工程目录下使用qmake -project命令创建.pro文件(比如说是叫helloworld.pro)。然后再在.pro文件目录下使用qmake helloworld.pro (make)或者qmake -tp vc helloworld.pro (
18、nmake)生成makefile,然后才能调用make或者是nmake进行编译。不过因为我们使用的是IDE,所以这些步骤就不需要我们手动完成了。值得说明一点的是,这个qmake能够生成标准的makefile文件,因此完全可以利用qmake自动生成makefile这是题外话。好了,下面修改一下源代码,把QLabel的创建一句改成QLabel *label = new QLabel(Hello, world!);运行一下:同Swing的JLabel一样,Qt也是支持HTML解析的。好了,这个Hello, world就说到这里!明确一下Qt的程序结构,在一个Qt源代码中,以下两条语句是必不可少的!:
19、QApplication app(argc, argv);/.return app.exec();Qt学习之路(4):初探信号槽看过了简单的Hello, world! 之后,下面来看看Qt最引以为豪的信号槽机制!所谓信号槽,简单来说,就像是插销一样:一个插头和一个插座。怎么说呢?当某种事件发生之后,比如,点击了一下鼠标,或者按了某个按键,这时,这个组件就会发出一个信号。就像是广播一样,如果有了事件,它就漫天发声。这时,如果有一个槽,正好对应上这个信号,那么,这个槽的函数就会执行,也就是回调。就像广播发出了,如果你感兴趣,那么你就会对这个广播有反应。干巴巴的解释很无力,还是看代码:#includ
20、e #include int main(int argc, char *argv)QApplication a(argc, argv);QPushButton *button = new QPushButton(Quit);QObject:connect(button,SIGNAL(clicked(),&a, SLOT(quit();button-show(); return a.exec();这是在Qt Creator上面新建的文件,因为前面已经详细的说明怎么新建工程,所以这里就不再赘述了。这个程序很简单,只有一个按钮,点击之后程序退出。(顺便说一句,Qt里面的button被叫做QPushB
21、utton,真搞不明白为什么一个简单的button非得加上push呢?呵呵)主要是看这一句:QObject:connect(button, SIGNAL(clicked(), &a, SLOT(quit();QObject是所有类的根。Qt使用这个QObject实现了一个单根继承的C+。它里面有一个connect静态函数,用于连接信号槽。当一个按钮被点击时,它会发出一个clicked信号,意思是,向周围的组件们声明:我被点击啦!当然,其它很多组件都懒得理他。如果对它感兴趣,就告诉QObject说,你帮我盯着点,只要button发出clicked信号,你就告诉我想了想之后,说,算了,你也别告诉我
22、了,直接去执行我的某某某函数吧!就这样,一个信号槽就形成了。具体来说呢,这个例子就是QApplication的实例a说,如果button发出了clicked信号,你就去执行我的quit函数。所以,当我们点击button的时候,a的quit函数被调用,程序退出了。所以,在这里,clicked()就是一个信号,而quit()就是槽,形象地说就是把这个信号插进这个槽里面去。Qt使用信号槽机制完成了事件监听操作。这类似与Swing里面的listener机制,只是要比这个listener简单得多。以后我们会看到,这种信号槽的定义也异常的简单。值得注意的是,这个信号槽机制仅仅是使用的QObject的con
23、nect函数,其他并没有什么耦合也就是说,完全可以利用这种机制实现你自己的信号监听!不过,这就需要使用qmake预处理一下了!细心的你或许发现,在Qt Creator里面,SIGNAL和SLOT竟然变颜色了!没错,Qt确实把它们当成了关键字!实际上,Qt正是利用它们扩展了C+语言,因此才需要使用qmake进行预处理,比便使普通的C+编译器能够顺利编译。另外,这里的signal和Unix系统里面的signal没有任何的关系!哦哦,有一点关系,那就是名字是一样的!信号槽机制是Qt关键部分之一,以后我们还会再仔细的探讨这个问题的。Qt学习之路(5):组件布局(布局:Layout)顾名思义,绝对定位就
24、是使用最原始的定位方法,给出这个组件的坐标和长宽值。这样,Qt就知道该把组件放在哪里,以及怎么设置组件的大小了。但是这样做的一个问题是,如果用户改变了窗口大小,比如点击了最大化或者拖动窗口边缘,这时,你就要自己编写相应的函数来响应这些变化,以避免那些组件还只是静静地呆在一个角落。或者,更简单的方法是直接禁止用户改变大小。不过,Qt提供了另外的一种机制,就是布局,来解决这个问题。你只要把组件放入某一种布局之中,当需要调整大小或者位置的时候,Qt就知道该怎样进行调整。这类似于Swing的布局管理器,不过Qt的布局没有那么多,只有有限的几个。来看一下下面的例子:#include #include #
25、include #include #include int main(int argc, char *argv)QApplication app(argc, argv);QWidget *window = new QWidget;window-setWindowTitle(Enter your age);QSpinBox *spinBox = new QSpinBox;QSlider *slider = new QSlider(Qt:Horizontal);spinBox-setRange(0, 130);slider-setRange(0, 130);QObject:connect(slid
26、er,SIGNAL(valueChanged(int),spinBox,SLOT(setValue(int);QObject:connect(spinBox,SIGNAL(valueChanged(int),slider,SLOT(setValue(int);spinBox-setValue(35); QHBoxLayout *layout = new QHBoxLayout; layout-addWidget(spinBox); layout-addWidget(slider); window-setLayout(layout); window-show(); return app.exec
27、();编缉推荐阅读以下文章 Qt学习之路(10): Meta-Object系统 Qt学习之路(9):深入了解信号槽 Qt学习之路(8): 创建一个对话框(下) Qt学习之路(7): 创建一个对话框(上) Qt学习之路(6): API文档的使用 Qt学习之路(4):初探信号槽 Qt学习之路(3):Hello, world!(续) Qt学习之路(2):Hello, world! Qt学习之路(1):前言这里使用了两个新的组件:QSpinBox和QSlider,以及一个新的顶级窗口QWidget。QSpinBox是一个有上下箭头的微调器,QSlider是一个滑动杆,只要运行一下就会明白到底是什么东西
28、了。代码并不是那么难懂,还是来简单的看一下。首先创建了一个QWidget的实例,调用setWindowTitle函数来设置窗口标题。然后创建了一个QSpinBox和QSlider,分别设置了它们值的范围,使用的是setRange函数。然后进行信号槽的链接。这点后面再详细说明。然后是一个QHBoxLayout,就是一个水平布局,按照从左到右的顺序进行添加,使用addWidget添加好组件后,调用QWidget的 setLayout把QWidget的layout设置为我们定义的这个Layout,这样,程序就完成了!编译运行一下,可以看到效果:如果最大化的话:虽然我并没有添加任何代码,但是那个lay
29、out就已经明白该怎样进行布局。或许你发现,那两个信号槽的链接操作会不会产生无限递归?因为steValue就会引发valueChanged信号!答案是不会。这两句语句实现了,当spinBox发出valueChanged信号的时候,会回调slider的setValue,以更新slider的值;而slider发出 valueChanged信号的时候,又会回调slider的setValue。但是,如果新的value和旧的value是一样的话,是不会发出这个信号的,因此避免了无限递归。 编缉推荐阅读以下文章 Qt学习之路(10): Meta-Object系统 Qt学习之路(9):深入了解信号槽 Qt学习之路(8): 创建一个对话框(下) Qt学习之路(7): 创建一个对话框(上) Qt学习之路(6): API文档的使用 Qt学习之路(4):初探信号槽 Qt学习之路(3):Hello, worl
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1