当前位置:   article > 正文

通俗易懂玩QT:自定义窗口移动与拉伸的实现(内附主要源代码)_qt中使窗体区域左右拉伸,使界面宽度发生变化

qt中使窗体区域左右拉伸,使界面宽度发生变化

QT自定义窗口移动与拉伸的实现(内附主要源代码)

国庆没啥事,研究了一下 Qt 实现自定义窗口,参考了两位博主的文章,自己做了点修改,修复了一些 Bug(有可能是我没按大佬的思路来产生的),目前还存在的 Bug 是最大化窗口被移动了以后,需要点击两次窗口还原按钮才能还原窗口,不想再耗费时间再纠结这个问题了,后面有需要的话再来改就完事,下面是主要源码:

zoomMove.h

enum {
    EDGENULL = 0,
    TOPLEFT,
    TOPRIGHT,
    BOTTOMRIGHT,
    BOTTOMLEFT,
    TOP,
    RIGHT,
    BOTTOM,
    LEFT
};

class ZoomMove : public QWidget {
    Q_OBJECT

public:
    explicit ZoomMove(QWidget *parent = nullptr);
    ~ZoomMove();

private:
    bool key_down,      //0:松开, 1:按下
         zoom,          //0:无操作, 1:拉扯
         move;          //0:无操作, 1:移动

    int is_on_edge,     //0:不沾边, 1:上边, 2:右上方 , 3:右边 , 4:右下方 , 5:下边 , 6:左下方 , 7:左边 , 8:左上方
        left,
        top,
        right,
        bottom,
        min_width,
        min_height;

    QPoint last_point,      //当前窗口的左上方顶点
           current_point,   //当前鼠标相对于屏幕的位置,不能将 current_point 与 point 看作同一坐标点,后者没有前者稳定
           point,           //当前鼠标在屏幕中的位置
           temp_point;      //用于存放窗口的四个顶点

    QWidget *widget;

