• QT 实现无边框可伸缩变换有阴影的QDialog弹窗


    在这里插入图片描述

    • 实现无标题栏窗口的拖拽移动、调节窗口大小以及边框阴影效果。
    • 初始化时进行位或操作,将这些标志合并为一个值,并将其设置为窗口的标志。这些标志分别表示这是一个对话框、无边框窗口、有标题栏、有最小化按钮和最大化按钮。
        setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint);
        setAttribute(Qt::WA_TranslucentBackground);
    
    • 1
    • 2
    • 重写绘制paintEvent函数
    void FramelessWindow::paintEvent(QPaintEvent *event)
    {
        QDialog::paintEvent(event);
        if (!_shadeEnabled)
        {
            return;
        }
    
        // 先将窗口背景刷新为白色
        QPainterPath path;
        path.setFillRule(Qt::WindingFill);
        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing, true);
    
        if (this->isMaximized() || this->isFullScreen()) // 最大化或全屏下刷新整个窗口为白色,且让子窗口填充满
        {
            QLayout *layout = this->layout();
            if (layout != NULL)
                layout->setContentsMargins(0, 0, 0, 0);
    
            path.addRect(this->rect());
            painter.fillPath(path, QBrush(Qt::white));
            return;
        }
        else // 正常大小显示,让主窗口布局四周空出阴影所需宽度。
        {
            QLayout *layout = this->layout();
            if (layout != NULL)
                layout->setContentsMargins(BoardShadeWidth, BoardShadeWidth, BoardShadeWidth, BoardShadeWidth);
    
            path.addRect(BoardShadeWidth, BoardShadeWidth,
                         this->width() - BoardShadeWidth * 2,
                         this->height() - BoardShadeWidth * 2);
            painter.fillPath(path, QBrush(Qt::white));
        }
            painter.drawPath(path);
    }
    
    
    • 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
    • 此类实现有2种方案
    1. 定义Platform_Win,此类仅支持windows系统,可以移动和改变大小;无法跨平台,效率高
    2. 非定义Platform_Win,支持跨平台,但是仅能实现移动,无法改变大小,效率低
    • 定义Platform_Win方式需要重写nativeEvent函数
        /**
         * 处理原生事件,用于实现无边框窗口的自定义拖动和缩放逻辑。
         *
         * @param eventType 事件类型。
         * @param message 事件的详细信息。
         * @param result 用于返回事件处理结果。
         * @return 如果事件被处理,则返回true;否则返回false。
         */
    bool FramelessWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
    {
    #ifdef Platform_Win
        if (!_resizeEnabled)
        { // 如果禁止了缩放,则将事件传递给父类处理
            return QDialog::nativeEvent(eventType, message, result);
        }
    
        Q_UNUSED(eventType);
        MSG *msg = reinterpret_cast<MSG *>(message);
        switch (msg->message)
        {
        case WM_NCHITTEST:
            // 计算鼠标位置相对于窗口的坐标
            int xPos = GET_X_LPARAM(msg->lParam) - this->frameGeometry().x();
            int yPos = GET_Y_LPARAM(msg->lParam) - this->frameGeometry().y();
            // 如果鼠标位置上有控件,则不处理
            if (this->childAt(xPos, yPos) != NULL)
            {
                return false;
            }
            // 判断鼠标位置是否在伪标题栏区域,以及在哪个边缘或角落
            // 鼠标位置上没有控件,先判断是否位于伪标题栏
            QRect rect = this->rect();
            rect.setHeight(_doubleClickHeight);
            if (rect.contains(QPoint(xPos, yPos))) // 鼠标位置位于伪标题栏区域内
            {
                *result = HTCAPTION;
            }
            // 判断鼠标是否在窗口的四个边或四个角落上
            if (xPos > BoardStartPix && xPos < BoardEndPix)
                *result = HTLEFT;
            if (xPos > (this->width() - BoardEndPix) && xPos < (this->width() - BoardStartPix))
                *result = HTRIGHT;
            if (yPos > BoardStartPix && yPos < BoardEndPix)
                *result = HTTOP;
            if (yPos > (this->height() - BoardEndPix) && yPos < (this->height() - BoardStartPix))
                *result = HTBOTTOM;
            if (xPos > BoardStartPix && xPos < BoardEndPix && yPos > BoardStartPix && yPos < BoardEndPix)
                *result = HTTOPLEFT;
            if (xPos > (this->width() - BoardEndPix) && xPos < (this->width() - BoardStartPix) && yPos > BoardStartPix && yPos < BoardEndPix)
                *result = HTTOPRIGHT;
            if (xPos > BoardStartPix && xPos < BoardEndPix && yPos > (this->height() - BoardEndPix) && yPos < (this->height() - BoardStartPix))
                *result = HTBOTTOMLEFT;
            if (xPos > (this->width() - BoardEndPix) && xPos < (this->width() - BoardStartPix) && yPos > (this->height() - BoardEndPix) && yPos < (this->height() - BoardStartPix))
                *result = HTBOTTOMRIGHT;
            return true;
        }
        return false;
    #else
        // 在非Windows平台上,将事件传递给父类处理
        return QDialog::nativeEvent(eventType, message, result);
    #endif
    }
    
    • 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
    • 阴影效果可以使用软件的方式绘制,也可以使用图片的方式,在paintEvent函数实现,相对复杂,不在此描述,可看源码。
    • 知识理应共享,源码在此。
    • 这个demo也是学习的,使用了很多比较专的宏与函数,加的注释尽量写了用途,不清楚的自己去查吧。
  • 相关阅读:
    LeetCode高频题:子串权值定义为,最长有效括号子序列的长度,请你返回字符串s的所有子串权值的和是多少
    Mistral 7B 比Llama 2更好的开源大模型 (一)
    leetcode 1624. 两个相同字符之间的最长子字符串
    微前端二:qiankun
    CIE A-Level化学Paper 1真题讲解(7)
    B树和B+树的理解
    HTTPS
    【java_wxid项目】【第十三章】【Elasticsearch集成】
    Vue3学习(二十二)- 保存文档内容
    我们能做出来数据库吗?
  • 原文地址:https://blog.csdn.net/weixin_49065061/article/details/137338526