摘要:本文主要是利用向导创建了第一个qt工程文件,主要介绍了工程文件的结构、main函数、按钮的创建、qt中的对象树、坐标系、qt中的信号和槽等概念。
一、工程文件的结构
利用qt导向创建好工程文件之后,会自动生成main函数、头文件、源文件和Pro文件,以下图:数组
二、main函数
在这个main函数中,主要建立了一个窗口对象w,调用构造函数,实现一些按钮、信号和槽的功能。函数
1 #include "mywidget.h" //包含头文件 2 #include <QApplication> //包含QApplication头文件 3 4 //程序入口 argc命令行变量的数量 argv命令行变量数组 5 int main(int argc, char *argv[]) 6 { 7 QApplication a(argc, argv); //a 应用程序对象,对于Qt项目必须有应用程序对象,并且有且仅有一个 8 MyWidget w; //建立一个MyWidget对象 9 w.show(); //建立出的窗口对象并不会直接显示,须要调用show方法 10 11 return a.exec(); //进入消息循环机制,阻塞状态 12 // while(true) 13 // { 14 // if(点击叉子) 15 // break; 16 // } 17 }
三、myweiget.cpp和myweiget.h
在头文件中,重点注意类中加了“Q_OBJECT”,构造函数有默认参数。工具
1 #ifndef MYWIDGET_H 2 #define MYWIDGET_H 3 4 #include <QWidget> 5 6 //继承于QWidget 7 class MyWidget : public QWidget 8 { 9 //支持Qt中的信号和槽使用 10 Q_OBJECT 11 12 public: 13 MyWidget(QWidget *parent = 0); //构造 14 ~MyWidget(); //析构 15 }; 16 17 #endif // MYWIDGET_H
在源文件中,注意函数变量的名字两个单词之间用大写字母隔开;注意建立按钮的两种方法;为按钮添加文本,设置按钮位置,设置按钮大小;重置窗口的大小和窗口名称等方法。重点是学会查看帮助文档。测试
1 #include "mywidget.h" 2 #include<QPushButton> 3 #include "mybutton.h" 4 #include <QDebug> 5 6 MyWidget::MyWidget(QWidget *parent) 7 : QWidget(parent) 8 { 9 QPushButton * btn =new QPushButton; 10 11 // btn->show(); 12 //btn应该依赖于主窗口 13 btn->setParent(this); 14 //显示文字 15 btn->setText("德玛"); 16 17 //第二种建立方式 18 QPushButton * btn2 = new QPushButton("德玛西亚",this); 19 //移动窗口 20 btn2->move(100,100); 21 //重置窗口大小 22 resize(960,640); 23 24 //btn可不能够 resize? 能够 25 btn2->resize(50,50); 26 27 //设置窗口标题名称 28 this->setWindowTitle("德玛西亚万岁"); 29 30 //对象树 31 MyButton * myBtn = new MyButton(); 32 myBtn->setParent(this); 33 myBtn->move(200,200); 34 myBtn->setText("个人按钮"); 35 36 //窗体的坐标系 37 //左上角为 0 0 点 38 // x 以右侧为正方向 y 如下侧为正方向 39 40 //需求 点击“个人按钮” ,关闭窗口 41 //链接信号槽的关键字 connect 42 //4个参数 参数1 信号发送者 参数2 发送的信号 参数3 信号的接受者 参数4 处理的槽函数 43 //参数2 和参数4 须要的都是函数地址 44 45 connect(myBtn,&QPushButton::clicked,this,&MyWidget::close); 46 47 } 48 49 MyWidget::~MyWidget() 50 { 51 qDebug("MyWidget析构了!"); 52 }
四、对象树
先来看一幅图:ui
(1)在qt中,QObject是以对象树的形式组织起来的。
- 当你建立一个QObject对象时,会看到QObject的构造函数接收一个QObject指针做为参数,这个参数就是 parent,也就是父对象指针。这至关于,在建立QObject对象时,能够提供一个其父对象,咱们建立的这个QObject对象会自动添加到其父对象的children()列表。例如上面的3中的构造函数:MyWidget::MyWidget(QWidget *parent): QWidget(parent)
- 当父对象析构的时候,这个列表中的全部对象也会被析构。(注意,这里的父对象并非继承意义上的父类!)这种机制在 GUI 程序设计中至关有用。例如,一个按钮有一个QShortcut(快捷键)对象做为其子对象。当咱们删除按钮的时候,这个快捷键理应被删除。这是合理的。
(2)QWidget是可以在屏幕上显示的一切组件的父类。
- QWidget继承自QObject,所以也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。所以,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,咱们但愿属于这个对话框的按钮、图标等应该一块儿被删除。事实就是如此,由于这些都是对话框的子组件。
- 固然,咱们也能够本身删除子对象,它们会自动从其父对象列表中删除。好比,当咱们删除了一个工具栏时,其所在的主窗口会自动将该工具栏从其子对象列表中删除,而且自动调整屏幕显示。
- Qt 引入对象树的概念,在必定程度上解决了内存问题。
(3)当一个QObject对象在堆上建立的时候,Qt 会同时为其建立一个对象树。不过,对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
(4)任何对象树中的 QObject对象 delete 的时候,若是这个对象有 parent,则自动将其从 parent 的children()列表中删除;若是有孩子,则自动 delete 每个孩子。Qt 保证没有QObject会被 delete 两次,这是由析构顺序决定的。
(5)注意的问题:
若是QObject在栈上建立,Qt 保持一样的行为。正常状况下,这也不会发生什么问题。来看下下面的代码片断:this
1 { 2 QWidget window; 3 QPushButton quit("Quit", &window); 4 }
做为父组件的 window 和做为子组件的 quit 都是QObject的子类(事实上,它们都是QWidget的子类,而QWidget是QObject的子类)。这段代码是正确的,quit 的析构函数不会被调用两次,由于标准 C++要求,局部对象的析构顺序应该按照其建立顺序的相反过程。所以,这段代码在超出做用域时,会先调用 quit 的析构函数,将其从父对象 window 的子对象列表中删除,而后才会再调用 window 的析构函数。spa
可是,若是咱们使用下面的代码:命令行
1 { 2 QPushButton quit("Quit"); 3 QWidget window; 4 quit.setParent(&window); 5 }
状况又有所不一样,析构顺序就有了问题。咱们看到,在上面的代码中,做为父对象的 window 会首先被析构,由于它是最后一个建立的对象。在析构过程当中,它会调用子对象列表中每个对象的析构函数,也就是说, quit 此时就被析构了。而后,代码继续执行,在 window 析构以后,quit 也会被析构,由于 quit 也是一个局部变量,在超出做用域的时候固然也须要析构。可是,这时候已是第二次调用 quit 的析构函数了,C++ 不容许调用两次析构函数,所以,程序崩溃了。设计
由此咱们看到,Qt 的对象树机制虽然帮助咱们在必定程度上解决了内存问题,可是也引入了一些值得注意的事情。这些细节在从此的开发过程当中极可能时不时跳出来烦扰一下,因此,咱们最好从开始就养成良好习惯,在 Qt 中,尽可能在构造的时候就指定 parent 对象,而且大胆在堆上建立。指针
(6)总结:
- 全部new出来的对象 不用管释放
- 缘由 children表中的对象会在窗口关闭后进行自动释放
(7)测试代码
mybutton.h
1 #ifndef MYBUTTON_H 2 #define MYBUTTON_H 3 4 #include <QWidget> 5 #include <QPushButton> 6 7 class MyButton : public QPushButton 8 { 9 Q_OBJECT 10 public: 11 explicit MyButton(QWidget *parent = 0); 12 ~MyButton(); 13 signals: 14 15 public slots: 16 }; 17 18 #endif // MYBUTTON_H
mybutton.cpp
1 #include "mybutton.h" 2 #include <QDebug> 3 MyButton::MyButton(QWidget *parent) : QPushButton(parent) 4 { 5 6 } 7 8 MyButton::~MyButton() 9 { 10 qDebug() << "MyButton调用析构了!"; 11 12 }
上面代码的执行结果是:
MyWidget析构了!
MyButton调用析构了!
这样的析构顺序和我咱们想象的不太一致,咱们会认为是先析构按钮再析构窗口,然而显示的结果却不是这样的。实际上咱们的想法是正确的,这是由于在执行到窗口析构的过程当中,会出现按钮的析构,等按钮析构完成之后,再返回窗口析构。
五、窗口的坐标系
原点在左上角
六、信号槽的基本使用
具体的使用见代码