1 需求描述
由於項目需要,xx軟件的一些模塊均是以dockwidget的方式進行開發的,這樣便於實現靈活布局;但是在某些情況下需要全屏展示dockwidget中的內容,遺憾的是QDockWidget除了關閉按鈕,最小化、最大化按鈕都沒提供。
簡單整理下需求:在不影響QDockWidget正常功能情況下,當dockwidget懸浮時,自動出現最小化、最大化按鈕使窗口能夠最小化、最大化顯示。
2 設計思路
首先第一點,QDockWidget繼承QWidget,隱隱感覺還是好辦,應該問題不大,穩定情緒不要慌。
2.1 怎么動態獲取dockwidget的懸浮狀態?
當然是捕獲事件,經測試當dockwidget懸浮狀態改變時會觸發QEvent::ZOrderChange事件或topLevelChanged信號,我們只要捕獲到這個事件或信號就可以了。
2.2 怎么增加dockwidget的最小、最大化按鈕?
剛剛說了,QDockWidget繼承QWidget,通過setWindowFlags設置窗口的標記應該能滿足需求的。
3 代碼實現
理清思路后,下面開始實現,先通過事件處理,繼承QDockWidget重寫event函數,如下:
#ifndef CUSTOMDOCKWIDGET_H
#define CUSTOMDOCKWIDGET_H
#include <QDockWidget>
class CustomDockWidget : public QDockWidget
{
Q_OBJECT
public:
explicit CustomDockWidget(QWidget *parent = nullptr);
// QObject interface
public:
bool event(QEvent *event) override;
};
#endif // CUSTOMDOCKWIDGET_H
#include "CustomDockWidget.h"
#include <QEvent>
CustomDockWidget::CustomDockWidget(QWidget *parent) : QDockWidget(parent)
{
}
bool CustomDockWidget::event(QEvent *event)
{
if (QEvent::ZOrderChange == event->type()) {
if (isFloating()) {
QWidget w;
setMaximumSize(w.maximumSize());
setWindowFlags(Qt::Dialog
| Qt::WindowCloseButtonHint
| Qt::WindowMaximizeButtonHint
| Qt::WindowMinimizeButtonHint);
show();
}
}
return QDockWidget::event(event);
}
代碼邏輯很簡單,就不需要解釋什么了吧,捕獲QEvent::ZOrderChange事件,根據dockwidget懸浮狀態做對應處理。
setMaximumSize這里如果不設置,最大化按鈕會是灰色的,因為dockwidget懸浮后maximumSize會改變,maximumSize如果不夠大的話窗口就不能最大化。
最后那個show()是有必要的,不然雙擊標題欄后dockwidget會隱藏。
當然,這里也可以通過信號處理,直接連接topLevelChanged信號:
connect(this, &QDockWidget::topLevelChanged, [=]() {
if (isFloating()) {
QWidget w;
setMaximumSize(w.maximumSize());
setWindowFlags(Qt::Dialog
| Qt::WindowCloseButtonHint
| Qt::WindowMaximizeButtonHint
| Qt::WindowMinimizeButtonHint);
show();
};
});
最終的效果都一樣,但是重寫事件的方式可以實現更復雜的功能,靈活度更高,可以應對更復雜的需求。
4 總結
通過上述過程便完成了dockwidget的最大化、最小話的功能實現,並且對QDockWidget原有的功能也沒有副作用,效果不錯;但是就這樣了嗎?如果用戶想雙擊標題欄實現全屏效果怎么辦呢?捕獲NonClientAreaMouseButtonDblClick事件就可以啦,面對不同的需求要能夠舉一反三,這是程序員必備的技能。