form 窗体增加边框_C/C++编程笔记:无边框窗口橡皮筋拉伸效果

本文介绍了如何使用Qt实现无边框窗口的拖拽和拉伸功能,通过创建CFrameForm类,利用鼠标事件监听窗口边缘,动态计算窗口大小并显示橡皮筋效果。详细讲解了各个区域的处理和橡皮筋窗口的设计,提供了一种实用且易于集成的方法。
摘要由CSDN通过智能技术生成

有时候UI设计的风格,并不需要系统默认的标题栏;如QQ、微信电脑版等等。

这时候就需要我们实现对窗口的拖动和拉伸进行实现。

由于拖动比较简单,就此略过。

本文将以Qt做示例介绍我实现的拉伸功能,并封装成类。

当然思路是相同的,其他UI也可按此方法实现。

460a2080e0e06a6f82c38a52dc07a84b.png

使用方法

秉持实用至上主义,集成使用尽可能的方便,具体操作如下:
只需要在无边框的窗体添加 CFrameForm 对象,将它叠放在窗体上就行。
例如:

#ifndef FORM_H#define FORM_H#include #include "cframeform.h"  // 包含头文件namespace Ui {class Form;}class Form : public QWidget{    Q_OBJECTpublic:    explicit Form(QWidget *parent = 0);    ~Form();private:    Ui::Form *ui;    CFrameForm *m_frame;  // 创建对象};#endif // FORM_H

类实现如下:

#include "form.h"#include "ui_form.h"Form::Form(QWidget *parent) :    QWidget(parent),    ui(new Ui::Form){    ui->setupUi(this);    setWindowFlags(windowFlags() | Qt::FramelessWindowHint);    m_frame = new CFrameForm(this);      // 创建对象}Form::~Form(){    delete ui;}

设计思路

  • 如图所示,一般鼠标移动到窗口的四个角落(黑色区域)和四个边缘(红色区域)的时候,就可以进行拖拽了;我们只要对这个几个区域进行监听处理,在不同位置时,鼠标移动到上面就处于不同的状态,这样可以给用户更好的体验。
  • 当点击鼠标左键后开始,监听鼠标移动消息;
  • 然后只要根据窗口和鼠标的位置,进行动态计算,确定窗口不动的角、边与拉动的角、边,便可以计算出拉伸的区域大小。
  • 再然后对区域大小进行边框标记,就可以看到大小;在来回拉动的过程中实时刷新下,即可看到橡皮筋的效果了。
  • 等到鼠标是否,移到了其他区域如白色区域或者窗口以外的地方,鼠标恢复箭头状态。
00581923eb534a459180a53733d47d2e.png

拖拽区域

为每个区域创建一个窗口,实现对响应鼠标的点击和释放,以及类型的管理,知道每个窗口显示什么样的光标,以及区域位置;
我们创建一个简单的区域操作类:

class CHandel : public QWidget{    Q_OBJECTpublic:    CHandel(int type, CFrameForm*frm):QWidget(frm), m_type(type), m_frm(frm){}    int type() {return m_type;}private:    void mousePressEvent(QMouseEvent *e)     {        m_frm->setType(m_type);        QWidget::mousePressEvent(e);    }    void mouseReleaseEvent(QMouseEvent *e)    {        m_frm->setType(9);        QWidget::mouseReleaseEvent(e);        }private:    int m_type;    CFrameForm*m_frm;};

橡皮筋

为每个边框设计一个窗口,实现4条线组成的方框,实现橡皮筋的显示效果。(问:为啥不是用一个窗口,然后绘制四边?)
为了对4条线的管理,我们创建一个简单的区域类:

class CRubberBand{public:    explicit CRubberBand();    void setRect(const QRect &rect);    QRect rect();    bool isVisible();    void show();    void hide();    void clear();private:    QRect m_rect;    QListm_lines;};

类的实现部分:

