# 【Qt編程】基于Qt的詞典開發系列--無邊框窗口的縮放與拖動
在現在,絕大多數軟件都向著簡潔,時尚發展。就拿有道的單詞本和我做的單詞本來說,絕大多數用戶肯定喜歡我所做的單詞本(就單單界面,關于顏色搭配和布局問題,大家就不要在意了)。
有道的單詞本:

我所做的單詞本:

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

**具體實現如下代碼(widget.ui未做任何改變):**
**1、widget.h文件**
~~~
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#define MARGIN 20//四個角的長度
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
int countFlag(QPoint p, int row);
void setCursorType(int flag);
int countRow(QPoint p);
protected:
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private:
Ui::Widget *ui;
bool isLeftPressed;
int curPos;
QPoint pLast;
};
#endif // WIDGET_H
~~~
**2、widget.cpp文件**
~~~
#include "widget.h"
#include "ui_widget.h"
#include<QMouseEvent>
#include<QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
this->setMouseTracking(true);
//設置在不按鼠標的情況下也觸發鼠標移動事件,注意QMainWindow的情況:centralWidget()->setMouseTracking(true);
isLeftPressed=false;
curPos=0;//標記鼠標左擊時的位置
this->setMinimumSize(400,300);//設置最小尺寸
QCursor cursor;
cursor.setShape(Qt::ArrowCursor);//設置鼠標為箭頭形狀
// ui->pushButton->setCursor(cursor);//當放在按鈕上時,為箭頭
// cursor.setShape(Qt::OpenHandCursor);
QWidget::setCursor(cursor);//當放在主窗口上時,為手形
qDebug()<<"h="<<this->height();
setWindowFlags(Qt::FramelessWindowHint);//設置主窗口無邊框
qDebug()<<this->minimumHeight();
}
Widget::~Widget()
{
delete ui;
}
void Widget::mousePressEvent(QMouseEvent *event)//鼠標按下事件
{
if(event->button()==Qt::LeftButton)
{
this->isLeftPressed=true;
QPoint temp=event->globalPos();
pLast=temp;
curPos=countFlag(event->pos(),countRow(event->pos()));
event->ignore();
}
}
void Widget::mouseReleaseEvent(QMouseEvent *event)//鼠標釋放事件
{
if(isLeftPressed)
isLeftPressed=false;
QApplication::restoreOverrideCursor();//恢復鼠標指針性狀
event->ignore();
}
void Widget::mouseDoubleClickEvent(QMouseEvent *event)//鼠標雙擊 全屏
{
if(event->button()==Qt::LeftButton)
{
if(windowState()!=Qt::WindowFullScreen)
setWindowState(Qt::WindowFullScreen);
else setWindowState(Qt::WindowNoState);//恢復正常模式
}
event->ignore();
}
void Widget::mouseMoveEvent(QMouseEvent *event)//鼠標移動事件
{
int poss=countFlag(event->pos(),countRow(event->pos()));
setCursorType(poss);
if(isLeftPressed)//是否左擊
{
QPoint ptemp=event->globalPos();
ptemp=ptemp-pLast;
if(curPos==22)//移動窗口
{
ptemp=ptemp+pos();
move(ptemp);
}
else
{
QRect wid=geometry();
switch(curPos)//改變窗口的大小
{
case 11:wid.setTopLeft(wid.topLeft()+ptemp);break;//左上角
case 13:wid.setTopRight(wid.topRight()+ptemp);break;//右上角
case 31:wid.setBottomLeft(wid.bottomLeft()+ptemp);break;//左下角
case 33:wid.setBottomRight(wid.bottomRight()+ptemp);break;//右下角
case 12:wid.setTop(wid.top()+ptemp.y());break;//中上角
case 21:wid.setLeft(wid.left()+ptemp.x());break;//中左角
case 23:wid.setRight(wid.right()+ptemp.x());break;//中右角
case 32:wid.setBottom(wid.bottom()+ptemp.y());break;//中下角
}
setGeometry(wid);
}
pLast=event->globalPos();//更新位置
}
event->ignore();
}
int Widget::countFlag(QPoint p,int row)//計算鼠標在哪一列和哪一行
{
if(p.y()<MARGIN)
return 10+row;
else if(p.y()>this->height()-MARGIN)
return 30+row;
else
return 20+row;
}
void Widget::setCursorType(int flag)//根據鼠標所在位置改變鼠標指針形狀
{
Qt::CursorShape cursor;
switch(flag)
{
case 11:
case 33:
cursor=Qt::SizeFDiagCursor;break;
case 13:
case 31:
cursor=Qt::SizeBDiagCursor;break;
case 21:
case 23:
cursor=Qt::SizeHorCursor;break;
case 12:
case 32:
cursor=Qt::SizeVerCursor;break;
case 22:
cursor=Qt::OpenHandCursor;break;
default:
// QApplication::restoreOverrideCursor();//恢復鼠標指針性狀
break;
}
setCursor(cursor);
}
int Widget::countRow(QPoint p)//計算在哪一列
{
return (p.x()<MARGIN)?1:(p.x()>(this->width()-MARGIN)?3:2);
}
~~~
**3、main.cpp文件**
~~~
#include<QtWidgets>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
~~~
**程序運行截圖如下:**

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

- 前言
- <一>--詞典框架設計及成品展示
- <二>--本地詞典的設計
- <三>--開始菜單的設計
- <四>--無邊框窗口的縮放與拖動
- <五>--無邊框窗口的拖動
- <六>--界面美化設計
- <七>--調用網絡API
- <八>--用戶登錄及API調用的實現
- <九>--JSON數據解析
- <十>--國際音標的顯示
- <十一>系統托盤的顯示
- <十二>調用講述人
- <十三>音頻播放
- <十四>自動補全功能
- <十五>html特殊字符及正則表達式
- 后序