本文出自:http://blog.csdn.net/kfbyj/article/details/9284923
最近做項目遇到的問題,總結下。
有時候我們覺得系統的標題列和按鈕太醜太呆板,想做自己的標題列以及最大化、最小化、關閉,功能表按鈕,我們就需要
[cpp]
view plaincopyprint?
- setWindowFlags(Qt::FramelessWindowHint);
setWindowFlags(Qt::FramelessWindowHint);
但是這樣過後,我們就不能拖動視窗改變位置,以及拖動邊緣改變視窗大小了。
有兩種方案處理這種情況:
1.自己對mouseMoveEvent,mousePressEvent,mouseReleaseEvent 等事件進行處理。
2.Qt可以處理windows的訊息。大家重新實現bool winEvent(MSG *message, long *result);(在此又一次感覺Qt的NB)
我剛開始使用第一種方法去實現的。移動視窗很容易做,大家可以去看看這個大大寫的,比網上其他版本問題少些。
http://blog.csdn.net/aqtata/article/details/8902889
在視窗邊緣按下滑鼠拖動改變視窗大小就比較麻煩了。
我是這樣做的:
在mousePressEvent 按下設定m_bPressed為真。
在mouseMoveEvent中m_bPressed為真且event->x() 在視窗邊緣 及處理算出滑鼠移動的增量 然後不斷resize視窗。
至於如何為邊緣的斷定,就自己設定一個 差值 假如 在視窗邊緣 ±4個px 就算在在該邊緣就處理該resize。
這樣做缺點很多,1.拖快了不行,很容易超過該差值 , 2.視窗抖動的厲害,一直在resize,3.要處理太多情況
鑒於上訴缺點於是乎就到處問人百度google。有了第二種方法:
第二種方法很好用,效果和有標題邊框程式一樣~~~
Qt居然可以處理windows訊息。。
這裡我們要重新實現winEvent ( MSG * message, long * result )
該虛函數在QWidget和QWizard以及QSizeGrip以及他們的子類中都可以實現。
如果你想停止Qt處理訊息就返回true,並且設定result到你想要儲存的值返回給window處理。否者的話返回false。
這裡我們主要想處理WM_NCHITTEST訊息。
The WM_NCHITTEST message is sent to a window in order to determine what part of the window corresponds to a particular screen coordinate. This can happen, for example, when the cursor moves, when a mouse button is pressed or released, or
in response to a call to a function such as
WindowFromPoint. If the mouse is not captured, the message is sent to the window beneath the cursor. Otherwise, the message is sent to the window that has captured the mouse.
A window receives this message through its
WindowProc function.
WM_NCHITTEST的訊息響應函數會根據滑鼠當前的座標來判斷滑鼠命中了視窗的哪個部位,訊息響應函數的傳回值指出了部位,例如它可能會返回HTCAPTION,或者HTCLIENT等。(其傳回值有很多,請查閱MSDN)。
知道這個就好了,我們還是要判斷下滑鼠的位置,然後通過該位置儲存到result給window處理。
其實就是我們的程式沒有邊框不能發送這些訊息,我們把它告訴windows,然後windows幫我們處理拖動,改變大小等效果。所以效果和有邊框有標題程式效果一樣的。
標頭檔申明:
[cpp]
view plaincopyprint?
- class MainWindow :
public QMainWindow
- {
- Q_OBJECT
- public:
- MainWindow(QWidget *parent = 0);
- ~MainWindow();
-
- protected:
- bool winEvent(MSG *message,
long *result);
- };
class MainWindow : public QMainWindow{ Q_OBJECTpublic: MainWindow(QWidget *parent = 0); ~MainWindow();protected: bool winEvent(MSG *message, long *result);};
CPP實現
[cpp]
view plaincopyprint?
- bool MainWindow::winEvent(MSG *message,
long *result)
- {
- switch(message->message)
- {
- case WM_NCHITTEST:
- int xPos = GET_X_LPARAM(message->lParam) -
this->frameGeometry().x();
- int yPos = GET_Y_LPARAM(message->lParam) -
this->frameGeometry().y();
- if(this->childAt(xPos,yPos) == 0)
- {
- *result = HTCAPTION;
- }else{
- return false;
- }
- if(xPos > 18 && xPos < 22)
- *result = HTLEFT;
- if(xPos > (this->width() - 22) && xPos < (this->width() - 18))
- *result = HTRIGHT;
- if(yPos > 18 && yPos < 22)
- *result = HTTOP;
- if(yPos > (this->height() - 22) && yPos < (this->height() - 18))
- *result = HTBOTTOM;
- if(xPos > 18 && xPos < 22 && yPos > 18 && yPos < 22)
- *result = HTTOPLEFT;
- if(xPos > (this->width() - 22) && xPos < (this->width() - 18) && yPos > 18 && yPos < 22)
- *result = HTTOPRIGHT;
- if(xPos > 18 && xPos < 22 && yPos > (this->height() - 22) && yPos < (this->height() - 18))
- *result = HTBOTTOMLEFT;
- if(xPos > (this->width() - 22) && xPos < (this->width() - 18) && yPos > (this->height()
- 22) && yPos < (this->height() - 18))
- *result = HTBOTTOMRIGHT;
-
- return true;
- }
- return false;
- }
bool MainWindow::winEvent(MSG *message, long *result){ switch(message->message) { case WM_NCHITTEST: int xPos = GET_X_LPARAM(message->lParam) - this->frameGeometry().x(); int yPos = GET_Y_LPARAM(message->lParam) - this->frameGeometry().y(); if(this->childAt(xPos,yPos) == 0) { *result = HTCAPTION; }else{ return false; } if(xPos > 18 && xPos < 22) *result = HTLEFT; if(xPos > (this->width() - 22) && xPos < (this->width() - 18)) *result = HTRIGHT; if(yPos > 18 && yPos < 22) *result = HTTOP; if(yPos > (this->height() - 22) && yPos < (this->height() - 18)) *result = HTBOTTOM; if(xPos > 18 && xPos < 22 && yPos > 18 && yPos < 22) *result = HTTOPLEFT; if(xPos > (this->width() - 22) && xPos < (this->width() - 18) && yPos > 18 && yPos < 22) *result = HTTOPRIGHT; if(xPos > 18 && xPos < 22 && yPos > (this->height() - 22) && yPos < (this->height() - 18)) *result = HTBOTTOMLEFT; if(xPos > (this->width() - 22) && xPos < (this->width() - 18) && yPos > (this->height() - 22) && yPos < (this->height() - 18)) *result = HTBOTTOMRIGHT; return true; } return false;}
把各種邊界情況儲存到result給windows處理,我們就省去很多事情,我想windows肯定比我們自己實現的效果要好多了。
以上的18 以及 22 是我對程式的邊緣進行判斷的範圍。
因為
我做了邊框陰影。陰影邊框設定為20px所以在
[cpp]
view plaincopyprint?
- xPos > 18 && xPos < 22 其實就是我們假定的邊框了。
xPos > 18 && xPos < 22 其實就是我們假定的邊框了。
[cpp]
view plaincopyprint?
-