QT從入門到入土(二)——對象模型(對象樹)和窗口坐標體系


摘要

我們使用的標准 C++,其設計的對象模型雖然已經提供了非常高效的 RTTI 支持,但是在某些方面還是不夠靈活。比如在 GUI 編程方面,既需要高效的運行效率也需要強大的靈活性,諸如刪除某窗口時可不想把子窗口用代碼一個個去析構。Qt 將這兩者的優點完美的結合在了一起,創造出了特有的對象模型(Qt Object Model)。


一,Qt的基本框架

在上一篇中,我們已經完成了Qt的安裝和VS的環境配置。QT從入門到入土(一)——Qt5.14.2安裝教程和VS2019環境配置 - 唯有自己強大 - 博客園 (cnblogs.com)

在講解對象樹之前,我們先來熟悉一下Qt的基本框架。首先新建一個項目:

  •  main.cpp分析

打開sources里面的main.cpp,可以看到以下代碼:

注意:

  1. 每個Qt程序有且只能有一個QApplication對象,沒有會報錯。
  2. Qt里面的頭文件和類名是一致的,知道頭文件就知道類名,反之亦然
  3. Qt頭文件是沒有.h的,基本都是以大寫的Q開頭

根據以上的分析,我們可以得出Qt的程序框架代碼:

#include <QApplication>      
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);  
     /*
       在這里寫你的代碼
     */     
    return a.exec();      
}
  • widget.h和widget.cpp分析

打開Headers里面的widget.h,和sources里面的widget.app,可以看到以下代碼:

 

最上面的MyfirstQt.pro,是管理項目的文件,用來存儲項目設置。

后綴為“.pro”的文件是項目的管理文件,文件名就是項目的名稱,如本項目中的 MyfirstQt.pro。(類似與VS工程的.sln文件)

💛💛實例(用代碼創建一個button):

幫助文檔的快捷鍵:第一種方式:F1 第二種方式:Qt左側按鈕 第三種方式:D:\Qt\Qt5.14.2\5.14.2\mingw73_64\bin\assistant

因為創建一個button需要QPushButton 類,因此我們可以在幫助文檔中查到相關的信息:

 代碼實現:

#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>//按鈕控件的頭文件

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //創建第一個按鈕
    QPushButton *btn=new QPushButton;
    //不能用btn->show();//show是以頂層方式彈出控件
    //讓btn在widget窗口顯示
    btn->setParent(this);//this指向當前對象的指針(即widget的地址)
    //顯示文本
    btn->setText("第一個按鈕");
    //創建第二個按鈕
    //注意:這種方法是按照按鈕的大小創建窗口
    QPushButton *btn2=new QPushButton("第二個按鈕",this);
    //移動btn2的位置(由於創建的兩個按鈕位置重疊了)
    btn2->move(100,100);
    //因此需要重置窗口大小
    resize(600,400);

    //設置窗口標題
    setWindowTitle("唯有自己強大");
}

二,對象模型(對象樹)

💚💚什么是對象樹?

我們常常聽到 QObject 會用對象樹來組織管理自己,那什么是對象樹?

這個概念非常好理解。因為 QObject 類就有一個私有變量 QList<QObject *>,專門存儲這個類的子孫后代們。比如創建一個 QObject 對象並指定父對象時,就會把自己加入到父對象的 childre() 列表中,也就是 QList<QObject *> 變量中。

 父對象析構的時候,這個列表中的所有對象也會被析構。注意,這 里的父對象並不是繼承意義上的父類!)

舉個例子,有一個窗口 Window,里面有 Label標簽、TextEdit文本輸入框、Button按鈕這三個元素,並且都設置 Window 為它們的父對象。這時候我做了一個關閉窗口的操作,作為程序員的你是不是自然想到將所有和窗口相關的對象析構啊?古老的辦法就是一個個手動 delete 唄。是不是很麻煩?Qt 運用對象樹模式,當父對象被析構時,子對象自動就 delete 掉了,不用再寫一大堆的代碼了。

QWidget 是能夠在屏幕上顯示的一切組件的父類(QWidget 繼承自 QObject,因此也繼承了這種對象樹關系。)

💛💛注意構建/析構 QObject 的順序問題

 正常情況下,最后被創建出來的會先被析構掉。就好比我有一個大桌子,上面先擺放一個盤子,再擺放一個碗。當我要把桌子撤掉的時候,會先撤掉碗,再撤掉盤子,最后撤掉桌子。

用代碼來演示一下:

int main()
{
     QWidget window;
     QPushButton quit("Quit", &window);
}

后創建的 quit 對象指定了 window 為其父對象。那么關閉程序時,會先調用它的析構函數,然后調用 window 的析構函數。

這就牽扯到一個特殊情況:

int main()
{
    QPushButton quit("Quit");
    QWidget window;
 
    quit.setParent(&window);
}

如果反過來,由於 window 后創建,程序關閉時先調用 window 的析構函數(此時 quit 被第一次析構)。接着調用 quit 的析構函數(此時 quit 被第二次析構),這時由於被兩次析構,所以出問題了。

這種特殊情況在編程中很隱蔽,不容易發現。因為編譯的時候不會報錯,只有運行時才會產生問題。

我們最好從開始就養成良好習慣,在 Qt 中,盡量在構 造的時候就指定 parent 對象,並且大膽在堆上創建。

三,Qt窗口坐標體系

Qt的窗口坐標系以左上角為原點,X 向右增加,Y 向下增加。(和opencv一樣)

 對於嵌套窗口,其坐標是相對於父窗口來說的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM