Qt的简单案例--加法计算器(详细代码注释)
一、项目结构
二、项目代码
widget.h
1 #ifndef WIDGET_H 2 #define WIDGET_H 3 //预编译指令, 为了避免头文件被重复包含: 如果WIDGET_H没有被定义, 那么把WIDGET_H这个词替换为空; 一直到下面#endif结束预编译 4 5 #include <QWidget> 6 #include <QPushButton> 7 #include <QLineEdit> 8 #include <QLabel> 9 10 class Widget : public QWidget //子类Widget公有地继承于父类Widget 11 { 12 Q_OBJECT //Q_OBJECT宏的作用是启动Qt元对象系统的一些特性(如支持信号和槽等); 对于要定义信号和槽的类, 类定义的类体的开头必须写上Q_OBJECT宏, 并且它必须放置到类定义的私有区 13 14 public: 15 Widget(QWidget *parent = 0); //子类Widget的构造函数, 参数是一个QWidget类指针,代表它的父窗口部件(parent)。为了生成一个顶层窗口,你应该指定一个空指针作为父窗口部件(parent)。 16 ~Widget(); 17 18 //下面声明我们即将创建的用户界面中会用到的控件,因为这些控件不需要继承, 也不需要在类外被访问访问,所以我们定义它们Widget子类的私有成员 19 private: 20 QPushButton *btn1; //记得包含相关头文件 21 QLineEdit *edit1, *edit2; //记得包含相关头文件 22 QLabel *label1; //记得包含相关头文件 23 //上面的控件都会在本项目中的widget.cpp的构造函数Widget::Widget(QWidget *parent = 0)中实例化 24 //下面声明要用到的槽函数 25 private slots: 26 void add(); 27 }; 28 29 #endif // WIDGET_H
main.cpp
1 #include "widget.h" //子类Widget的定义了我们要创建的程序中需要完成的功能,在Widget类中封装完了这些功能。"widget.h"不是Qt的库文件, 而是我们创建一个Qt GUI应用时, Qt为我们建立的(当然, 我们也可以自己创建这样一个头文件) 2 #include <QApplication> //Application 类的定义。在每一个使用Qt 图形化应用程序中都必须使用一个QApplication 对象。QApplication 管理了各种各样的图形化应用程序的广泛资源、基本设置、控制流及事件处理等 3 4 int main(int argc, char *argv[]) //应用程序的入口,几乎在所有使用Qt的情况下,在将控制转交给Qt库之前, main()函数只需要执行初始化,然后Qt库通过事件(event)向程序告知用户的行为。所有Qt 程序中都必须有且只有一个main()函数。main()函数有两个参数argc 和argv , argc 是命令行变量的个数,argv是命令行变量的数组。 5 { 6 QApplication a(argc, argv); //a 是这个程序的QApplication 对象。在任何Qt的窗口系统部件被使用之前, 我们创建QApplication 对象都是必须的。它在这里被创建并且处理这些命令行变量。所有被Qt 识别的命令行参数都将从argv 中被移去(并且argc也因此而减少) 7 Widget w; //创建一个Widget类对象,在该类中完成我们创建的程序的各种功能 8 w.show(); //当创建一个窗口部件的时候,默认它是不可见的,必须调用showO函数使它变为可见 9 10 return a.exec(); 11 //这一句相当于: 12 //int result = a.exec(); return result; 13 //exec()函数的作用是通过main()把控制(control)转交给Qt,进入程序的"消息循环(message loop)"状态,等待可能的菜单,工具条,鼠标等的输入, 然后进行响应, 直到exit() 函数被调用来结束程序。此时exec()函数的值会返回.(Returns the value that was set to exit() (which is 0 if exit() is called via quit()) 14 //如果写return 0;程序就直接退出了,不能达到显示的效果。通过exec(),Qt接受并处理用户和系统的事件并且把它们传递给适当的窗口部件。 15 //※ 控制: 确定数据处理系统中不同部件执行输入、处理、存储和输出操作 的执行时间和顺序。 16 //※ 所谓“消息循环”,实际是程序循环。即Windows 中有一个系统消息队列,对于每一个正在执行的Windows应用程序,系统为其建立一个“消息队列”,即应用程序队列,用来存放该程序可能创建的各种窗口的消息。应用程序中含有一段称作“消息循环”的代码,用来从消息队列中检索这些消息并把它们分发到相应的窗口函数中。 17 }
widget.cpp
1 #include "widget.h" 2 #include <QGridLayout> 3 4 Widget::Widget(QWidget *parent) 5 : QWidget(parent) //初始化列表, 在子类中调用父类构造函数, parent的值(默认为0)传给了QWidget()构造函数; 这是为了创建一个新的窗体, 这个窗体是一个顶层窗体(因为QWidget()构造函数的第一个形参代表父窗口, 如果对应的形参为0, 则代表生成一个父窗口) 6 { 7 btn1 = new QPushButton(this); //动态子对象btn1通过QPushButton类的构造函数创建 8 //创建子控件对象时, 需指定其parent对象. 9 //Qt的对象模型提供了一种Qt对象之间的父子关系,当很多个对象都按一定次序建立起来这种父子关系的时候,就组织成了一颗树。 10 //当delete一个父对象的时候,Qt的对象模型机制保证了会自动的把它的所有子对象,以及孙对象,等等,全部delete,从而保证不会有内存泄漏的情况发生。 11 // 具体来说, 在每一个Qt对象中,都有一个链表,这个链表保存有它所有子对象的指针。 12 //当创建一个新的Qt对象的时候,如果把另外一个Qt对象指定为这个对象的父对象, 那么父对象就会在它的子对象链表中加入这个子对象的指针。另外,对于任意一个Qt对象而言,在其生命周期的任何时候,都还可以通过setParent函数 重新设置它的父对象。当一个父对象在被delete的时候,它会自动的把它所有的子对象全部delete。当一个子对象在delete的时候,会把它自己 从它的父对象的子对象链表中删除。 13 //※ 唯有我们使用new创建的没有父对象的对象才需要我们调用delete来释放。 14 //QPushButton类的构造函数为: QPushButton::QPushButton ( QWidget * parent, const char * name = 0 ), 15 //我们看到, parent的类型为QWidget, 但this的类型为Widget, 这就说明, 父类指针形参(QWidget*)可以接受其子类指针实参(Widget*) 16 edit1 = new QLineEdit(this); 17 edit2 = new QLineEdit(this); 18 label1 = new QLabel(this); //上面都是在子类Widget的构造函数里面创建控件(即"动态对象"作"成员对象") 19 label1->setText("label1"); //setText()是对象label1的成员函数; 记得包含相关头文件 20 btn1->setText("Get sum"); 21 QGridLayout *layout = new QGridLayout(this); //建立一个布局(layout), 这个布局是一个动态对象 22 layout->addWidget(edit1, 0, 0); 23 layout->addWidget(edit2, 0, 1); 24 layout->addWidget(btn1, 1, 0); 25 layout->addWidget(label1, 1, 1); //上面的layout对象的addWidget()成员函数用于在布局中插入控件 26 connect(btn1, SIGNAL(clicked()), this,SLOT(add()));//将btn1的点击事件和add函数关联 27 //connect函数语法如下: 28 //connect(sender, SIGNAL(signal()), receiver, SLOT(slot())); 29 //sender和receiver是QObject对象指针,signal 和 slot 函数一定要有形参类型(除非像这里clicked()和add()函数一样本身就没有形参), 但是,不可以有形参名。SIGNALE()和SLOT()宏的作用是把他们的参数转换成字符串。 30 //如果要确定"SIGNAL(signal())"中的signal()是什么, 我们首先需要确定对象sender所属的类型是什么, 然后去Qt文档里面查这种类型可以有哪些signals 31 } 32 33 Widget::~Widget() 34 { 35 36 } 37 38 void Widget::add() //实现槽函数 39 { 40 QString s1 = edit1->text();//得到在edit1控件中用户输入的字符 41 QString s2 = edit2->text(); 42 int a = s1.toInt() + s2.toInt(); 43 label1->setText(QString::number(a)); 44 45 }
三、项目效果