在Qt5项目中要想让程序运行时显示出我们设计的界面,关键是要执行界面文件生成的类中的setupUi(QWidget *Widget)函数,否则界面是无法显示出来的.
首先,我们来看一下自动生成的Qt5项目中是如何调用界面类中的setupUi()函数的.
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
可以看出,在该头文件中,首先是前置声明了Ui界面类,也就是通过uic工具,将我们设计的.ui文件翻译成标准的界面头文件中的界面类.
然后,定义了一个一个继承自QWidget的类Widget, 并且将界面类的作为其私有子对象.
namespace Ui {
class Widget;
}
...
private:
Ui::Widget *ui;
接着我们来看widget.cpp
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
}
可以看出,在这里,继承自QWidget的Widget类的构造函数实现了对类Widget子对象ui实现了初始化操作
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this); #这里的this就是调用构造函数的对象
}
一种与上面等效的简单直接的方式如下:
#include <QApplication>
#include <QDialog>
#include "ui_dialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Ui::Dialog ui;
QDialog *d=new QDialog;
ui. setupUi(d);
d->show();
return a.exec();
}
main.cpp文件
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
界面头文件
ui_widget.h
/********************************************************************************
** Form generated from reading UI file 'widget.ui'
**
** Created by: Qt User Interface Compiler version 5.9.3
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_WIDGET_H
#define UI_WIDGET_H
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Widget
{
public:
QPushButton *pushButton;
void setupUi(QWidget *Widget)
{
if (Widget->objectName().isEmpty())
Widget->setObjectName(QStringLiteral("Widget"));
Widget->setEnabled(false);
Widget->resize(927, 533);
QIcon icon;
icon.addFile(QStringLiteral("../../python3_project/heihei.png"), QSize(), QIcon::Normal, QIcon::Off);
Widget->setWindowIcon(icon);
Widget->setWindowOpacity(0.5);
pushButton = new QPushButton(Widget);
pushButton->setObjectName(QStringLiteral("pushButton"));
pushButton->setGeometry(QRect(430, 250, 106, 29));
retranslateUi(Widget);
QObject::connect(pushButton, SIGNAL(clicked()), Widget, SLOT(close()));
QMetaObject::connectSlotsByName(Widget);
} // setupUi
void retranslateUi(QWidget *Widget)
{
Widget->setWindowTitle(QApplication::translate("Widget", "MyWidget", Q_NULLPTR));
pushButton->setText(QApplication::translate("Widget", "PushButton", Q_NULLPTR));
} // retranslateUi
};
namespace Ui {
class Widget: public Ui_Widget {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_WIDGET_H
补充资料 1:
使用new创建对象指针
使用delete删除对象指针
使用new创建对象对象的同时,会返回对象的指针,因此,我们需要定义一个类的指针变量来接收返回的对象指针.
ClassName *object=new ClassName(param);
delete object;
除了这种通过new方法创建对象外,还有我们最常用的创建对象的方式:
ClassName object(param);
这样就声明了一个ClassName类型的object对象,C++会为它分配足够的存放对象所有成员的存储空间.
注意:为节省存储空间,C++创建对象时仅分配用于保存数据成员的空间,而类中定义的成员函数则被分配到存储空间中的一个公用区域,由该类的所有对象共享.
这种方法创建的对象,内存分配是分配到栈中的,由C++缺省创建和撤销,自动调用构造函数和析构函数.
注意:该方法创建的对象调用类方法时,必须用“.”,而不能用“->”.
使用这种方式创建的类对象,在创建之初就已经分配了内存空间. 而类指针,如果未经过对象初始化,则不需要delete释放, 因为没有初始化就没有为指针绑定的对象分配内存.
一般来说,编译器将内存分为三部分:静态存储区域、栈、堆。静态存储区主要保存全局变量和静态变量,栈存储调用函数相关的变量、地址等,堆存储动态生成的变量
C++中有三种创建对象的方法:
#include <iostream>
using namespace std;
class A
{
private:
int n;
public:
A(int m):n(m)
{ }
~A(){}
};
int main()
{
A a(1); //栈中分配
A b = A(1); //栈中分配
A* c = new A(1); //堆中分配
delete c;
return 0;
}
第一种和第二种没什么区别,一个隐式调用,一个显式调用,两者都是在进程虚拟地址空间中的栈中分配内存,而第三种使用了new,在堆中分配了内存,而栈中内存的分配和释放是由系统管理,而堆中内存的分配和释放必须由程序员手动释放。采用第三种方式时,必须注意一下几点问题:
new创建类对象需要指针接收,一处初始化,多处使用
new创建类对象使用完需delete销毁
new创建对象直接使用堆空间,而局部不用new定义类对象则使用栈空间
new对象指针用途广泛,比如作为函数返回值、函数参数等
频繁调用场合并不适合new,就像new申请和释放内存一样
栈的大小远小于堆的
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率 比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在 堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会 分 到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。
补充资料 2
什么是堆内存?什么是栈内存?
栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结
构中的栈。
内存中的栈区处于相对较高的地址以地址的增长方向为上的话,栈地址是向下增长的。
栈中分配局部变量空间,堆区是向上增长的用于分配程序员申请的内存空间。另外还有静态区是分配静态变量,全局变量空间的;只读区是分配常量和程序代码空间的;以及其他一些分区。
网友评论