牛骨文教育服务平台(让学习变的简单)

【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属性,加上图片即可。下面给出使用上面的无边框窗口所做的词典软件的主界面: