Qt 窗口系统
Qt窗口坐标系统
坐标系统是以左上角为原点,X向右增加, Y向下增加;
对于嵌套窗口,其坐标是相对于父窗口而言的。
QWidget
所有窗口及窗口控件都是从QWidget直接或间接派生出来的。
对象模型
在Qt中创建对象时,会提供一个parent对象指针,QObject是以对象树形式组织起来的。
- 若创建一个QObject对象时,QObject的构造函数接收一个QObject指针作为参数,该参数是父对象指针parent。在创建QObject对象时,可提供一个其父对象,创建的QObject对象会自动添加其父对象的children()列表;
- 当父对象析构时,该列表中的所有对象也会被析构,值得注意,这里父对象不是指继承意义上的父类。
QWidget是能够在屏幕上显示的一切组件的父类。
- QWidget继承自QObject,也继承了这种对象树关系。一个孩子自动成为父组件的一个子组件。如用户关闭一个对话框时,应用程序将其删除,属于这个对话框的按钮,图标等应该一起被删除,因为这些组件为对话框的子组件。
- 也可以自己删除子对象,他们会自动从其父对象列表中删除,如当删除一个工具栏时,其所在的主窗口会自动将该工具栏从其子对象列表中删除,并且自动调整屏膜显示。
Qt引入对象树概念,在一定程度上解决了内存问题。
- 当一个QObject对象在堆上创建时,Qt会自动为其创建一个对象树,但对象数中对象顺序没有被定义,同时 销毁对象的顺序也是未定的。
- 任何对象树中的QObject对象delete时,若对象有parent,则自动将其从parent的children()列表中删除;若有子对象,则自动delete每一个孩子。Qt保证没有QObject会被delete两次,这由析构顺序决定的。
若QObject在栈上创建,Qt保持同样的行为。
{
QWidget window;
QPushBUtton quit("Quit",&windows);
}
作为父组件的window和作为子组件的quit都是QObject的子类(他们都是QWiget的子类,而QWidget是QObject的子类)。quit的析构函数不会被调用两次,因为标准C++要求,局部对象的析构顺序应该按照其创建顺序的想反过程。因此,这段代码在超出作用域时,会先调用quit的析构函数,将其从父对象window的子对象列表中删除,然后才会在调用window的析构函数。
{
PushBUtton quit("Quit");
QWidget window;
quit.setParent(&windows);
}
与上例不同,析构顺序有问题,作为父对象的window会首先被析构,因为它是最后一个创建的对象。在析构过程中,它会调用子对象列表中每一个对象的析构函数,quit此时被析构了。然后代码继续执行,在window析构之后,quit也会被析构,因为quit也是一个局部变量,在超出作用域时,也需要被析构。此时,第二次调用quit的析构函数,C++不允许调用两次析构函数,这会导致程序崩溃。
小结:Qt的对象树机制虽然帮助用户在一定程序上解决了内存问题,但是也引入了一些值得注意的事,在后续的开发中需要注意该些问题,养成良好的编程习惯,在Qt中,在构造是指定parent对象,并且在堆上创建(内存回收机制)。
QMainWindow
对话框QDialog
基本概念
标准对话框
QMessageBox
The QMessageBox class provides a modal dialog for informing the user or for asking the user a question and receiving an answer.
A message box displays a primary text to alert the user to a situation, an informative text to further explain the alert or to ask the user a question, and an optional detailed text to provide even more data if the user requests it. A message box can also display an icon and standard buttons for accepting a user response.
Two APIs for using QMessageBox are provided, the property-based API, and the static functions. Calling one of the static functions is the simpler approach, but it is less flexible than using the property-based API, and the result is less informative. Using the property-based API is recommended.
//06_Dialogdemo/mainwindow.cpp
#include "mainwindow.h"
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <qDebug>
#include <QDialog>
#include <QMessageBox>
#include <QString>
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
//菜单栏
QMenuBar *mBar = menuBar();
setMenuBar(mBar);
//添加菜单
QMenu *menu = mBar->addMenu("add menu");
//添加模态对话框
QAction *p1 = menu->addAction("motai duihuakuang");
//连接函数
connect(p1,&QAction::triggered,
[=]()
{
// QDialog dlg;
// dlg.show();
// qDebug()<<"asdfas";
QDialog *p2 = new QDialog;
p2->setAttribute(Qt::WA_DeleteOnClose);
p2->show();
}
);
QAction *p3 = menu->addAction("guanyu duihuakuang");
connect(p3,&QAction::triggered,
[=]()
{
int ret = QMessageBox::question(this,
"question","Are you ok>",
0x00004000|QMessageBox::No);//可以指定按钮,OK,cancel...
switch(ret){
case QMessageBox::Yes:
qDebug() << "ok";
case QMessageBox::No:
qDebug() << "bad";
break;
default:
break;
}
});
QAction *p4 = menu->addAction("file duihuakuang");
connect(p4,&QAction::triggered,
[=]()
{
QString path = QFileDialog::getOpenFileName(
this,
"open",
"../",
"source(*.cpp *.h);;Text(*.txt);;all(*.*)"
);
qDebug() << path;
});
}
}
MainWindow::~MainWindow()
{
}
运行结果