1. 程式人生 > 實用技巧 >Qt 基於Qt的詞典開發系列--無邊框視窗的縮放與拖動

Qt 基於Qt的詞典開發系列--無邊框視窗的縮放與拖動

在現在,絕大多數軟體都向著簡潔,時尚發展。就拿有道的單詞本和我做的單詞本來說,絕大多數使用者肯定喜歡我所做的單詞本(就單單介面,關於顏色搭配和佈局問題,大家就不要在意了)。

有道的單詞本:

我所做的單詞本:

很明顯,兩者的主要區別就是周圍的邊框問題。你可以對比QQ以前的版本和這幾年的版本,就會發現都傾向於下面這種視窗模式。下面我們就說說如何用Qt實現無邊框視窗的縮放與拖動。 對於無邊框視窗的拖動其實很簡單,其基本思想是,在滑鼠移動前後記錄滑鼠的座標,然後將視窗移動這兩個座標之差的距離即可,具體實現可以看程式碼,就非常清楚了。下面主要講講如何實現滑鼠改變視窗的大小,首先,我們將一個視窗分為以下9個區域,其中只有滑鼠在22區域時無法改變其形狀,不能改變視窗大小。當滑鼠在其它區域時,滑鼠改變形狀並可以改變視窗大小。視窗區域分類如下圖:

具體實現如下程式碼(widget.ui未做任何改變): 1、widget.h檔案
 1 #ifndef WIDGET_H
 2 #define WIDGET_H
 3  
 4 #include <QWidget>
 5 #define MARGIN 20//四個角的長度
 6 namespace Ui {
 7 class Widget;
 8 }
 9  
10 class Widget : public QWidget
11 {
12     Q_OBJECT
13     
14 public:
15     explicit Widget(QWidget *parent = 0
); 16 ~Widget(); 17 int countFlag(QPoint p, int row); 18 void setCursorType(int flag); 19 int countRow(QPoint p); 20 21 protected: 22 void mousePressEvent(QMouseEvent *event); 23 void mouseReleaseEvent(QMouseEvent *event); 24 void mouseDoubleClickEvent(QMouseEvent *event
); 25 void mouseMoveEvent(QMouseEvent *event); 26 private: 27 Ui::Widget *ui; 28 bool isLeftPressed; 29 int curPos; 30 QPoint pLast; 31 }; 32 33 #endif // WIDGET_H

