<四>–无边框窗口的缩放与拖动

最后更新于:2022-04-01 07:11:16

# 【Qt编程】基于Qt的词典开发系列--无边框窗口的缩放与拖动 在现在,绝大多数软件都向着简洁,时尚发展。就拿有道的单词本和我做的单词本来说,绝大多数用户肯定喜欢我所做的单词本(就单单界面,关于颜色搭配和布局问题,大家就不要在意了)。 有道的单词本: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-15_5698c1c5e6c6a.jpg) 我所做的单词本: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-15_5698c1c616a18.jpg) 很明显,两者的主要区别就是周围的边框问题。你可以对比QQ以前的版本和这几年的版本,就会发现都倾向于下面这种窗口模式。下面我们就说说如何用Qt实现无边框窗口的缩放与拖动。 对于无边框窗口的拖动其实很简单,其基本思想是,在鼠标移动前后记录鼠标的坐标,然后将窗口移动这两个坐标之差的距离即可,具体实现可以看代码,就非常清楚了。下面主要讲讲如何实现鼠标改变窗口的大小,首先,我们将一个窗口分为以下9个区域,其中只有鼠标在22区域时无法改变其形状,不能改变窗口大小。当鼠标在其它区域时,鼠标改变形状并可以改变窗口大小。窗口区域分类如下图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-15_5698c1c62e774.jpg) **具体实现如下代码(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(); } ~~~ **程序运行截图如下:** ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-15_5698c1c63e21e.jpg)         当你将鼠标放在窗口的边缘时,鼠标会变化形状,表示可以拖动窗口。由于没有关闭窗口,只能在强制关闭窗口。如果想做到和不同窗口实现最小化和关闭窗口的画,我们可以在窗口左上角放置两个ToolButton,并设置autorise属性,加上图片即可。下面给出使用上面的无边框窗口所做的词典软件的主界面: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-15_5698c1c2daaed.jpg)
';