Qt6.0開發 第二章 GUI程序設計基礎
第二章 GUI程序設計基礎
窗口相關文件
按照第一章所給提示創建一個新project,我們得到了下面的代碼:
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
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;
}
main.cpp:
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
上面的內容便是一個完整的新項目的代碼部分了.
下面我們將逐文件逐語句對其進行解釋:
widget.h
首先對最外層的宏進行分析,不難發現,這是從C語言開始防止重復include的宏設計:
#ifndef WIDGET_H
#define WIDGET_H
//...
#endif // WIDGET_H
include語句將QWidget引入,以便對QWidget類進行繼承:
#include <QWidget>
在include語句后又定義了一個繼承自QWidget的自定義Widget類.
同時,其還聲明了一個名稱為Ui的名稱空間:
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
注意:此處的Widget不是此文件中的Widget,而是ui_widget中定義的一個類,所以我們區分Ui::Widget是窗口ui類,是為了用于描述可視化設計的窗口界面的.
下面即為Widget的定義了.
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
widget.cpp
在其中,首先就和一般C++多文件程序一樣,同名的.cpp文件對包含類聲明與形式定義的.h文件進行include.
#include "widget.h"
接著對自定義Widget類的構造函數進行了定義:
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
結合widget.h中的聲明:
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
解釋上面initial-list的代碼,有:
:QWidget(parent)//從父QWidget繼承,同時默認為nullptr
,ui(new Ui::Widget)//存在一個新分配的Ui::Widget
然后對構造函數函數體進行解釋:
ui->setupUi(this);//通過Ui::Widget對自定義Widget的Ui進行裝載
在setupUi()中會創建窗口上的所有界面組件,并且以Widget窗口作為所有組建的父容器.
而析構函數中則為簡單的釋放Ui::Widget對象.
delete ui;
注意:ui_widget.h是UI文件widget.ui被UIC編譯后自動生成的文件.該文件中定義了窗口UI類.
#include "ui_widget.h"
main.cpp
開門見山,對自定義widget.h的include:
#include "widget.h"
接著由于函數體中要對QApplication進行初始化,對QApplication進行include:
#include <QApplication>
主函數體本身沒有太大變化:
int main(int argc, char *argv[])
{
//do something
}
而其中每一句語句的含義見下:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);//定義并創建應用程序
Widget w;//定義并創建窗口對象
w.show();//顯示窗口
return a.exec();//運行應用程序,開始應用程序的消息循環和事件處理
}
界面組件布局管理
Qt的UI設計具有布局(layout)功能.所謂布局,就是指界面上組件的排列方式.
伙伴關系
點擊Qt Designer工具欄上的Edit Buddies按鈕進入伙伴關系編輯狀態.
在伙伴狀態下可以選中一個標簽,按住鼠標左鍵將其拖向控件.
將擁有伙伴關系的標簽text屬性改為<name>+(&+<char>)形式的字串.則在運行時按下alt+<char>便可跳轉焦點至相關控件.
Tab順序
點擊Qt Designer工具欄上的Edit Tab Order按鈕進入Tab順序編輯狀態.
Tab順序是指程序在運行時,按下鍵盤上Tab鍵時輸入焦點的移動順序.
進入Tab順序編輯狀態后,界面上會顯示具有Tab順序的組件的Tab順序編號,依次按希望的順序點擊組件就可以重排Tab順序.
信號與槽
信號(signal): 特定情況下被發射的通知.GUI程序設計的主要工作就是對界面上各組件的信號進行響應.
槽(slot): 是對信號進行響應的函數.槽就是函數,所以也稱槽函數.槽函數與一般函數不同的是:槽函數與信號關聯,當信號被發射時,關聯的槽函數被自動運行.
信號與槽是通過QObject::connect()實現的,使用connect()函數的基本格式為:
QObject::connect(sender, SIGNAL(signal()),receiver,SLOT(slot()));
其中,sender是發射信號的對象的名稱;signal()是信號,信號可以看作特殊的函數,需要帶有括號,有參數時還需要指名各參數類型;receiver是接收信號的對象的名稱;slot()是槽函數,需要帶有括號,有參數時還需要指名各參數類型.
SIGNAL和SLOT是Qt的宏,分別用于指明信號和槽函數,并將它們的參數轉換為相應的字符串.
關于信號與槽的使用,有下列規則:
-
一個信號可以連接多個槽函數.
-
多個信號可以連接一個槽函數.
-
一個信號可以連接另一個信號,如:
connect(spinNum,SIGNAL(signal_1(int)),this,SIGNAL(signal_2(int)));
-
嚴格的情況下,信號與槽的參數個數與類型需要一致,至少信號參數不能少于槽參數.
-
在使用信號與槽的類中,必須在類的定義中插入宏Q_OBJECT.
-
當一個信號被發射時,與其關聯的槽函數通常被立即運行,只有所有所有關聯槽函數運行完,才運行發射信號后的代碼.
Qt的界面組件都是從QWidget繼承而來的,都支持信號與槽的功能.每個類都有一些內建的信號和槽函數.
信號與槽的使用
如果需要通過Qt Designer可視化設計某個組件的信號的槽函數,選擇Qt Designer下側Action編輯器旁邊的 Signals and Slots Editor 進行新增即可.
如果希望手動對信號的槽函數進行定義,而非直接生成在ui_widget.h中.那么可以選擇一個組件,然后右鍵選擇 "轉到槽..."
實例:第一個Qt應用程序
選擇Dialog類開始,且不繼承(即不需要ui界面輔助)
Dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QCheckBox>
#include <QPushButton>
#include <QRadioButton>
#include <QPlainTextEdit>
#include <QHBoxLayout>
#include <QVBoxLayout>
class QPlainTextEdit;
class QRadioButton;
class QPushButton;
class QCheckBox;
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = nullptr);
~Dialog();
private:
QCheckBox *chkBoxUl,*chkBoxIt,*chkBoxBf;
QPushButton *btnOk,*btnExit,*btnClear;
QRadioButton *radioBlack,*radioRed,*radioBlue;
QPlainTextEdit *txtEdit;
private slots:
//勾選框
void do_checkBoxUl(bool checked);
void do_checkBoxBf(bool checked);
void do_checkBoxIt(bool checked);
//按鈕
void do_pushButtonOk();
void do_pushButtonExit();
void do_pushButtonClear();
//選擇框
void do_radioColor();
//測試自定義信號
void do_reactionToSignal();
signals:
void do_checkedRadio();
};
#endif // DIALOG_H
Dialog.cpp
#include "dialog.h"
void Dialog::do_checkBoxUl(bool checked)
{
QFont font= txtEdit->font();
font.setUnderline(checked);
txtEdit->setFont(font);
return;
}
void Dialog::do_checkBoxIt(bool checked)
{
QFont font= this->txtEdit->font();
font.setItalic(checked);
this->txtEdit->setFont(font);
return;
}
void Dialog::do_checkBoxBf(bool checked)
{
QFont font= this->txtEdit->font();
font.setBold(checked);
this->txtEdit->setFont(font);
return;
}
void Dialog::do_pushButtonOk()
{
emit do_checkedRadio();
//this->accept();
return;
}
void Dialog::do_pushButtonExit()
{
this->close();
return;
}
void Dialog::do_pushButtonClear()
{
txtEdit->clear();
return;
}
void Dialog::do_radioColor()
{
QPalette plet= txtEdit->palette();
if(radioBlack->isChecked())
plet.setColor(QPalette::Text,Qt::black);
if(radioRed->isChecked())
plet.setColor(QPalette::Text,Qt::red);
if(radioBlue->isChecked())
plet.setColor(QPalette::Text,Qt::blue);
txtEdit->setPalette(plet);
return;
}
void Dialog::do_reactionToSignal()
{
QPalette plet= txtEdit->palette();
plet.setColor(QPalette::Text,Qt::green);
txtEdit->setPalette(plet);
return;
}
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
//新建豎向布局
QVBoxLayout *VLay= new QVBoxLayout;
//勾選框
chkBoxUl= new QCheckBox("下劃線");
chkBoxIt= new QCheckBox("傾斜體");
chkBoxBf= new QCheckBox("加粗體");
QHBoxLayout *HLay1= new QHBoxLayout;
HLay1->addWidget(chkBoxUl);
HLay1->addWidget(chkBoxIt);
HLay1->addWidget(chkBoxBf);
connect(chkBoxUl,SIGNAL(clicked(bool)),this,SLOT(do_checkBoxUl(bool)));
connect(chkBoxIt,SIGNAL(clicked(bool)),this,SLOT(do_checkBoxIt(bool)));
connect(chkBoxBf,SIGNAL(clicked(bool)),this,SLOT(do_checkBoxBf(bool)));
//選擇框
radioBlack= new QRadioButton("黑色");
radioRed= new QRadioButton("紅色");
radioBlue= new QRadioButton("藍色");
QHBoxLayout *HLay2= new QHBoxLayout;
HLay2->addWidget(radioBlack);
HLay2->addWidget(radioRed);
HLay2->addWidget(radioBlue);
connect(radioBlack,SIGNAL(clicked()),this,SLOT(do_radioColor()));
connect(radioRed,SIGNAL(clicked()),this,SLOT(do_radioColor()));
connect(radioBlue,SIGNAL(clicked()),this,SLOT(do_radioColor()));
//按鈕
btnOk= new QPushButton("確定");
btnClear= new QPushButton("清除");
btnExit= new QPushButton("退出");
QHBoxLayout *HLay3= new QHBoxLayout;
HLay3->addWidget(btnOk);
HLay3->addWidget(btnClear);
HLay3->addWidget(btnExit);
connect(btnOk,SIGNAL(clicked()),this,SLOT(do_pushButtonOk()));
connect(btnClear,SIGNAL(clicked()),this,SLOT(do_pushButtonClear()));
connect(btnExit,SIGNAL(clicked()),this,SLOT(do_pushButtonExit()));
//文本欄
txtEdit= new QPlainTextEdit;
txtEdit->setPlainText("Qt6.0 學習\n第二章 項目二");
//測試自定義信號函數
connect(this,SIGNAL(do_checkedRadio()),this,SLOT(do_reactionToSignal()));
VLay->addLayout(HLay1);
VLay->addLayout(HLay2);
VLay->addWidget(txtEdit);
VLay->addLayout(HLay3);
//布局應用
setLayout(VLay);
}
Dialog::~Dialog() {}
main.cpp則默認即可.
最后,最重要的建議:去看視頻跟著學,里面很多書里沒有的操作https://www.bilibili.com/video/BV1km4y1k7CW

浙公網安備 33010602011771號