博客地址已更改,文章數量較多不便批量修改,若想訪問源文請到 coologic博客 查閱,網址:www.coologic.cn
如本文記錄地址為 techieliang.com/A/B/C/ 請改為 www.coologic.cn/A/B/C/ 即可查閱
版權聲明:若無來源注明, Techie亮博客文章均為原創。 轉載請以鏈接形式標明本文標題和地址:
本文標題:QWidget一生,從創建到銷毀事件流 本文地址: http://techieliang.com/2017/11/319/
最近做UI,有多個窗口嵌套,且所有窗口均用了Layout布局,當運行程序時,主窗口布局有效,而嵌套的窗口布局未生效。
1. 構造函數Resize()
首先我想到的是,我設置了Layout,那么他會自動調整大小,是不是在創建子窗口的時候並沒有獲取到此窗口在父類布局中占用的位置?那么我在構造的時候分別設置每個子窗口即可。
child_widget->Resize(this->XXXX->size());//XXXX是子窗口一個widget的區域,或者qstackedwidget等某個頁面的大小
使用上述類似的指令去重新設置,發現沒有任何效果。而根本原因是構造函數中獲得的Size()並不對,不是主窗口的真實尺寸。
2. 笨方法-QTimer()
由於時間關系,使用了笨方法。無論如何最后構造完成以后肯定窗口顯示了。。。。
那么建立一個定時器,構造的時候啟動定時器,連接到槽,然后timeout()以后執行Resize指令,並且stop Timer。。。
此方法確實解決了布局適應的問題,但是建立一個timer,方法並不友好
3. QWidget構造到銷毀事件流分析
此處為了方便,不對QWidget做范例分析,直接用QMainWindow做分析,QMainWindow是QWidget的子類。
下面會詳細說明分析方法,若需要對QWidget或者其他控件做分析,可以仿照進行。
3.1. 實驗項目配置
直接新建一個Qt Widgets項目,為了測試方便,我把默認的菜單欄、工具欄、狀態欄都取消了,只添加了一個QPushButton按鈕控件。
程序代碼如下:
*.pro
- QT += core gui
- greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
- TARGET = untitled
- TEMPLATE = app
- DEFINES += QT_DEPRECATED_WARNINGS
- SOURCES += \
- main.cpp \
- mainwindow.cpp
- HEADERS += \
- mainwindow.h
- FORMS += \
- mainwindow.ui
mainwindow.ui
- <?xml version="1.0" encoding="UTF-8"?>
- <ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>400</width>
- <height>300</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>MainWindow</string>
- </property>
- <widget class="QWidget" name="centralWidget">
- <widget class="QPushButton" name="pushButton">
- <property name="geometry">
- <rect>
- <x>190</x>
- <y>150</y>
- <width>89</width>
- <height>24</height>
- </rect>
- </property>
- <property name="text">
- <string>PushButton</string>
- </property>
- </widget>
- </widget>
- </widget>
- <layoutdefault spacing="6" margin="11"/>
- <resources/>
- <connections/>
- </ui>
main.cpp
- #include "mainwindow.h"
- #include <QApplication>
- int main(int argc, char *argv[]) {
- QApplication a(argc, argv);
- MainWindow w;
- w.show();
- return a.exec();
- }
mainwindow.h
- #pragma once
- #include <QMainWindow>
- namespace Ui {
- class MainWindow;
- }
- class MainWindow : public QMainWindow {
- Q_OBJECT
- public:
- explicit MainWindow(QWidget *parent = 0);
- ~MainWindow();
- protected:
- bool event(QEvent *event) Q_DECL_OVERRIDE;
- private:
- Ui::MainWindow *ui;
- };
mainwindow.cpp
- #include "mainwindow.h"
- #include "ui_mainwindow.h"
- #include <QEvent>
- #include <QDebug>
- MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::MainWindow) {
- qDebug()<<"Befor ui->setupUi(this)";
- ui->setupUi(this);
- qDebug()<<"After ui->setupUi(this)";
- }
- MainWindow::~MainWindow() {
- delete ui;
- }
- bool MainWindow::event(QEvent *event) {
- qDebug()<<event->type();
- QMainWindow::event(event);
- }
其實項目很簡單,就是直接重寫了event(QEvent *event)函數,利用qDebug()輸出事件類型。
事件類型通過type調用,返回TYPE枚舉類型,此類型在“qcoreevent.h”文件夾存儲
- enum Type {
- None = 0, // invalid event
- Timer = 1, // timer event
- MouseButtonPress = 2, // mouse button pressed
- MouseButtonRelease = 3, // mouse button released
- MouseButtonDblClick = 4, // mouse button double click
- MouseMove = 5, // mouse move
- KeyPress = 6, // key pressed
- KeyRelease = 7, // key released
- FocusIn = 8, // keyboard focus received
- FocusOut = 9, // keyboard focus lost
- FocusAboutToChange = 23, // keyboard focus is about to be lost
- Enter = 10, // mouse enters widget
- Leave = 11, // mouse leaves widget
- Paint = 12, // paint widget
- Move = 13, // move widget
- Resize = 14, // resize widget
- Create = 15, // after widget creation
- ……………………………………………………………………//太多了,具體自行查看
- };
3.2. 結果
直接運行程序就出現了結果,從運行到窗口創建完畢:
同時在main()函數中每個位置增加斷點可以看到不同指令的詳細執行效果。
- Befor ui->setupUi(this)//構造函數開始----MainWindow?w;
- QEvent::Type(ChildAdded)
- QEvent::Type(WindowTitleChange)
- After ui->setupUi(this)//構造函數結束---MainWindow?w結束;
- QEvent::Type(PlatformSurface)//---w.show()開始;
- QEvent::Type(WinIdChange)
- QEvent::Type(WindowIconChange)//icon
- QEvent::Type(Polish)//style polish
- QEvent::Type(ChildPolished)
- QEvent::Type(Move)//調整窗口位置
- QEvent::Type(Resize)//調整窗口尺寸
- QEvent::Type(Show)//顯示
- QEvent::Type(CursorChange)
- QEvent::Type(ShowToParent)
- QEvent::Type(PolishRequest)
- QEvent::Type(LayoutRequest)
- QEvent::Type(UpdateLater)
- QEvent::Type(UpdateRequest)//---w.show()結束
- QEvent::Type(WindowActivate)//---a.exec()
- QEvent::Type(ActivationChange)
- QEvent::Type(Paint)//---a.exec()結束
關閉窗口:
- QEvent::Type(NonClientAreaMouseMove)//鼠標移動到關閉
- QEvent::Type(NonClientAreaMouseButtonPress)//點擊右上角關閉
- QEvent::Type(Close)
- QEvent::Type(WindowDeactivate)
- QEvent::Type(ActivationChange)
- QEvent::Type(Hide)
- QEvent::Type(HideToParent)
- QEvent::Type(UpdateRequest)
3.3. 結果分析
通過構造的事件流可以看到,Qt的設置各個控件的尺寸的操作在構造函數之后,所以在構造函數用Size獲取到的尺寸是錯誤的。
Qt的Event類型有很多,發型不同類型的事件會調用對應的函數,可以看QWidget的API,上述發生事件部分對照關系已經在注釋中寫出,下面總結一下主要的事件流,出現的先后順序就是事件發生順序:
MainWindow?w;
- 調用構造函數
w.show();
- QStyle::polish()
- QWidget::moveEvent()
- QWidget::resizeEvent()
- QWidget::showEvent()—–在這里刷新所有嵌入的子頁面的size即可實現自適應
a.exec();
- QWidget::ensurePolished()
- QWidgetBackingStore::sync()
- QWidget::paintEvent()
退出:
- QWidget::closerEvent()
