在Qt5項目中要想讓程序運行時顯示出我們設計的界面逆甜,關鍵是要執(zhí)行界面文件生成的類中的setupUi(QWidget *Widget)函數(shù)镰吆,否則界面是無法顯示出來的.
首先芒粹,我們來看一下自動生成的Qt5項目中是如何調(diào)用界面類中的setupUi()函數(shù)的.
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類的構造函數(shù)實現(xiàn)了對類Widget子對象ui實現(xiàn)了初始化操作
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this); #這里的this就是調(diào)用構造函數(shù)的對象
}
一種與上面等效的簡單直接的方式如下:
#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創(chuàng)建對象指針
使用delete刪除對象指針
使用new創(chuàng)建對象對象的同時,會返回對象的指針诅福,因此匾委,我們需要定義一個類的指針變量來接收返回的對象指針.
ClassName *object=new ClassName(param);
delete object;
除了這種通過new方法創(chuàng)建對象外,還有我們最常用的創(chuàng)建對象的方式:
ClassName object(param);
這樣就聲明了一個ClassName類型的object對象氓润,C++會為它分配足夠的存放對象所有成員的存儲空間.
注意:為節(jié)省存儲空間赂乐,C++創(chuàng)建對象時僅分配用于保存數(shù)據(jù)成員的空間,而類中定義的成員函數(shù)則被分配到存儲空間中的一個公用區(qū)域咖气,由該類的所有對象共享.
這種方法創(chuàng)建的對象挨措,內(nèi)存分配是分配到棧中的,由C++缺省創(chuàng)建和撤銷崩溪,自動調(diào)用構造函數(shù)和析構函數(shù).
注意:該方法創(chuàng)建的對象調(diào)用類方法時运嗜,必須用“.”,而不能用“->”.
使用這種方式創(chuàng)建的類對象悯舟,在創(chuàng)建之初就已經(jīng)分配了內(nèi)存空間. 而類指針,如果未經(jīng)過對象初始化砸民,則不需要delete釋放, 因為沒有初始化就沒有為指針綁定的對象分配內(nèi)存.
一般來說抵怎,編譯器將內(nèi)存分為三部分:靜態(tài)存儲區(qū)域、棧岭参、堆反惕。靜態(tài)存儲區(qū)主要保存全局變量和靜態(tài)變量,棧存儲調(diào)用函數(shù)相關的變量演侯、地址等姿染,堆存儲動態(tài)生成的變量
C++中有三種創(chuàng)建對象的方法:
#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;
}
第一種和第二種沒什么區(qū)別,一個隱式調(diào)用,一個顯式調(diào)用悬赏,兩者都是在進程虛擬地址空間中的棧中分配內(nèi)存狡汉,而第三種使用了new,在堆中分配了內(nèi)存闽颇,而棧中內(nèi)存的分配和釋放是由系統(tǒng)管理盾戴,而堆中內(nèi)存的分配和釋放必須由程序員手動釋放。采用第三種方式時兵多,必須注意一下幾點問題:
new創(chuàng)建類對象需要指針接收尖啡,一處初始化,多處使用
new創(chuàng)建類對象使用完需delete銷毀
new創(chuàng)建對象直接使用堆空間剩膘,而局部不用new定義類對象則使用椥普叮空間
new對象指針用途廣泛,比如作為函數(shù)返回值怠褐、函數(shù)參數(shù)等
頻繁調(diào)用場合并不適合new畏梆,就像new申請和釋放內(nèi)存一樣
棧的大小遠小于堆的
棧是機器系統(tǒng)提供的數(shù)據(jù)結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址惫搏,壓棧出棧都有專門的指令執(zhí)行具温,這就決定了棧的效率 比較高。堆則是C/C++函數(shù)庫提供的筐赔,它的機制是很復雜的铣猩,例如為了分配一塊內(nèi)存,庫函數(shù)會按照一定的算法(具體的算法可以參考數(shù)據(jù)結構/操作系統(tǒng))在 堆內(nèi)存中搜索可用的足夠大小的空間茴丰,如果沒有足夠大小的空間(可能是由于內(nèi)存碎片太多)达皿,就有可能調(diào)用系統(tǒng)功能去增加程序數(shù)據(jù)段的內(nèi)存空間,這樣就有機會 分 到足夠大小的內(nèi)存贿肩,然后進行返回峦椰。顯然,堆的效率比棧要低得多汰规。
補充資料 2
什么是堆內(nèi)存汤功?什么是棧內(nèi)存?
棧區(qū)(stack)— 由編譯器自動分配釋放 溜哮,存放函數(shù)的參數(shù)值滔金,局部變量的值等。其操作方式類似于數(shù)據(jù)結
構中的棧茂嗓。
內(nèi)存中的棧區(qū)處于相對較高的地址以地址的增長方向為上的話餐茵,棧地址是向下增長的。
棧中分配局部變量空間述吸,堆區(qū)是向上增長的用于分配程序員申請的內(nèi)存空間忿族。另外還有靜態(tài)區(qū)是分配靜態(tài)變量,全局變量空間的;只讀區(qū)是分配常量和程序代碼空間的道批;以及其他一些分區(qū)错英。