2、widget.cpp檔案

  1 #include "widget.h"
  2 #include "ui_widget.h"
  3 #include<QMouseEvent>
  4 #include<QDebug>
  5  
  6 Widget::Widget(QWidget *parent) :
  7     QWidget(parent),
  8     ui(new Ui::Widget)
  9 {
 10     ui->setupUi(this);
 11     this->setMouseTracking(true);
 12     //設定在不按滑鼠的情況下也觸發滑鼠移動事件,注意QMainWindow的情況:centralWidget()->setMouseTracking(true);
 13     isLeftPressed=false;
 14     curPos=0;//標記滑鼠左擊時的位置
 15     this->setMinimumSize(400,300);//設定最小尺寸
 16     QCursor cursor;
 17     cursor.setShape(Qt::ArrowCursor);//設定滑鼠為箭頭形狀
 18    // ui->pushButton->setCursor(cursor);//當放在按鈕上時,為箭頭
 19    // cursor.setShape(Qt::OpenHandCursor);
 20     QWidget::setCursor(cursor);//當放在主視窗上時,為手形
 21     qDebug()<<"h="<<this->height();
 22     setWindowFlags(Qt::FramelessWindowHint);//設定主視窗無邊框
 23     qDebug()<<this->minimumHeight();
 24 }
 25  
 26 Widget::~Widget()
 27 {
 28     delete ui;
 29 }
 30 void Widget::mousePressEvent(QMouseEvent *event)//滑鼠按下事件
 31 {
 32     if(event->button()==Qt::LeftButton)
 33     {
 34         this->isLeftPressed=true;
 35         QPoint temp=event->globalPos();
 36         pLast=temp;
 37         curPos=countFlag(event->pos(),countRow(event->pos()));
 38         event->ignore();
 39     }
 40 }
 41  
 42 void Widget::mouseReleaseEvent(QMouseEvent *event)//滑鼠釋放事件
 43 {
 44     if(isLeftPressed)
 45         isLeftPressed=false;
 46     QApplication::restoreOverrideCursor();//恢復滑鼠指標性狀
 47     event->ignore();
 48 }
 49  
 50 void Widget::mouseDoubleClickEvent(QMouseEvent *event)//滑鼠雙擊 全屏
 51 {
 52     if(event->button()==Qt::LeftButton)
 53     {
 54         if(windowState()!=Qt::WindowFullScreen)
 55             setWindowState(Qt::WindowFullScreen);
 56         else setWindowState(Qt::WindowNoState);//恢復正常模式
 57     }
 58     event->ignore();
 59 }
 60  
 61 void Widget::mouseMoveEvent(QMouseEvent *event)//滑鼠移動事件
 62 {
 63  
 64     int poss=countFlag(event->pos(),countRow(event->pos()));
 65     setCursorType(poss);
 66     if(isLeftPressed)//是否左擊
 67     {
 68         QPoint ptemp=event->globalPos();
 69         ptemp=ptemp-pLast;
 70         if(curPos==22)//移動視窗
 71         {
 72             ptemp=ptemp+pos();
 73             move(ptemp);
 74         }
 75         else
 76         {
 77             QRect wid=geometry();
 78  
 79             switch(curPos)//改變視窗的大小
 80             {
 81  
 82             case 11:wid.setTopLeft(wid.topLeft()+ptemp);break;//左上角
 83             case 13:wid.setTopRight(wid.topRight()+ptemp);break;//右上角
 84             case 31:wid.setBottomLeft(wid.bottomLeft()+ptemp);break;//左下角
 85             case 33:wid.setBottomRight(wid.bottomRight()+ptemp);break;//右下角
 86             case 12:wid.setTop(wid.top()+ptemp.y());break;//中上角
 87             case 21:wid.setLeft(wid.left()+ptemp.x());break;//中左角
 88             case 23:wid.setRight(wid.right()+ptemp.x());break;//中右角
 89             case 32:wid.setBottom(wid.bottom()+ptemp.y());break;//中下角
 90             }
 91             setGeometry(wid);
 92         }
 93  
 94  
 95         pLast=event->globalPos();//更新位置
 96     }
 97     event->ignore();
 98 }
 99  
100  
101  
102 int Widget::countFlag(QPoint p,int row)//計算滑鼠在哪一列和哪一行
103 {
104     if(p.y()<MARGIN)
105         return 10+row;
106     else if(p.y()>this->height()-MARGIN)
107         return 30+row;
108     else
109         return 20+row;
110 }
111  
112 void Widget::setCursorType(int flag)//根據滑鼠所在位置改變滑鼠指標形狀
113 {
114     Qt::CursorShape cursor;
115     switch(flag)
116     {
117     case 11:
118     case 33:
119         cursor=Qt::SizeFDiagCursor;break;
120     case 13:
121     case 31:
122         cursor=Qt::SizeBDiagCursor;break;
123     case 21:
124     case 23:
125         cursor=Qt::SizeHorCursor;break;
126     case 12:
127     case 32:
128         cursor=Qt::SizeVerCursor;break;
129     case 22:
130         cursor=Qt::OpenHandCursor;break;
131     default:
132        //  QApplication::restoreOverrideCursor();//恢復滑鼠指標性狀
133          break;
134  
135     }
136     setCursor(cursor);
137 }
138  
139 int Widget::countRow(QPoint p)//計算在哪一列
140 {
141     return (p.x()<MARGIN)?1:(p.x()>(this->width()-MARGIN)?3:2);
142 }

3、main.cpp檔案

 1 #include<QtWidgets>
 2 #include "widget.h"
 3 int main(int argc, char *argv[])
 4 {
 5     QApplication a(argc, argv);
 6     Widget w;
 7     w.show();
 8     
 9     return a.exec();
10 }

程式執行截圖如下:

當你將滑鼠放在視窗的邊緣時,滑鼠會變化形狀,表示可以拖動視窗。由於沒有關閉視窗,只能在強制關閉視窗。如果想做到和不同視窗實現最小化和關閉視窗的畫,我們可以在視窗左上角放置兩個ToolButton,並設定autorise屬性,加上圖片即可。下面給出使用上面的無邊框視窗所做的詞典軟體的主介面: