Qt实战案例(42)——利用Qt实现自定义标题栏功能(自定义最大化、最小化、关闭等功能)

一、项目介绍(为什么要自自定义标题栏功能)

无论是使用qtdesigner,还是直接在程序中创建一个Qwidget,qt程序生成的界面都会生成一个默认的标题栏。
该标题栏实质上应当是一个边框,只不过这个边框上可以显示ico,标题,可以进行最大化最小化等操作。
标题栏的颜色随计算机系统的主题变化,且形式固定,如果为界面设置统一的背景和风格,这个标题栏就会非常的突兀,丑陋。因此,如果想要获得一个和谐的统一的UI界面,我们最好把系统生成的默认标题栏去掉,自己重现默认标题栏附带的功能。

  • 默认标题栏,在统一背景下显得很突兀
  • 自定义标题栏,可以自己设计按键的大小,图标,位置,能够和背景更加统一
    在这里插入图片描述

二、项目基本配置

新建一个Qt案例,项目名称为“UITest”,基类选择“QWidget”,点击选中创建UI界面复选框,完成项目创建。

三、UI界面设计

UI界面布局如下:
在这里插入图片描述
在UI界面中分别添加三个toolbutton按钮:

序号名称类型属性
tbn_closeQToolButton\
tbn_maxQToolButton\
tbn_minQToolButton\

四、主程序实现

4.1 隐藏边框

QT编程中使用以下语句可以去除系统自动生成的默认边框。

setWindowFlags(Qt::FramelessWindowHint);//隐藏边框 

通过修改setWindowFlags的输入,我们还可以将边框修改成特殊的样式,比如只带一个关闭按钮。
Qt::FramelessWindowHint用于生成无边界窗口。用户无法通过窗口系统移动或调整无边框窗口的大小。

由于标题栏的本质是一个边框,或者说一个group,这个边框作为限制,UI内容嵌套在边框里,而边框则“悬浮”在桌面上,因此去掉标题栏后会存在如下问题:

  1. 因此,去除边框后,首当其冲,UI界面会因为失去边框丢失调整大小的能力,表现出来的就是鼠标无法选中界面的边缘,达到拖动边缘改变大小的目的。
  2. 因为改变界面在桌面上的位置原本由边框实现,去除边框后,UI与桌面不存在明确的布局关系,界面内容将无法移动。
  3. 原本程序的最大化(还原),最小化,关闭等功能由标题栏的按钮实现,去除标题栏后,该类操作界面的方式就会消失,不过我们仍可以通过底部状态栏右键操作界面。

总结而言,去除标题栏后,我们将无法通过按钮对界面进行最大化(还原),最小化,关闭等操作,无法拖动界面,也无法改变界面的大小,而这些也将是我们后续亟待实现的功能。

4.2 设置最大化(还原),最小化,关闭按钮的样式风格

首先,设置按钮样式:

    ui->tbn_close->setIcon(QIcon(":/img/close.png"));
    ui->tbn_max->setIcon(QIcon(":/img/max.png"));
    ui->tbn_min->setIcon(QIcon(":/img/min.png"));

绘制或找到符合自己界面风格的各按钮标志,并提前添加到QT的素材文件(.qrc)里,然后在程序中调用相应图片:

    //设置样式表(默认背景颜色、悬停时背景颜色、按下时背景颜色)
    setStyleSheet("QToolButton{background-color:rgba(0,0,0,0);}QToolButton:hover{background-color:rgba(255,255,255,0.5);}QToolButton:pressed{background-color: rgba(100,100,100,1);}");

4.3 关闭按钮的实现

要实现关闭操作,只需要在关闭按钮clicked槽函数下调用QT默认的close事件即可:

//close
void Widget::on_tbn_close_clicked()
{
    Widget::close();//关闭事件
}

4.4 最大化(还原)按钮的实现

最大化(还原)按钮的实现方式如下:

//max-restore
void Widget::on_tbn_max_clicked()
{
    if (Widget::isMaximized())
    {
        Widget::showNormal();//还原事件
        ui->tbn_max->setIcon(QIcon(":/img/max.png"));
    }
    else
    {
        Widget::showMaximized();//最大化事件
        ui->tbn_max->setIcon(QIcon(":/img/restore.png"));
    }
}

利用isMaximized()函数可以判断UI界面当前的状态,以分别实现最大化和还原的功能。功能切换时注意更换按钮上显示的图标icon,以显示其当前真正的功能。

4.5 最小化按钮的实现

//min
void Widget::on_tbn_min_clicked()
{
   Widget::showMinimized(); //最小化
}

4.6 实现界面移动

因为改变界面在桌面上的位置原本由边框实现,去除边框后,UI与桌面不存在明确的布局关系,界面内容将无法移动。

联想一下,正常情况下界面移动的操作过程是什么?鼠标左键长按标题栏中的非按钮位置,然后拖动鼠标,界面从起始位置移动到鼠标停留的位置。在此过程中,起到定位作用的参数分别有,界面当前的位置,鼠标光标的起始位置,鼠标光标终止位置,起到触发作用则是鼠标左键的长按动作。

用QT编程的思路解析该过程,可以表述为:鼠标左键长按作为信号,该信号触发的槽函数为计算操作过程中鼠标位置的变化,再将界面按鼠标位置的变化移动,达成鼠标拖动界面的效果。

