Qt C++自定义窗体,实现自定义标题栏、阴影、全局背景、拖拽、缩放、最大化等功能,附下载链接

本文详细介绍了如何使用Qt实现自定义窗体,包括设置阴影效果、自定义标题栏、实现拖拽、缩放、最大化、最小化和关闭功能。通过QGraphicsDropShadowEffect实现阴影,通过重写鼠标事件处理拖拽,使用QLabel作为边界实现缩放,以及通过信号槽处理最大化和关闭操作。文章还分享了具体的代码实现和资源下载链接。
摘要由CSDN通过智能技术生成

第一章 项目特点

功能:自定义标题栏、阴影、透明、边框、全局背景、拖拽、缩放、最大化、最小化、还原、关闭、记住窗体状态。

网上已经有很多类似的教程,但都有一些不足。本篇文章几乎完全实现了和window默认窗体的所有功能(缺少最小化的动画和分屏)。
我是业余的,水平不高,这是我能想到最完美的解决方案了。

第二章 大致思路

2.1 阴影

Qt中的QGraphicsDropShadowEffect类,可以实现阴影效果。
而QWidget提供了void QWidget::setGraphicsEffect(QGraphicsEffect *effect)
通过这个函数,就能为窗体设置阴影。但有一些细节需要知晓:

  • 窗体范围:一个应用程序的范围就是最外层窗体的geometry(),任何超出这个范围的效果都没法显示。

而阴影便是超出了所在窗体的范围,所以为了实现阴影效果,需要再外层窗体内嵌套一个窗体,为内层窗体设置阴影。这样阴影就不会超出应用程序的范围了。

2.2 标题栏

自定义窗体最重要的就是能自定义标题栏,比如在标题栏上加上其他的东西,像这样:
在这里插入图片描述
窗体的标题栏属于操作系统控制,肯定是没法修改的,想要实现上面的效果,肯定要隐藏窗体的默认标题栏,然后自己做一个标题栏。

2.3 拖拽

当鼠标拖拽标题栏时,可以移动整个窗体。这里可以重写QWidget的鼠标按下、鼠标移动、鼠标释放三个事件来实现。

  • 首先鼠标按下时,记录鼠标坐标、鼠标状态、窗体坐标;
  • 鼠标移动时,计算鼠标移动的向量,让窗体原来的坐标加上这个向量;
  • 鼠标释放时,更新鼠标状态。
2.4 缩放

当鼠标移动到窗体边缘时,鼠标样式自动改变,并且拖拽鼠标实现改变窗体的大小。
这里我在窗体的四周放置了8个QLabel,分别放在绿色和蓝色区域,利用他们定义了“窗体四周”。
在这里插入图片描述
网上其他例子都是在鼠标移动事件里判断鼠标坐标,进而改变鼠标样式,实现相应的功能,逻辑很复杂,而且要为窗体里所有元素设置鼠标跟踪:setMouseTracking(true)。
这里利用8个标签,省去了该表鼠标样式的麻烦,简化了判断鼠标位置的逻辑,并且非常稳定,不会出现各种各样的bug。

2.5 最小化、最大化、还原、关闭

在内层窗体里加上相应的QToolButton,连接信号槽即可。
比较复杂的时最大化/还原按钮,当窗体最大化时,应当隐藏阴影、8个标签、改变按钮图标。

第三章 具体实现

环境:Qt Creator 5.9

  • 新建QWidget项目,选中ui设计界面。这个界面就是窗体的主界面,按钮、文本框之类的元素放在这个界面上。
  • 添加BaseWindow类,继承自QWidget类,在这个类中实现阴影,拖拽等功能。
  • 添加一些必要的图标资源。
  • 在main函数里设置启动窗体为BaseWindow。
    在这里插入图片描述
    最外面的虚线框为BaseWindow,内层实线框为Widget。蓝绿色为8个标签,放置在BaseWindow里。
    在这里插入图片描述
3.1 设置布局

在BaseWindow头文件中定义变量:

private:
    QSettings *m_Settings;

    int m_ShadowWidth;      //阴影宽度,也是m_BaseLayout的margin
    int m_ResizeWidth = 3;     //窗体四周调整尺寸的宽度,也是m_LblLeftTop等的宽度或高度

    int m_TitleHeight;          //标题栏高度
    int m_TempShadowWidth;

    //记录窗体状态
    bool m_IsMaximized;
    QRect m_Rect;
    int m_BorderWidth;

    //用于调整窗体大小的label
    QLabel *m_LblLeftTop;
    QLabel *m_LblTop;
    QLabel *m_LblRightTop;
    QLabel *m_LblLeft;
    QLabel *m_LblRight;
    QLabel *m_LblLeftBottom;
    QLabel *m_LblBottom;
    QLabel *m_LblRightBottom;

    QFrame *m_BaseFrame;            //主窗体,产生阴影,容纳m_ContentWindow等
    QGridLayout *m_BaseLayout;      //主窗体的网格布局

    Widget *m_ContentWindow;        //用户实际的界面,指向构造函数传入的ContentWindow
    QGridLayout *m_ContentLayout;   //m_ContentWindow的网格布局

定义私有成员函数void initializeUi();
在这个函数内实现界面布局,具体实现如下:

//初始化窗体
void BaseWindow::initializeUi()
{
   
    //读取ini配置文件
    m_Settings = new QSettings(QApplication::applicationDirPath()+"/config.ini", QSettings::IniFormat, this);

    //设置背景窗体透明,为了实现阴影效果
    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);
    this->setAttribute(Qt::WA_TranslucentBackground);

    //BaseWindow显示阴影的布局
    m_ShadowWidth = m_Settings->value("Shadow/shadowWidth").toInt();
    m_BaseLayout = new QGridLayout();
    m_BaseLayout->setMargin(m_ShadowWidth);
    m_BaseLayout->setSpacing(0);
    this->setLayout(m_BaseLayout);

    //主窗体显示
    m_BaseFrame = new QFrame();
    m_BaseFrame->setObjectName("m_BaseFrame");
    QString borderStyle = m_Settings->value("BaseWindow/border").toString();
    m_BaseFrame->setStyleSheet("QFrame#m_BaseFrame{border:"+borderStyle+"}");
    m_BorderWidth = borderStyle.mid(0, borderStyle.indexOf("px")).toInt();
    m_BaseLayout->addWidget(m_BaseFrame, 0, 0, 3, 3);

    //主窗体的布局
    m_ContentLayout = new QGridLayout();
    m_ContentLayout->setMargin(0);
    m_ContentLayout->setSpacing(0);
    m_BaseFrame->setLayout(m_ContentLayout);

    //加入主窗体
    m_ContentWindow = new Widget();
    m_ContentLayout->addWidget(m_ContentWindow, 0, 0);

    //设置最大化按钮的图标
    m_ContentWindow->setToolResizeIcon(m_IsMaximized);

    //设置调整窗体大小的Label
    {
   
        m_LblLeftTop = new QLabel();
        m_LblLeftTop->setFixedSize(m_ResizeWidth, m_ResizeWidth);
        m_LblLeftTop->setCursor(Qt::SizeFDiagCursor
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值