QT入门教程教程详解版.docx
《QT入门教程教程详解版.docx》由会员分享,可在线阅读,更多相关《QT入门教程教程详解版.docx(100页珍藏版)》请在冰豆网上搜索。
QT入门教程教程详解版
Qt教程一十四步
这个教程介绍了使用Qt工具包进行图形用户界面编程。
它没有包括所有的东西:
强调的是教授一种图形用户界面编程的编程思想,并且介绍Qt的特征也是必需的。
一些通常情况下使用的特征在这个教程里没有用到。
第一章:
Hello,World!
第一个程序是一个简单的HelloWorld例子。
它只包含你建立和运行Qt应用程序所需要的最少的代码。
上面的图片是这个程序的快照。
#include
#include
intmain(intargc,char**argv)
{
QApplicationa(argc,argv);
QPushButtonhello("Helloworld!
",0);
hello.resize(100,30);
a.setMainWidget(&hello);
hello.show();
returna.exec();
}
一行一行地解说
#include
这一行包含了QApplication类的定义。
在每一个使用Qt的应用程序中都必须使用一个QApplication对象。
QApplication管理了各种各样的应用程序的广泛资源,比如默认的字体和光标。
#include
这一行包含了QPushButton类的定义。
参考文档的文件的最上部分提到了使用哪个类就必须包含哪个头文件的说明。
QPushButton是一个经典的图形用户界面按钮,用户可以按下去,也可以放开。
它管理自己的观感,就像其它每一个QWidget。
一个窗口部件就是一个可以处理用户输入和绘制图形的用户界面对象。
程序员可以改变它的全部观感和它的许多主要的属性(比如颜色),还有这个窗口部件的内容。
一个QPushButton可以显示一段文本或者一个QPixmap。
intmain(intargc,char**argv)
{
main()函数是程序的入口。
几乎在使用Qt的所有情况下,main()只需要在把控制转交给Qt库之前执行一些初始化,然后Qt库通过事件来向程序告知用户的行为。
argc是命令行变量的数量,argv是命令行变量的数组。
这是一个C/C++特征。
它不是Qt专有的,无论如何Qt需要处理这些变量(请看下面)。
QApplicationa(argc,argv);
a是这个程序的QApplication。
它在这里被创建并且处理这些命令行变量(比如在X窗口下的-display)。
请注意,所有被Qt识别的命令行参数都会从argv中被移除(并且argc也因此而减少)。
关于细节请看QApplication:
:
argv()文档。
注意:
在任何Qt的窗口系统部件被使用之前创建QApplication对象是必须的。
QPushButtonhello("Helloworld!
",0);
这里,在QApplication之后,接着的是第一个窗口系统代码:
一个按钮被创建了。
这个按钮被设置成显示“Helloworld!
”并且它自己构成了一个窗口(因为在构造函数指定0为它的父窗口,在这个父窗口中按钮被定位)。
hello.resize(100,30);
这个按酒被设置成100像素宽,30像素高(加上窗口系统边框)。
在这种情况下,我们不用考虑按钮的位置,并且我们接受默认值。
a.setMainWidget(&hello);
这个按钮被选为这个应用程序的主窗口部件。
如果用户关闭了主窗口部件,应用程序就退出了。
你不用必须设置一个主窗口部件,但绝大多数程序都有一个。
hello.show();
当你创建一个窗口部件的时候,它是不可见的。
你必须调用show()来使它变为可见的。
returna.exec();
这里就是main()把控制转交给Qt,并且当应用程序退出的时候exec()就会返回。
在exec()中,Qt接受并处理用户和系统的事件并且把它们传递给适当的窗口部件。
}
你现在可以试着编译和运行这个程序了。
编译
编译一个C++应用程序,你需要创建一个makefile。
创建一个Qt的makefile的最容易的方法是使用Qt提供的连编工具qmake。
如果你已经把main.cpp保存到它自己的目录了,你所要做的就是这些:
qmake-project
qmake
第一个命令调用qmake来生成一个.pro(项目)文件。
第二个命令根据这个项目文件来生成一个(系统相关的)makefile。
你现在可以输入make(或者nmake,如果你使用VisualStudio),然后运行你的第一个Qt应用程序!
行为
当你运行它的时候,你就会看到一个被单一按钮充满的小窗口,在它上面你可以读到著名的词:
HellowWorld!
第二章:
调用退出
你已经在第一章中创建了一个窗口,我们现在使这个应用程序在用户让它退出的时候退出。
我们也会使用一个比默认字体更好的一个字体。
#include
#include
#include
intmain(intargc,char**argv)
{
QApplicationa(argc,argv);
QPushButtonquit("Quit",0);
quit.resize(75,30);
quit.setFont(QFont("Times",18,QFont:
:
Bold));
QObject:
:
connect(&quit,SIGNAL(clicked()),&a,SLOT(quit()));
a.setMainWidget(&quit);
quit.show();
returna.exec();
}
一行一行地解说
#include
因为这个程序使用了QFont,所以它需要包含qfont.h。
Qt的字体提取和X中提供的可怕的字体提取大为不同,字体的载入和使用都已经被高度优化了。
QPushButtonquit("Quit",0);
这时,按钮显示“Quit”,确切的说这就是当用户点击这个按钮时程序所要做的。
这不是一个巧合。
因为这个按钮是一个顶层窗口,我们还是把0作为它的父对象。
quit.resize(75,30);
我们给这个按钮选择了另外一个大小,因为这个文本比“Helloworld!
”小一些。
我们也可以使用QFontMetrics来设置正确的大小。
quit.setFont(QFont("Times",18,QFont:
:
Bold));
这里我们给这个按钮选择了一个新字体,Times字体中的18点加粗字体。
注意在这里我们调用了这个字体。
你也可以改变整个应用程序的默认字体(使用QApplication:
:
setFont())。
QObject:
:
connect(&quit,SIGNAL(clicked()),&a,SLOT(quit()));
connect也许是Qt中最重要的特征了。
注意connect()是QObject中的一个静态函数。
不要把这个函数和socket库中的connect()搞混了。
这一行在两个Qt对象(直接或间接继承QObject对象的对象)中建立了一种单向的连接。
每一个Qt对象都有signals(发送消息)和slots(接收消息)。
所有窗口部件都是Qt对象。
它们继承QWidget,而QWidget继承QObject。
这里quit的clicked()信号和a的quit()槽连接起来了,所以当这个按钮被按下的时候,这个程序就退出了。
信号和槽文档详细描述了这一主题。
行为
当你运行这个程序的时候,你会看到这个窗口比第一章中的那个小一些,并且被一个更小的按钮充满。
第三章:
家庭价值
这个例子演示了如何创建一个父窗口部件和子窗口部件。
我们将会保持这个程序的简单性,并且只使用一个单一的父窗口部件和一个独立的子窗口部件。
#include
#include
#include
#include
intmain(intargc,char**argv)
{
QApplicationa(argc,argv);
QVBoxbox;
box.resize(200,120);
QPushButtonquit("Quit",&box);
quit.setFont(QFont("Times",18,QFont:
:
Bold));
QObject:
:
connect(&quit,SIGNAL(clicked()),&a,SLOT(quit()));
a.setMainWidget(&box);
box.show();
returna.exec();
}
一行一行地解说
#include
我们添加了一个头文件qvbox.h用来获得我们要使用的布局类。
QVBoxbox;
这里我们简单地创建了一个垂直的盒子容器。
QVBox把它的子窗口部件排成一个垂直的行,一个在其它的上面,根据每一个子窗口部件的QWidget:
:
sizePolicy()来安排空间。
box.resize(200,120);
我们它的高设置为120像素,宽为200像素。
QPushButtonquit("Quit",&box);
子窗口部件产生了。
QPushButton通过一个文本(“text”)和一个父窗口部件(box)生成的。
子窗口部件总是放在它的父窗口部件的最顶端。
当它被显示的时候,它被父窗口部件的边界挡住了一部分。
父窗口部件,QVBox,自动地把这个子窗口部件添加到它的盒子中央。
因为没有其它的东西被添加了,这个按钮就获得了父窗口部件的所有空间。
box.show();
当父窗口部件被显示的时候,它会调用所有子窗口部件的显示函数(除非在这些子窗口部件中你已经明确地使用QWidget:
:
hide())。
行为
这个按钮不再充满整个窗口部件。
相反,它获得了一个“自然的”大小。
这是因为现在的这个新的顶层窗口,使用了按钮的大小提示和大小变化策略来设置这个按钮的大小和位置。
(请看QWidget:
:
sizeHint()和QWidget:
:
setSizePolicy()来获得关于这几个函数的更详细的信息。
)
第四章:
使用窗口部件
这个例子显示了如何创建一个你自己的窗口部件,描述如何控制一个窗口部件的最小大小和最大大小,并且介绍了窗口部件的名称。
#include
#include
#include
classMyWidget:
publicQWidget
{
public:
MyWidget(QWidget*parent=0,constchar*name=0);
};
MyWidget:
:
MyWidget(QWidget*parent,constchar*name)
:
QWidget(parent,name)
{
setMinimumSize(200,120);
setMaximumSize(200,120);
QPushButton*quit=newQPushButton("Quit",this,"quit");
quit->setGeometry(62,40,75,30);
quit->setFont(QFont("Times",18,QFont:
:
Bold));
connect(quit,SIGNAL(clicked()),qApp,SLOT(quit()));
}
intmain(intargc,char**argv)
{
QApplicationa(argc,argv);
MyWidgetw;
w.setGeometry(100,100,200,120);
a.setMainWidget(&w);
w.show();
returna.exec();
}
一行一行地解说
classMyWidget:
publicQWidget
{
public:
MyWidget(QWidget*parent=0,constchar*name=0);
};
这里我们创建了一个新类。
因为这个类继承了QWidget,所以新类是一个窗口部件,并且可以最为一个顶层窗口或者子窗口部件(像第三章里面的按钮)。
这个类只有一个成员函数,构造函数(加上从QWidget继承来的成员函数)。
这个构造函数是一个标准的Qt窗口部件构造函数,当你创建窗口部件时,你应该总是包含一个相似的构造函数。
第一个参数是它的父窗口部件。
为了生成一个顶层窗口,你指定一个空指针作为父窗口部件。
就像你看到的那样,这个窗口部件默认地被认做是一个顶层窗口。
第二个参数是这个窗口部件的名称。
这个不是显示在窗口标题栏或者按钮上的文本。
这只是分配给窗口部件的一个名称,以后可以用来查找这个窗口部件,并且这里还有一个方便的调试功能可以完整地列出窗口部件层次。
MyWidget:
:
MyWidget(QWidget*parent,constchar*name)
:
QWidget(parent,name)
构造函数的实现从这里开始。
像大多数窗口部件一样,它把parent和name传递给了QWidget的构造函数。
{
setMinimumSize(200,120);
setMaximumSize(200,120);
因为这个窗口部件不知道如何处理重新定义大小,我们把它的最小大小和最大大小设置为相等的值,这样我们就确定了它的大小。
在下一章,我们将演示窗口部件如何响应用户的重新定义大小事件。
QPushButton*quit=newQPushButton("Quit",this,"quit");
quit->setGeometry(62,40,75,30);
quit->setFont(QFont("Times",18,QFont:
:
Bold));
这里我们创建并设置了这个窗口部件的一个名称为“quit”的子窗口部件(新窗口部件的父窗口部件是this)。
这个窗口部件名称和按钮文本没有关系,只是在这一情况下碰巧相似。
注意quit是这个构造函数中的局部变量。
MyWidget不能跟踪它,但Qt可以,当MyWidget被删除的时候,默认地它也会被删除。
这就是为什么MyWidget不需要一个析构函数的原因。
(另外一方面,如果你选择删除一个子窗口部件,也没什么坏处,这个子窗口部件会自动告诉Qt它即将死亡。
)
setGeometry()调用和上一章的move()和resize()是一样的。
connect(quit,SIGNAL(clicked()),qApp,SLOT(quit()));
}
因为MyWidget类不知道这个应用程序对象,它不得不连接到Qt的指针,qApp。
一个窗口部件就是一个软件组件并且它应该尽量少地知道关于它的环境,因为它应该尽可能的通用和可重用。
知道了应用程序的名称将会打破上述原则,所以在一个组件,比如MyWidget,需要和应用程序对象对话的这种情况下,Qt提供了一个别名,qApp。
intmain(intargc,char**argv)
{
QApplicationa(argc,argv);
MyWidgetw;
w.setGeometry(100,100,200,120);
a.setMainWidget(&w);
w.show();
returna.exec();
}
这里我们举例说明了我们的新子窗口部件,把它设置为主窗口部件,并且执行这个应用程序。
行为
这个程序和上一章的在行为上非常相似。
不同点是我们实现的方式。
无论如何它的行为还是有一些小差别。
试试改变它的大小,你会看到什么?
(请看编译来学习如何创建一个makefile和连编应用程序。
)
第五章:
组装积木
这个例子显示了创建几个窗口部件并用信号和槽把它们连接起来,和如何处理重新定义大小事件。
#include
#include
#include
#include
#include
#include
classMyWidget:
publicQVBox
{
public:
MyWidget(QWidget*parent=0,constchar*name=0);
};
MyWidget:
:
MyWidget(QWidget*parent,constchar*name)
:
QVBox(parent,name)
{
QPushButton*quit=newQPushButton("Quit",this,"quit");
quit->setFont(QFont("Times",18,QFont:
:
Bold));
connect(quit,SIGNAL(clicked()),qApp,SLOT(quit()));
QLCDNumber*lcd=newQLCDNumber(2,this,"lcd");
QSlider*slider=newQSlider(Horizontal,this,"slider");
slider->setRange(0,99);
slider->setValue(0);
connect(slider,SIGNAL(valueChanged(int)),lcd,SLOT(display(int)));
}
intmain(intargc,char**argv)
{
QApplicationa(argc,argv);
MyWidgetw;
a.setMainWidget(&w);
w.show();
returna.exec();
}
一行一行地解说
#include
#include
#include
#include
#include
#include
这里显示的是三个新的被包含的头文件。
qslider.h和qlcdnumber.h在这里是因为我们使用了两个新的窗口部件,QSlider和QLCDNumber。
qvbox.h在这里是因为我们使用了Qt的自动布局支持。
classMyWidget:
publicQVBox
{
public:
MyWidget(QWidget*parent=0,constchar*name=0);
};
MyWidget:
:
MyWidget(QWidget*parent,constchar*name)
:
QVBox(parent,name)
{
MyWidget现在继承了QVBox,而不是QWidget。
我们通过这种方式来使用QVBox的布局(它可以把它的子窗口部件垂直地放在自己里面)。
重新定义大小自动地被QVBox处理,因此现在也就被MyWidget处理了。
QLCDNumber*lcd=newQLCDNumber(2,this,"lcd");
lcd是一个QLCDNumber,一个可以按像LCD的方式显示数字的窗口部件。
这个实例被设置为显示两个数字,并且是this的子窗口部件。
它被命名为“lcd”。
QSlider*slider=newQSlider(Horizontal,this,"slider");
slider->setRange(0,99);
slider->setValue(0);
QSlider是一个经典的滑块,用户可以通过在拖动一个东西在一定范围内调节一个整数数值的方式来使用这个窗口部件。
这里我们创建了一个水平的滑块,设置它的范围是0~99(包括0和99,参见QSlider:
:
setRange()文档)并且它的初始值是0。
connect(slider,SIGNAL(valueChanged(int)),lcd,SLOT(display(int)));
这里我们是用了信号/槽机制把滑块的valueChanged()信号和LCD数字的display()槽连接起来了。
无论什么时候滑块的值发生了变化,它都会通过发射valueChanged()信号来广播这个新的值。
因为这个信号已经和LCD数字的display()槽连接起来了,当信号被广播的时候,这个槽就被调用了。
这两个对象中的任何一个都不知道对方。
这就是组件编程的本质。
槽是和普通C++成员函数的方式不同,但有着普通C++成员函数的方位规则。
行为
LCD数字反应了你对滑块做的一切,并且这个窗口部件很好地处理了重新定义大小事件。
注意当窗口被重新定义大小(因为它可以)的时候,LDC数字窗口部件也改变了大小,但是其它的还是和原来一样(因为如果它们变化了,看起来好像很傻)。
(请看编译来学习如何创建一个makefile和连编应用程序。
)
第六章:
组装丰富的积木!
这个例子显示了如何把两个窗口部件封装成一个新的组件和使用许多窗口部件是多么的容易。
首先,我们使用一个自定义的窗口部件作为一个子窗口部件。
#include
#include
#include
#include
#include
#include
#include
classLCDRange:
publicQVBox
{
public:
LCDRange(QWidget*parent=0,constchar*name=0);
};
LCDRange:
:
LCDRange(QWidget*parent,constchar*name)
:
QVBox(parent,name)
{
QLCDNumbe