/// class CRubberBandCRubberBand::CRubberBand()  // 构造4条线的属性和颜色{    for (int i = 0; i < 4; i++) {        QWidget *l = new QWidget;        l->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);        l->setStyleSheet("background:rgb(133,132,131)");        l->raise();        m_lines.append(l);    }}void CRubberBand::setRect(const QRect&r)  // 根据区域大小设置线的位置{    m_rect = r;    m_lines[0]->setGeometry(QRect(r.topLeft(), r.topRight()+QPoint(0,2)));    m_lines[1]->setGeometry(QRect(r.bottomLeft(), r.bottomRight()+QPoint(0,2)));    m_lines[2]->setGeometry(QRect(r.topLeft(), r.bottomLeft()+QPoint(2,0)));    m_lines[3]->setGeometry(QRect(r.topRight(), r.bottomRight()+QPoint(2,0)));    foreach (auto l, m_lines)        l->raise();}QRect CRubberBand::rect(){    return m_rect;}bool CRubberBand::isVisible() // 判断是否可见{    return m_lines[0]->isVisible();}void CRubberBand::show()  // 显示4条线{    foreach (auto l, m_lines)        l->show();}void CRubberBand::hide() // 隐藏4条线{    foreach (auto l, m_lines)        l->hide();}void CRubberBand::clear() // 删除四条线{    foreach (auto l, m_lines)        l->deleteLater();    m_lines.clear();}

功能代码实现

为了便于通用其他项目,我将功能代码封装成另一个类,派生于QWidget,处理鼠标事件、窗口大小改变事件及对区域与橡皮筋的操作。
代码实现如下:

