1. 程式人生 > >QT入門(一)Qt工程簡介、訊號與槽初步練習

QT入門(一)Qt工程簡介、訊號與槽初步練習

QT程式結構

程式特點

  • 跟普通程式一樣,標頭檔案,原始檔,工程檔案.pro
  • 標頭檔案特點

    • QT系統標頭檔案沒有.h
    • 標頭檔案和類名一樣
    • 命名Q開頭,前兩個字母大寫
  • 工程檔案.Pro的相關介紹

# 模組
QT  += core gui
# 高於4版本新增本句內容,增加相容
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
# 生成程式的名稱
TARGET = my_first

# 指定Makefile生成的型別 app lib···
TEMPLATE = app

#警告資訊
DEFINES += QT_DEPRECATED_WARNINGS

# 原始檔
SOURCES += \ main.cpp \ mywidget.cpp # 標頭檔案 HEADERS += \ mywidget.h # 增加對C++11的支援 CONFIG += C++11
  • 特點
    一個程式有多個物件時,預設情況下各個物件(視窗)是相互獨立的,只有指定父類情況下,物件間才產生依賴關係,例如想在視窗物件上,建立一個按鈕物件,那麼按鈕物件的父物件應該被設定為視窗物件。依賴關係確定只要父物件顯示,那麼子物件就會顯示出來,子物件可以不必呼叫自身顯示函式。
#include<QPushbutton>
int main(int argc,char **argv)
{
    QApplication a(argc,argv);
QWidget w; w.setWindowTitle("李京京"); QPushButton b; b.setParent(&w); b.setText("張超"); b.move(100,100); QPushButton b1(&w); b1.setText("李京京"); b1.move(200,100); /* *如果不指定父物件,物件和物件(視窗和視窗沒有關係),獨立 *a指定b為他的物件,a放在b的上面 *指定父物件有兩種方式: * 1)setParent * 2)通過建構函式傳參 *指定父物件,只要父物件顯示,上面的子物件自動顯示(不必在呼叫子物件顯示函式) */
w.show(); return a.exec(); }
  • 視窗物件
    視窗或者其它可視物件建立以後,預設是隱藏的,只有呼叫顯示函式時才會顯示,編譯執行程式時,如果沒有呼叫顯示函式,雖然沒有看到任何東西,但程式已經在運行了,預設等不到使用者處理它就會一直執行,我們可以通過工作管理員將它殺掉,或者通過IDE停止按鈕將程式結束執行。

訊號與槽

訊號連線函式
connect(發出訊號的物件地址,訊號及所在類的地址,接收訊號物件的地址,接受者的處理函式(槽函式)地址)
自定義訊號
需要signals:關鍵字修飾,訊號形式類似函式宣告,只宣告不填充訊號發射用emit關鍵字修飾,槽函式與訊號型別需要一致,無返回值,有無引數需要與訊號形式保持一致。
訊號過載
訊號同名,不同引數時產生訊號過載,connect函式不能區分訊號型別而產生錯誤,需要用函式指標來進行區分,最好不要用QT4方式。QT4方式雖然簡單編譯階段不能檢測訊號是否正確,只有在執行時才能檢測到錯誤與否,對於大型軟體專案,此類方法並不好

//定義兩個過載訊號
signals:
    void mysignal();
    void mysignal(int,QString);

//定義訊號發射    
void SubWidget::myslot2()
{
    emit mysignal();
    emit mysignal(100,"1234");
}

//利用函式指標區分過載訊號,避免二義性的產生
//函式指標需要新增定義域
//呼叫函式指標時直接呼叫即可
void (SubWidget::*funcSignal1)()=&SubWidget::mysignal;
void (SubWidget::*funcSignal2)(int,QString)=&SubWidget::mysignal;
connect(&w2,funcSignal1,this,&MainWidget::myslot3);
connect(&w2,funcSignal2,this,&MainWidget::myslot4);

Lambda函式
自定義槽函式需要宣告、填充很麻煩,可以採用lambda函式,直接將槽函式函式體寫在訊號與槽的函式內部Lambda函式(匿名函式)是C++11以後新增的新特性,我們可以利用Lambda函式,代替槽函式,避免了槽函式宣告構造等,增加程式碼效率,直接將槽函式寫在函式體內部,使用時需要在工程檔案裡面新增CONFIG += C++11

 connect(&w2,&SubWidget::mysignal,this,&MainWidget::myslot3);
 void MainWidget::myslot3()
{
    this->show();
    w2.hide();
}

//利用匿名函式,直接將函式體寫在連線函式內部比上面的寫法要簡潔
//【】中=代表將區域性變數或者類中成員物件以值的方式傳入函式體
//預設傳入引數屬性是隻讀屬性,若想改變引數的值需要加mutable關鍵字[=]()mutable
connect(&w2,&SubWidget::mysignal,[=]()
{
    this->show();
    w2.hide();
}
);

實現主副視窗切換的QT程式(入門程式)

檔案main.cpp mainwidget.cpp subwidget.h mainwidget.h subwidget.h Signal.pro

//main.cpp
#include "mainwidget.h"
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //定義主視窗物件
    MainWidget w;

    //視窗標題
    w.setWindowTitle("這是主視窗");

    //視窗顯示
    w.show();
    return a.exec();
}
//mainwidget.c
#include "mainwidget.h"
#include <QDebug>
//主視窗建構函式
MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
{
    //b1按鈕設定
    b1.setParent(this);
    b1.setText("切換副視窗");
    b1.move(100,100);

    //b1訊號處理
    connect(&b1,&QPushButton::pressed,this,&MainWidget::myslot1);

    //副視窗標題設定
    w2.setWindowTitle("這是副視窗");

    //副視窗訊號處理
    connect(&w2,&SubWidget::mysignal,this,&MainWidget::myslot3);
    //調整視窗解析度
    resize(400,300);
}
MainWidget::~MainWidget()
{

}
//自定義槽函式1
void MainWidget::myslot1()
{
    this->hide();
    w2.show();
}
//自定義槽函式3
void MainWidget::myslot3()
{
    this->show();
    w2.hide();
}
//subwidget.cpp
#include "subwidget.h"
//副視窗建構函式
SubWidget::SubWidget(QWidget *parent) : QWidget(parent)
{
    //b2按鈕設定
    b2.setParent(this);
    b2.setText("切換到主視窗");
    b2.move(100,100);

    //修改解析度
    resize(400,300);

    //b2按鈕訊號處理
    connect(&b2,&QPushButton::pressed,this,&SubWidget::myslot2);
}
//槽函式2
void SubWidget::myslot2()
{
    //發射訊號  用emit修飾
    emit mysignal();
}
//mainwidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QWidget>
#include <QPushButton>
#include "subwidget.h"
class MainWidget : public QWidget
{
    Q_OBJECT

public:
    MainWidget(QWidget *parent = 0);
    ~MainWidget();
    //宣告槽函式
    void myslot1();
    void myslot3();
private:
QPushButton b1;
SubWidget w2;
};

#endif // MAINWIDGET_H
//subwidget.h
#ifndef SUBWIDGET_H
#define SUBWIDGET_H

#include <QWidget>
#include <QPushButton>
class SubWidget : public QWidget
{
    Q_OBJECT
public:
    explicit SubWidget(QWidget *parent = nullptr);
    //宣告槽函式
    void myslot2();
signals:
    //定義自定義訊號 只宣告不定義  需要signals關鍵字修飾 
    void mysignal();
public slots:
private:
    QPushButton b2;
};

#endif // SUBWIDGET_H
//Signal.pro
//新增模組
QT       += core gui

//新增對QT4以上版本的支援  增加相容性
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

//目標程式名字
TARGET = Signal
TEMPLATE = app

//編譯警告輸出
DEFINES += QT_DEPRECATED_WARNINGS

//原始檔
SOURCES += \
        main.cpp \
        mainwidget.cpp \
    subwidget.cpp

//標頭檔案
HEADERS += \
        mainwidget.h \
    subwidget.h

記憶體釋放

QT中從 Q_OBJECT開始,會為每個物件建立記憶體依賴樹,當物件使用完畢不用,手動釋放記憶體,記憶體會被自動釋放掉

//申請記憶體空間定義一個按鈕
b3 =new QPushButton(this);
b3->setText("小按鈕");
b3->move(50,50);

//不定義delete手動釋放記憶體,直接關閉視窗
MainWidget::~MainWidget()
{
    qDebug()<<"物件被析構";
}

//能夠看到仍然能夠進入解構函式

座標系統

每個物件都會以父物件的左上角為(0,0)座標原點