Qt C++ 实现无边框窗口

发布于:2024-04-17 ⋅ 阅读:(19) ⋅ 点赞:(0)

Qt C++ 实现无边框窗口

// widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QDebug>
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QPushButton>
#include <QString>
#include <QWidget>

#define PADDING 6

enum Location {
    TOP,
    BOTTOM,
    LEFT,
    RIGHT,
    TOP_LEFT,
    TOP_RIGHT,
    BOTTOM_LEFT,
    BOTTOM_RIGHT,
    CENTER
};

class Widget : public QWidget {
    Q_OBJECT

public:
    Widget(QWidget* parent = nullptr);
    ~Widget();

protected:
    void mousePressEvent(QMouseEvent* event);
    void mouseMoveEvent(QMouseEvent* event);
    void mouseReleaseEvent(QMouseEvent* event);

private:
    void setCursorShape(const QPoint& point);

private:
    // 左键有没有按下
    bool isLeftPressed;
    // 鼠标按下的位置 偏移
    QPoint mouseOffset;
    Location location;
};
#endif  // WIDGET_H


// widget.cpp
#include "widget.h"

Widget::Widget(QWidget* parent) : QWidget(parent) {
    // 设置窗口的宽高
    this->setMinimumWidth(500);
    this->setMinimumHeight(300);

    // 设置背景色
    this->setStyleSheet("background: #303030");

    // 添加两个按钮 - 水平布局
    QHBoxLayout* layout = new QHBoxLayout(this);
    layout->setSpacing(10);
    layout->setContentsMargins(10, 10, 10, 10);

    QPushButton* btn1 = new QPushButton("确定");
    QPushButton* btn2 = new QPushButton("取消");

    layout->addWidget(btn1);
    layout->addWidget(btn2);

    QString style = R"(
        QPushButton {
            background-color: rgb(64, 64, 64);
            font: 16px "Microsoft YaHei";
            color: rgb(200, 200, 200);
            border-radius: 5px;
            padding: 5px;
        }
        QPushButton:hover {
            background-color: rgb(40, 40, 40);
        }
        QPushButton:pressed {
            background-color: rgb(64, 64, 64);
        }
    )";

    btn1->setStyleSheet(style);
    btn2->setStyleSheet(style);

    // 去除标题栏
    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);

    this->isLeftPressed = false;

    // 开启鼠标追踪
    this->setMouseTracking(true);
}

Widget::~Widget() {}

void Widget::mousePressEvent(QMouseEvent* event) {
    switch (event->button()) {
        case Qt::RightButton:
            this->close();
            break;
        case Qt::LeftButton:
            this->isLeftPressed = true;
            if (location == CENTER) {
                this->mouseOffset =
                    event->globalPos() - this->frameGeometry().topLeft();
            }
            break;
    }
}

void Widget::mouseMoveEvent(QMouseEvent* event) {
    QPoint globalPos = event->globalPos();

    QRect rect = this->rect();
    QPoint topLeft = mapToGlobal(rect.topLeft());
    QPoint bottomRight = mapToGlobal(rect.bottomRight());

    // 1. 鼠标未按下
    if (!this->isLeftPressed) {
        this->setCursorShape(globalPos);
        return;
    }

    // 2. 鼠标按下, 在CENTER位置按下
    if (this->location == CENTER) {
        move(globalPos - mouseOffset);
        event->accept();
        return;
    }

    // 3. 缩放
    QRect rMove(topLeft, bottomRight);
    switch (location) {
        case TOP:
            // 窗口达到最小高度后,会被鼠标 “向下推走”
            if (bottomRight.y() - globalPos.y() > this->minimumHeight())
                rMove.setY(globalPos.y());
            break;
        case BOTTOM:
            rMove.setHeight(globalPos.y() - topLeft.y());
            break;
        case LEFT:
            if (bottomRight.x() - globalPos.x() > this->minimumWidth())
                rMove.setX(globalPos.x());
            break;
        case RIGHT:
            rMove.setWidth(globalPos.x() - topLeft.x());
            break;
        case TOP_LEFT:
            if (bottomRight.y() - globalPos.y() > this->minimumHeight())
                rMove.setY(globalPos.y());
            if (bottomRight.x() - globalPos.x() > this->minimumWidth())
                rMove.setX(globalPos.x());
            break;
        case TOP_RIGHT:
            if (bottomRight.y() - globalPos.y() > this->minimumHeight())
                rMove.setY(globalPos.y());
            rMove.setWidth(globalPos.x() - topLeft.x());
            break;
        case BOTTOM_LEFT:
            rMove.setHeight(globalPos.y() - topLeft.y());
            if (bottomRight.x() - globalPos.x() > this->minimumWidth())
                rMove.setX(globalPos.x());
            break;
        case BOTTOM_RIGHT:
            rMove.setHeight(globalPos.y() - topLeft.y());
            rMove.setWidth(globalPos.x() - topLeft.x());
            break;
        default:
            break;
    }
    this->setGeometry(rMove);
}

void Widget::mouseReleaseEvent(QMouseEvent* event) {
    if (event->button() == Qt::LeftButton) {
        isLeftPressed = false;
    }
}

void Widget::setCursorShape(const QPoint& point) {
    QRect rect = this->rect();
    QPoint topLeft = mapToGlobal(rect.topLeft());
    QPoint bottomRight = mapToGlobal(rect.bottomRight());

    int x = point.x();
    int y = point.y();

    if (x >= topLeft.x() && x <= topLeft.x() + PADDING && y >= topLeft.y() &&
        y <= topLeft.y() + PADDING) {
        // 左上角
        location = TOP_LEFT;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    } else if (x <= bottomRight.x() && x >= bottomRight.x() - PADDING &&
               y <= bottomRight.y() && y >= bottomRight.y() - PADDING) {
        // 右下角
        location = BOTTOM_RIGHT;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    } else if (x >= topLeft.x() && x <= topLeft.x() + PADDING &&
               y <= bottomRight.y() && y >= bottomRight.y() - PADDING) {
        // 左下角
        location = BOTTOM_LEFT;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    } else if (x <= bottomRight.x() && x >= bottomRight.x() - PADDING &&
               y >= topLeft.y() && y <= topLeft.y() + PADDING) {
        // 右上角
        location = TOP_RIGHT;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    } else if (x >= topLeft.x() && x <= topLeft.x() + PADDING) {
        // 左边
        location = LEFT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    } else if (x >= bottomRight.x() - PADDING && x <= bottomRight.x()) {
        // 右边
        location = RIGHT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    } else if (y >= topLeft.y() && y <= topLeft.y() + PADDING) {
        // 上边
        location = TOP;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    } else if (y >= bottomRight.y() - PADDING && y <= bottomRight.y()) {
        // 下边
        location = BOTTOM;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    } else {
        location = CENTER;
        this->setCursor(QCursor(Qt::ArrowCursor));
    }
}