    void updateCursor();                            //更新鼠标图标
    void mouseIsOnEdge(QPoint point, QRect rect);   //判断鼠标是否在边停靠
    void resizeWidget(QPoint p);                    //根据拉伸重置窗口大小
    void widgetEventHandler(QEvent *e);             //窗口事件处理
    void mouseHoverEventHandler(QHoverEvent *e);    //鼠标停靠窗口
    void mouseMoveEventHandler(QMouseEvent *e);     //鼠标移动
    void mousePressEventHandler(QMouseEvent *e);    //鼠标被按下
    void mouseReleaseEventHandler(QMouseEvent *e);  //鼠标被松开

protected:
    virtual bool eventFilter(QObject *obj, QEvent *e);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

zoomMove.cpp

ZoomMove::ZoomMove(QWidget *parent):
    QWidget(parent) {
    key_down =      //默认鼠标为松开状态
    zoom =          //默认无拉扯操作
    move = 0;       //默认无移动操作
    is_on_edge = 0; //默认鼠标没有在边停靠

    parent -> installEventFilter(this); //开启事件过滤
}

ZoomMove::~ZoomMove() {
    widget -> removeEventFilter(this);  //关闭事件过滤
}

void ZoomMove::updateCursor() {
    switch(is_on_edge) {
    case TOPLEFT:     //左上方
    case BOTTOMRIGHT:     //右下方
        widget -> setCursor(Qt::SizeFDiagCursor);   //左上-右下
        break;
    case TOPRIGHT:     //右上方
    case BOTTOMLEFT:     //左下方
        widget -> setCursor(Qt::SizeBDiagCursor);   //右上-左下
        break;
    case TOP:     //上边
    case BOTTOM:     //下边
        widget -> setCursor(Qt::SizeVerCursor);     //上-下
        break;
    case RIGHT:     //右边
    case LEFT:     //左边
        widget -> setCursor(Qt::SizeHorCursor);     //左-右
        break;
    case EDGENULL:
    default:
        widget -> setCursor(Qt::ArrowCursor);       //箭头
        break;
    }
}

void ZoomMove::mouseIsOnEdge(QPoint point, QRect rect) {
    if((point.x() - rect.x() < 5) && (point.y() - rect.y() < 5)) {
        is_on_edge = TOPLEFT; //左上方
    }
    else if((rect.x() + rect.width() - point.x() < 5) && (point.y() - rect.y() < 5)) {
        is_on_edge = TOPRIGHT; //右上方
    }
    else if((rect.x() + rect.width() - point.x() < 5) && (rect.y() + rect.height() - point.y() < 5)) {
        is_on_edge = BOTTOMRIGHT; //右下方
    }
    else if((point.x() - rect.x() < 5) && (rect.y() + rect.height() - point.y() < 5)) {
        is_on_edge = BOTTOMLEFT; //左下方
    }
    else if(point.y() - rect.y() < 5) {
        is_on_edge = TOP; //上边
    }
    else if(rect.x() + rect.width() - point.x() < 5) {
        is_on_edge = RIGHT; //右边
    }
    else if(rect.y() + rect.height() - point.y() < 5) {
        is_on_edge = BOTTOM; //下边
    }
    else if(point.x() - rect.x() < 5) {
        is_on_edge = LEFT; //左边
    }
    else {
        is_on_edge = EDGENULL; //不沾边
    }

    zoom = is_on_edge == EDGENULL ? 0 : 1;
}

void ZoomMove::resizeWidget(QPoint p) {
    min_width = widget -> minimumWidth();
    min_height = widget -> minimumHeight();

    QRect frame = widget -> frameGeometry(); //获取窗口的几何框架

    switch(is_on_edge) {    //根据边框的位置改变窗口的形状
        case TOPLEFT:     //左上方
            temp_point = frame.topLeft();
            if(frame.bottomRight().x() - p.x() > min_width) { temp_point.setX(p.x()); }
            if(frame.bottomRight().y() - p.y() > min_height) { temp_point.setY(p.y()); }
            if(frame.bottomRight().x() - p.x() <= min_width && frame.bottomRight().y() - p.y() <= min_height) {
                temp_point.setX(frame.bottomRight().x() - min_width);
                temp_point.setY(frame.bottomRight().y() - min_height);
            }
            frame.setTopLeft(temp_point);
            break;

        case TOPRIGHT:     //右上方
            temp_point = frame.topRight();
            if(p.x() - frame.bottomLeft().x() > 0) { temp_point.setX(p.x()); }
            if(frame.bottomLeft().y() - p.y() > min_height) { temp_point.setY(p.y()); }
            if(p.x() - frame.bottomLeft().x() <= 0 && frame.bottomLeft().y() - p.y() <= min_height) {
                temp_point.setX(p.x());
                temp_point.setY(frame.bottomLeft().y() - min_height);
            }
            frame.setTopRight(temp_point);
            break;

        case BOTTOMRIGHT:   //右下方
            temp_point = frame.bottomRight();
            if(p.x() - frame.topLeft().x() > 0) { temp_point.setX(p.x()); }
            if(p.y() - frame.topLeft().y() > 0) { temp_point.setY(p.y()); }
            if(p.x() - frame.topLeft().x() <= 0 && p.y() - frame.topLeft().y() <= 0) {
                temp_point.setX(p.x());
                temp_point.setY(p.y());
            }
            frame.setBottomRight(temp_point);
            break;

        case BOTTOMLEFT:    //左下方
            temp_point = frame.bottomLeft();
            if(frame.topRight().x() - p.x() > min_width) { temp_point.setX(p.x()); }
            if(p.y() - frame.topRight().y() > 0) { temp_point.setY(p.y()); }
            if(frame.topRight().x() - p.x() <= min_width && p.y() - frame.topRight().y() <= 0) {
                temp_point.setX(frame.topRight().x() - min_width);
                temp_point.setY(p.y());
            }
            frame.setBottomLeft(temp_point);
            break;

        case TOP:           //上边
            temp_point = frame.topRight();
            if(frame.bottomLeft().y() - p.y() > min_height) { temp_point.setY(p.y()); }
            frame.setTopRight(temp_point);
            break;

        case RIGHT:         //右边
            temp_point = frame.bottomRight();
            if(p.x() - frame.topLeft().x() > 0) { temp_point.setX(p.x()); }
            frame.setBottomRight(temp_point);
            break;

        case BOTTOM:        //下边
            temp_point = frame.bottomLeft();
            if(p.y() - frame.topRight().y() > 0) { temp_point.setY(p.y()); }
            frame.setBottomLeft(temp_point);
            break;

        case LEFT:          //左边
            temp_point = frame.topLeft();
            if(frame.bottomRight().x() - p.x() > min_width) { temp_point.setX(p.x()); }
            frame.setTopLeft(temp_point);
            break;

        default:
            break;
    }

    widget -> setGeometry(frame);    //给窗口设置新的几何框架
}

void ZoomMove::widgetEventHandler(QEvent *e) {
    switch(e -> type()) {
    case QEvent::HoverMove:
        mouseHoverEventHandler(static_cast<QHoverEvent *>(e));
        break;
    case QEvent::MouseMove:
        mouseMoveEventHandler(static_cast<QMouseEvent *>(e));
        break;
    case QEvent::MouseButtonPress:
        mousePressEventHandler(static_cast<QMouseEvent *>(e));
        break;
    case QEvent::MouseButtonRelease:
        mouseReleaseEventHandler(static_cast<QMouseEvent *>(e));
        break;
    default:
        break;
    }
}

void ZoomMove::mouseHoverEventHandler(QHoverEvent *e) {
    if(!key_down){      //在窗口被拉扯或移动的过程中,停止对鼠标的悬浮监听
        point = widget -> mapToGlobal(e -> pos());

        mouseIsOnEdge(point, widget -> frameGeometry());
        updateCursor();
    }
}

void ZoomMove::mouseMoveEventHandler(QMouseEvent *e) {
    Q_UNUSED(e);

    if(key_down) {
        current_point = e -> globalPos();

        //current_point - last_point 即窗口的左上角顶点
        if(move && last_point.y() < 65) {
            widget -> move(current_point - last_point);
        }

        if(zoom) {
            resizeWidget(current_point);
        }
    }
}

void ZoomMove::mousePressEventHandler(QMouseEvent *e) {
    if(e -> button() == Qt::LeftButton) {
        key_down = 1;
        move = (!zoom && !move) & 1;
        last_point = e -> pos();
    }
}

void ZoomMove::mouseReleaseEventHandler(QMouseEvent *e) {
    if(e -> button() == Qt::LeftButton) {
        key_down =      //按键松开
        move = 0;       //更正移动状态
    }
}

bool ZoomMove::eventFilter(QObject *obj, QEvent *e) {
    switch(e -> type()) {
    case QEvent::MouseMove:
    case QEvent::MouseButtonPress:
    case QEvent::MouseButtonRelease:
    case QEvent::HoverMove:
        widget = static_cast<QWidget *>(obj);
        widgetEventHandler(e);
        return true;
    default:
        return QObject::eventFilter(obj, e);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226

在 QMainWindow 或 QWidget 中初始化该类即可实现自定义窗口的拉伸与移动功能。

new ZoomMove(this);
  • 1

参考博文:
前行中的小猪:Qt 之 自定义窗口标题栏 之窗口拉伸
一去丶二三里:Qt 之自定义界面(窗体缩放-跨平台终极版)

学习分享,一起成长!以上为小编的经验分享,若存在不当之处,请批评指正!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/94907
推荐阅读
相关标签
  

闽ICP备14008679号