一杯清酒邀明月
天下本无事,庸人扰之而烦耳。

 在现在,绝大多数软件都向着简洁,时尚发展。就拿有道的单词本和我做的单词本来说,绝大多数用户肯定喜欢我所做的单词本(就单单界面,关于颜色搭配和布局问题,大家就不要在意了)。

有道的单词本:

我所做的单词本:

 很明显,两者的主要区别就是周围的边框问题。你可以对比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属性,加上图片即可。下面给出使用上面的无边框窗口所做的词典软件的主界面:

posted on 2020-08-14 13:22  一杯清酒邀明月  阅读(491)  评论(0编辑  收藏  举报