之前在做有關QDockWidget的內容時候遇到了瓶頸,那就是窗口彈出來之后拖動不了,也不可以放大和縮小,若是彈出來之后設置成了window的flags,也不可以拖動,而且也不是需要的效果。
1.彈出來之后的dockwidget的titlebar右邊需要有3個按鈕分別來控制放大與恢復、彈出來與收進去和關閉按鈕。考慮到Qt自帶的dockwidget彈出來后實現不了這個,所以參考了網上的方法,需要自己從QWidget中派生一個類來實現自己的titlebar
2.因為dockwidget是嵌套在QTabWidget中的,而tabwidget本身是不可以拖動的,所以此dockwiget也不可以拖動(Qt中子窗口的拖動是和父窗口有關聯的),加上需要實現自己的dockwidget樣式,所以也從QDockWidget中派生一個類
首先實現自己的titlebar:
1 class myDockWidgetTitleBar:public QWidget 2 { 3 Q_OBJECT 4 5 private: 6 //自己需要的類成員定義 7 QSize sizeHint() const { return minimumSizeHint(); } 8 QSize mimimumSizeHint() const;//在寫自己的titlebar時,這2個函數必須要實現 9 10 protected: 11 void paintEvent(QPaintEvent *event); 12 void mouseDoubleClickEvent(QMouseEvent *event); 13 void mouseReleaseEvent(QMouseEvent *event); 14 15 private slots: 16 //自己定義的一些槽函數,比如我這里需要實現放大縮小、浮動和關閉 17 void MaxMinDockWidget(); 18 void FloatDockWidget(); 19 void CloseDockWidget(); 20 21 public: 22 myDockWidgetTitleBar(QWidget *parent = 0); 23 ~myDockWigetTitleBar(); 24 };
這里需要注意的是:若dockwidget沒有titlebar則直接setTitleBarWidget(QWidget());這樣可以只有一個dockwidget的窗口而沒有窗口上面的titlebar。(方法來源於網上,源地址找尋不到了,若是找到再加上原有鏈接)
下面寫一下在實現titlebar時必須要實現的函數的實現:
1 QSize *myDockWidgetTitleBar::minimumSizeHint() const 2 { 3 myDockWidget*dock_widget = qobject_cast<myDockWidget *>(parentWidget()); 4 Q_ASSERT(dock_widget != 0); 5 QSize result(50, 30); 6 if(dock_widget->features & QDockWidget::DockWidgetVerticalTitleBar) 7 { 8 result.transpose(); 9 } 10 return result; 11 }
paintEvent主要用來在titlebar上繪制圖標和位置。不過我這里因為這些按鈕其他地方也要用到,所以我將按鈕都定義成了類成員,同時在構造函數中給出了按鈕的類型。其他的slots函數可以根據需求定義就行。
實現自己的dockwidget:
1 class myDockWidget:public QDockWidget 2 { 3 Q_OBJECT 4 5 private: 6 //一些類成員變量 7 int _cur_point_pos; 8 int _margin_length; 9 QWidget *_default_title_bar; 10 myDockWidgetTitleBar *_dock_widget_title_bar; 11 12 protected: 13 void mouseMoveEvent(QMouseEvent *event);//因為要實現拖動,所以這個鼠標移動事件必須要實現 14 void mousePressEvent(QMouseEvent *event);//拖動的時候鼠標左鍵應該是一直按壓着的,所以需要在這個里面進行判斷 15 void mouseReleaseEvent(QMouseEvent *event); 16 void closeEvent(QCloseEvent *event); 17 18 public: 19 myDockWidget(QTabWidget *tab_widget, QWidget *parent = 0); 20 ~myDockWidget(); 21 };
需要注意的是這里的類定義中都用到了Q_OBJECT,若是在類中有信號和槽函數的定義,則必須要寫此,具體的原因請參考Qt幫助手冊。
“信號和槽函數的聲明一般位於頭文件中,同時在類聲明的開始位置必須加上Q_OBJECT語句,這條語句是不可缺少的,它將告訴編譯器在編譯之前必須先應用 moc工具進行擴展。”--信號(Signal)與槽(Slot)-Qt中的典型機制
上面的類中還需要定義一個用來判斷鼠標左鍵是否一直按壓着的bool變量和鼠標之前點擊的位置信息:
1 private: 2 bool _left_mose_press; 3 Qpoint _last_point_pos, _length_pos;
鼠標按壓事件中:
1 void myDockWidget::mousePressEvent(QMouseEvent *event) 2 { 3 if(event->button == Qt::LeftButton) 4 { 5 _left_mouse_press = ture; 6 _last_point_pos = event->globalPos(); 7 _cur_point_pos = CountFlag(event->pos(), CountColumn(event->pos())); 8 event->ignore(); 9 } 10 }
鼠標釋放事件中:
1 void myDockWidget::mouseReleaseEvent(QMouseEvent *event) 2 { 3 if(_left_mouse_press) 4 { 5 _left_mouse_press = false; 6 } 7 QApplication::restoreOverrideCursor(); 8 event->ignore(); 9 }
重點是這里的鼠標移動事件,這里處理的方法參考了【Qt編程】基於Qt的詞典開發系列<四>--無邊框窗口的縮放與拖動,並且這里里面有很詳細的描述:有拖動窗口也有當鼠標放到四周顯示不同形狀進行放大縮小。這里將一個窗口划分成3*3的板塊的方法還是不錯的。
但是這里有一點不好的就是,每次拖動的時候都會重繪,若是窗口里面的內容比較復雜,當鼠標移動過快的時候便會出現窗口在某一個位置停下來了。這里還需要進一步的改進。
(移動窗口本身也有很多方法,但是考慮到要支持不同的平台,可能不能夠只用到windows下的函數,所以選擇了上面的方法,若只有windows平台,可以考慮下面的方法:
1. Qt窗口拖動及改變大小
3. 【Qt】移動無邊框窗體
這些都是我當時查找到的一些方法,其實網上的方法大多也都是類似的,當然如果能夠一個一個的看demo中的例子,就會發現其實Qt的源代碼中也有類似的操作,網上的方法和Qt例子中的都大同小異)
當然Qt中也有獲取當前屏幕大小的函數,這個可用來處理放大和縮小的時候看要到什么大小:
1 QRect desktop_rect = QApplication::desktop()->availableGeometry();