class CFrameForm : public QWidget{    Q_OBJECTpublic:    enum Type { LeftTop=0, Top, RightTop, Right, RightBottom, Bottom, LeftBottom, Left, Other };    explicit CFrameForm(QWidget*parent=0);    ~CFrameForm();    void setType(int type) {m_type = (Type)type;}    void setCanResize(bool c);private slots:    void setHandel(QWidget *handel, CFrameForm::Type type);private:    void mousePressEvent(QMouseEvent *);    void mouseMoveEvent(QMouseEvent *);    void mouseReleaseEvent(QMouseEvent *);    void showEvent(QShowEvent *event);    void resizeEvent(QResizeEvent *e);private:    QPoint m_pos;    QRect m_normalRect;    QDesktopWidget m_desk;    QWidget* m_parent;    Type m_type;    CRubberBand m_rubber;            // 橡皮筋    QListm_handles;        // 8块区域};

类功能实现如下:

const int iresize = 8;  // 拖拽窗体尺寸像素CFrameForm::CFrameForm(QWidget*parent) :QWidget(parent), m_parent(parent){    m_rubber.hide();    m_type = Other;    setWindowFlags(windowFlags() | Qt::FramelessWindowHint);   // 设置成无边框    for (int i = Left; i >= LeftTop; i--)  // 创建8个区域    {        CHandel *w = new CHandel(i, this);        m_handles.push_front(w);    }}CFrameForm::~CFrameForm(){    m_rubber.clear();}void CFrameForm::setCanResize(bool c)  // 设置是否可以进行拖拽拉伸{    for (int i = 0; i < m_handles.size(); i++){        setHandel(m_handles[i], !c ? Other : (Type)m_handles[i]->type());        m_handles[i]->raise();    }}// 根据所属类型,移动到对应区域和设置对应光标void CFrameForm::setHandel(QWidget*handel, CFrameForm::Type type){    switch (type)    {    case LeftTop:        handel->setGeometry(QRect(0,0,10,10));        handel->setCursor(Qt::SizeFDiagCursor);        break;    case Top:        handel->setGeometry(QRect(10,0,width()-20,iresize));        handel->setCursor(Qt::SizeVerCursor);        break;    case RightTop:        handel->setGeometry(QRect(width()-10,0,10,10));        handel->setCursor(Qt::SizeBDiagCursor);        break;    case Right:        handel->setGeometry(QRect(width()-iresize,10,iresize,height()-20));        handel->setCursor(Qt::SizeHorCursor);        break;    case RightBottom:        handel->setGeometry(QRect(width()-10,height()-10,10,10));        handel->setCursor(Qt::SizeFDiagCursor);        break;    case Bottom:        handel->setGeometry(QRect(10,height()-iresize,width()-20,iresize));        handel->setCursor(Qt::SizeVerCursor);        break;    case LeftBottom:        handel->setGeometry(QRect(0,height()-10,10,10));        handel->setCursor(Qt::SizeBDiagCursor);        break;    case Left:        handel->setGeometry(QRect(0,10,iresize,height()-20));        handel->setCursor(Qt::SizeHorCursor);        break;    case Other:        handel->setCursor(Qt::ArrowCursor);        break;    }}void CFrameForm::mousePressEvent(QMouseEvent *e)  // 判断鼠标按键与类型正确与否{    if ((e->button() == Qt::LeftButton) && (m_type != Other))          m_pos = e->pos();    else        QWidget::mousePressEvent(e);}void CFrameForm::mouseMoveEvent(QMouseEvent *e) // 动态计算大小拉伸区域大小,并设置显示橡皮筋{    if (!m_pos.isNull())    {        QWidget *p = m_parent;        if (p && m_type < Other){            QRect r;            int w = p->minimumSizeHint().width();            int h = p->minimumSizeHint().height();            if (m_type == Right) {                r = QRect(p->pos(), QSize(e->pos().x(), height()));                if (r.width() < w)                    r.setWidth(w);            }            else if (m_type == Left) {                int x = QCursor::pos().x();                r = QRect(x, p->pos().y(), p->pos().x() + width() - x, height());                int dx = r.x() + r.width();                if (r.width() < w)                    r.setX(dx-w);            }            else if (m_type == Bottom) {                r = QRect(p->pos(), QSize(width(), e->pos().y()));                if (r.height() < h)                    r.setHeight(h);            }            else if (m_type == Top) {                r = QRect(p->pos().x(), QCursor::pos().y(), width(), p->pos().y() + height() - QCursor::pos().y());                int dy = r.y() + r.height();                if (r.height() < h)                    r.setY(dy-h);            }            else if (m_type == RightTop) {                r = QRect(p->pos().x(), QCursor::pos().y(), e->pos().x(), p->pos().y() + height() - QCursor::pos().y());                if (r.width() < w)                    r.setWidth(w);                int dy = r.y() + r.height();                if (r.height() < h)                    r.setY(dy-h);            }            else if (m_type == LeftTop) {                r = QRect(QCursor::pos(), QSize(p->pos().x() + width() - QCursor::pos().x(), p->pos().y() + height() - QCursor::pos().y()));                int dx = r.x() + r.width();                if (r.width() < w)                    r.setX(dx-w);                int dy = r.y() + r.height();                if (r.height() < h)                    r.setY(dy-h);            }            else if (m_type == RightBottom) {                r = QRect(p->pos(), QCursor::pos());//QSize(e->pos().x(), e->pos().y())));                if (r.width() < w)                    r.setWidth(w);                if (r.height() < h)                    r.setHeight(h);            }            else if (m_type == LeftBottom) {                r = QRect(QCursor::pos().x(), p->pos().y(), p->pos().x() + width() - QCursor::pos().x(), e->pos().y());                int dx = r.x() + r.width();                if (r.width() < w)                    r.setX(dx-w);                if (r.height() < h)                    r.setHeight(h);            }            else return;            m_rubber.show();            m_rubber.setRect(r);        }    }    else        QWidget::mouseMoveEvent(e);}void CFrameForm::mouseReleaseEvent(QMouseEvent *e) // 鼠标释放后隐藏橡皮筋并设置界面大小{    if (m_rubber.isVisible()) {        m_rubber.hide();        if (m_parent) m_parent->setGeometry(m_rubber.rect());        resize(m_rubber.rect().size());    }    else        QWidget::mousePressEvent(e);    m_type = Other;    m_pos = QPoint();}void CFrameForm::showEvent(QShowEvent *event) { if (m_parent) resize(m_parent->size()); }void CFrameForm::resizeEvent(QResizeEvent *e) // 窗体大小变更后,更新8个区域位置{    QWidget::resizeEvent(e);    for (int i = 0; i < m_handles.size(); i++) {        setHandel(m_handles[i], (Type)m_handles[i]->type());        m_handles[i]->raise();    }}

总结

我的砖就抛到这里,希望对你们有用。

接下来的路就请各位小伙伴们自己走了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值