因此,根据上述分析,鼠标拖动界面移动的实现至少需要两个部分:

  1. 识别鼠标的长按动作及落点,长按动作用于触发移动操作,落点则用于判断当前位置应不应该移动界面。

  2. 根据记录的鼠标位置,计算出鼠标在桌面坐标系中的变化,再将界面按照变化调整位置。

Step1:通过鼠标点击事件,识别鼠标左键按下操作,并记录当前位置:

void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        whereismouse=event->pos();
    }
}

Step2:通过鼠标移动事件,计算鼠标光标的坐标变化,并借助move事件使界面进行相同的移动:

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons() == Qt::LeftButton)
    {
        //当窗口最大化或最小化时也不进行触发
        if(Widget::isMaximized() || Widget::isMinimized())
        {
            return;
        }
        else
        {
            //当在按钮之类需要鼠标操作的地方不进行触发(防误触)
            if (ui->tbn_close->underMouse()||ui->tbn_max->underMouse()||ui->tbn_min->underMouse())
            {
            }
            else
            {
                Widget::move(Widget::mapToGlobal(event->pos()-whereismouse));//移动
            }
        }
    }
    event->accept();
}

underMouse()函数可以判断鼠标当前是否悬浮在相应控件上,通过该语句可以控制界面拖动的生效范围,使其不在按钮之类需要鼠标操作的地方误触发。

五、效果演示

完整效果如下:

利用Qt实现自定义标题栏功能示例


如果没有看懂的话,完整代码可以参考:https://download.csdn.net/download/didi_ya/85153071

ok,以上便是本文的全部内容了,如果对你有所帮助,记得点个赞哟~

可以使用Qt的QMainWindow类来自定义标题栏。 首先,需要将窗口的标题栏隐藏起来,可以使用setWindowFlags函数来实现: ```cpp setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); ``` 这里使用了`Qt::FramelessWindowHint`参数来隐藏窗口的标题栏,`Qt::WindowSystemMenuHint`参数来显示窗口的系统菜单,`Qt::WindowMinMaxButtonsHint`参数来显示窗口的最大化最小化按钮。 接下来,需要在窗口中添加自定义标题栏。可以使用QWidget来实现,将其作为QMainWindow的子控件添加到窗口中: ```cpp QWidget *titleBar = new QWidget(this); titleBar->setObjectName("TitleBar"); titleBar->setStyleSheet("QWidget#TitleBar{background-color: #F0F0F0;}"); titleBar->setFixedHeight(30); QHBoxLayout *layout = new QHBoxLayout(titleBar); layout->setMargin(0); layout->setSpacing(0); QLabel *titleLabel = new QLabel(titleBar); titleLabel->setText("My Title"); titleLabel->setStyleSheet("QLabel{font-size: 14px;color: #333333;}"); layout->addWidget(titleLabel); layout->addStretch(); QToolButton *minButton = new QToolButton(titleBar); minButton->setObjectName("MinButton"); minButton->setStyleSheet("QToolButton{border:none;background-color:transparent;}" "QToolButton:hover{background-color:#E0E0E0;}" "QToolButton:pressed{background-color:#D0D0D0;}"); minButton->setIcon(QIcon(":/titlebar/minimize.png")); minButton->setFixedSize(30, 30); layout->addWidget(minButton); QToolButton *maxButton = new QToolButton(titleBar); maxButton->setObjectName("MaxButton"); maxButton->setStyleSheet("QToolButton{border:none;background-color:transparent;}" "QToolButton:hover{background-color:#E0E0E0;}" "QToolButton:pressed{background-color:#D0D0D0;}"); maxButton->setIcon(QIcon(":/titlebar/maximize.png")); maxButton->setFixedSize(30, 30); layout->addWidget(maxButton); QToolButton *closeButton = new QToolButton(titleBar); closeButton->setObjectName("CloseButton"); closeButton->setStyleSheet("QToolButton{border:none;background-color:transparent;}" "QToolButton:hover{background-color:#E0E0E0;}" "QToolButton:pressed{background-color:#D0D0D0;}"); closeButton->setIcon(QIcon(":/titlebar/close.png")); closeButton->setFixedSize(30, 30); layout->addWidget(closeButton); setMenuWidget(titleBar); ``` 这里创建了一个名为"titleBar"的QWidget作为窗口的标题栏,设置了其背景颜色和固定高度。然后创建了一个水平布局并添加了一个QLabel、一个最小化按钮、一个最大化按钮和一个关闭按钮。最后将标题栏设置为窗口的菜单控件,用于显示系统菜单。 需要注意的是,上面的代码中使用了三个图标文件,需要将它们添加到Qt项目中,并在代码中使用正确的路径。 ```qrc <RCC> <qresource prefix="/titlebar"> <file>minimize.png</file> <file>maximize.png</file> <file>close.png</file> </qresource> </RCC> ``` 最后,需要在窗口中实现标题栏按钮的功能。可以在按钮的clicked信号中实现最小化最大化关闭窗口的功能: ```cpp connect(minButton, &QToolButton::clicked, this, &QMainWindow::showMinimized); connect(maxButton, &QToolButton::clicked, this, &QMainWindow::showMaximized); connect(closeButton, &QToolButton::clicked, this, &QMainWindow::close); ``` 这里使用了Qt的槽函数机制来实现按钮的功能。 完整的示例代码可以参考下面的链接: https://github.com/qt/qtbase/blob/dev/examples/widgets/widgets/framelesswindow/main.cpp
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wendy_ya

您的鼓励将是我创作的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值