Qt 之自定义界面(添加自定义标题栏)

简述

通过上节内容,我们实现了自定义窗体的移动,但是我们缺少一个标题栏来显示窗体的图标、标题,以及控制窗体最小化、最大化、关闭的按钮。

自定义标题栏后,所有的控件我们都可以定制,比如:在标题栏中添加换肤、设置按钮以及其他控件。

| 版权声明:一去、二三里,未经博主允许不得转载。

效果

这里写图片描述

自定义标题栏

实现

title_bar.h

#ifndef TITLE_BAR
#define TITLE_BAR

#include <QWidget>

class QLabel;
class QPushButton;

class TitleBar : public QWidget
{
    Q_OBJECT

public:
    explicit TitleBar(QWidget *parent = 0);
    ~TitleBar();

protected:

    // 双击标题栏进行界面的最大化/还原
    virtual void mouseDoubleClickEvent(QMouseEvent *event);

    // 进行鼠界面的拖动
    virtual void mousePressEvent(QMouseEvent *event);

    // 设置界面标题与图标
    virtual bool eventFilter(QObject *obj, QEvent *event);

private slots:

    // 进行最小化、最大化/还原、关闭操作
    void onClicked();

private:

    // 最大化/还原
    void updateMaximize();

private:
    QLabel *m_pIconLabel;
    QLabel *m_pTitleLabel;
    QPushButton *m_pMinimizeButton;
    QPushButton *m_pMaximizeButton;
    QPushButton *m_pCloseButton;
};

#endif // TITLE_BAR

title_bar.cpp

#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include <QEvent>
#include <QMouseEvent>
#include <QApplication>
#include "title_bar.h"

#ifdef Q_OS_WIN
#pragma comment(lib, "user32.lib")
#include <qt_windows.h>
#endif

TitleBar::TitleBar(QWidget *parent)
    : QWidget(parent)
{
    setFixedHeight(30);

    m_pIconLabel = new QLabel(this);
    m_pTitleLabel = new QLabel(this);
    m_pMinimizeButton = new QPushButton(this);
    m_pMaximizeButton = new QPushButton(this);
    m_pCloseButton = new QPushButton(this);

    m_pIconLabel->setFixedSize(20, 20);
    m_pIconLabel->setScaledContents(true);

    m_pTitleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

    m_pMinimizeButton->setFixedSize(27, 22);
    m_pMaximizeButton->setFixedSize(27, 22);
    m_pCloseButton->setFixedSize(27, 22);

    m_pTitleLabel->setObjectName("whiteLabel");
    m_pMinimizeButton->setObjectName("minimizeButton");
    m_pMaximizeButton->setObjectName("maximizeButton");
    m_pCloseButton->setObjectName("closeButton");

    m_pMinimizeButton->setToolTip("Minimize");
    m_pMaximizeButton->setToolTip("Maximize");
    m_pCloseButton->setToolTip("Close");

    QHBoxLayout *pLayout = new QHBoxLayout(this);
    pLayout->addWidget(m_pIconLabel);
    pLayout->addSpacing(5);
    pLayout->addWidget(m_pTitleLabel);
    pLayout->addWidget(m_pMinimizeButton);
    pLayout->addWidget(m_pMaximizeButton);
    pLayout->addWidget(m_pCloseButton);
    pLayout->setSpacing(0);
    pLayout->setContentsMargins(5, 0, 5, 0);

    setLayout(pLayout);

    connect(m_pMinimizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
    connect(m_pMaximizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
    connect(m_pCloseButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
}

TitleBar::~TitleBar()
{

}

void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
    Q_UNUSED(event);

    emit m_pMaximizeButton->clicked();
}

void TitleBar::mousePressEvent(QMouseEvent *event)
{
#ifdef Q_OS_WIN
    if (ReleaseCapture())
    {
        QWidget *pWindow = this->window();
        if (pWindow->isTopLevel())
        {
           SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
        }
    }
       event->ignore();
#else
#endif
}

bool TitleBar::eventFilter(QObject *obj, QEvent *event)
{
    switch (event->type())
    {
    case QEvent::WindowTitleChange:
    {
        QWidget *pWidget = qobject_cast<QWidget *>(obj);
        if (pWidget)
        {
            m_pTitleLabel->setText(pWidget->windowTitle());
            return true;
        }
    }
    case QEvent::WindowIconChange:
    {
        QWidget *pWidget = qobject_cast<QWidget *>(obj);
        if (pWidget)
        {
            QIcon icon = pWidget->windowIcon();
            m_pIconLabel->setPixmap(icon.pixmap(m_pIconLabel->size()));
            return true;
        }
    }
    case QEvent::WindowStateChange:
    case QEvent::Resize:
        updateMaximize();
        return true;
    }
    return QWidget::eventFilter(obj, event);
}

void TitleBar::onClicked()
{
    QPushButton *pButton = qobject_cast<QPushButton *>(sender());
    QWidget *pWindow = this->window();
    if (pWindow->isTopLevel())
    {
        if (pButton == m_pMinimizeButton)
        {
            pWindow->showMinimized();
        }
        else if (pButton == m_pMaximizeButton)
        {
            pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized();
        }
        else if (pButton == m_pCloseButton)
        {
            pWindow->close();
        }
    }
}

void TitleBar::updateMaximize()
{
    QWidget *pWindow = this->window();
    if (pWindow->isTopLevel())
    {
        bool bMaximize = pWindow->isMaximized();
        if (bMaximize)
        {
            m_pMaximizeButton->setToolTip(tr("Restore"));
            m_pMaximizeButton->setProperty("maximizeProperty", "restore");
        }
        else
        {
            m_pMaximizeButton->setProperty("maximizeProperty", "maximize");
            m_pMaximizeButton->setToolTip(tr("Maximize"));
        }

        m_pMaximizeButton->setStyle(QApplication::style());
    }
}

接口说明

  • mousePressEvent

之前,我们将界面移动的事件写在主界面里面,这会有一个问题,一般情况下,是界面随着标题栏的移动而移动,而并非界面中的所有位置都可以进行拖动,所以我们将事件写在标题栏中比较合理。

  • mouseDoubleClickEvent

双击标题栏会进行窗体的最大化/还原,所以我们需要重写此事件进行控制。

  • eventFilter
  1. 事件过滤器,这里被监听的窗体为标题栏所在的窗体,所以当窗体标题、图标等信息发生改变时,标题栏也应该随之改变。

  2. 最好不要通过直接调用接口的形式来操作对应的行为,比如:TitleBar中定义一个public函数来专门修改标题与图标,这样会造成不必要的麻烦,因为Qt本身就是基于事件的,所以此处采用过滤器的方式。

  • updateMaximize

因为窗体大小发生变化的时候,最大化的图标、提示应该对应的发生变化,所以在eventFilter中事件触发时调用。

使用方式

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    setWindowFlags(Qt::FramelessWindowHint | windowFlags());

    TitleBar *pTitleBar = new TitleBar(this);
    installEventFilter(pTitleBar);

    resize(400, 300);
    setWindowTitle("Custom Window");
    setWindowIcon(QIcon(":/Images/logo"));

    QPalette pal(palette());
    pal.setColor(QPalette::Background, QColor(50, 50, 50));
    setAutoFillBackground(true);
    setPalette(pal);

    QVBoxLayout *pLayout = new QVBoxLayout();
    pLayout->addWidget(pTitleBar);
    pLayout->addStretch();
    pLayout->setSpacing(0);
    pLayout->setContentsMargins(0, 0, 0, 0);
    setLayout(pLayout);
}

注意

installEventFilter必须在setWindowTitle、setWindowIcon之前调用,因为必须先安装事件过滤器,相应事件触发时,才会进入标题栏的eventFilter事件中。

  • 37
    点赞
  • 146
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 51
    评论
### 回答1: Qt中可以通过样式表来改变窗口标题栏的颜色。 样式表是指一种用于在应用程序中设置部件外观的文本文件。它使用类似于CSS的语法,使程序员能够改变控件的属性,如颜色、字体、大小、背景等。 窗口标题栏是由QMainWindow类中的QWidget *centralWidget()函数返回的QWidget对象控制的。因此,我们可以通过在样式表中设置这个控件的背景颜色来改变标题栏的颜色。 下面是一个例子: QMainWindow { background-color: red; } 这个样式表将改变应用程序中所有QMainWindow的背景颜色为红色。如果你不想改变所有的QMainWindow,你可以用QWidget标签来限定样式表只对该窗口有效。 例如: QWidget#myWindow { background-color: blue; } 这个样式表将改变一个ID为“myWindow”的QWidget背景颜色为蓝色。 总之,我们可以根据需要编写适当的样式表来改变窗口标题栏的颜色,从而使我们的应用程序更加个性化和美观。 ### 回答2: 在Qt中,我们可以通过修改QWidget的样式来改变窗口标题栏的颜色。具体步骤如下: 1. 找到窗口标题栏的QSS属性名称。在Qt中,窗口标题栏的QSS属性名称为"QHeaderView::section"。 2. 写入QSS代码。在写入QSS代码前,需要注意QSS的语法和格式。以下是一个简单的QSS样式: QHeaderView::section{ background-color:red; color:white; font-size:14px; font-weight:bold; } 在上面的代码中,background-color用来设置窗口标题栏的背景色,color用来设置文字颜色,font-size用来设置字体大小,font-weight用来设置字体加粗等。 3. 应用QSS样式。将刚才所写的QSS代码应用到QWidget上,即可实现改变窗口标题栏颜色的效果。以下是一个使用QSS样式的示例代码: QWidget *pWidget = new QWidget(this); pWidget->setStyleSheet("QHeaderView::section{background-color:red;color:white;font-size:14px;font-weight:bold;}"); pWidget->show(); 在这段代码中,我们先创建了一个QWidget对象,然后通过setStyleSheet()方法应用QSS样式,最后通过show()方法显示QWidget对象。 通过以上步骤,就可以轻松地改变窗口标题栏的颜色了。当然,除了颜色,还可以通过修改QSS样式来改变窗口标题栏的其他样式。 ### 回答3: Qt是一种流行的跨平台界面开发框架,可以轻松地创建各种类型的应用程序,包括窗口标题栏的颜色。在Qt中,改变窗口标题栏的颜色可以通过以下步骤实现: 1. 声明QPalette对象,并使用setBrush()方法设置QPalette的颜色。 2. 获取窗口的QPalette对象,使用setPalette()方法设置新的QPalette。 3. 使用setStyleSheet()方法设置新的标题栏样式表,以覆盖旧的样式并使用新的颜色。 下面是具体的代码实现: QPalette palette; palette.setBrush(QPalette::Window, QBrush(QColor(255, 0, 0, 255))); // 设置标题栏背景颜色为红色 ui->widget->setPalette(palette); // 获取窗口并将QPalette设置为新的颜色 QString styleSheet = QString("QHeaderView::section {background-color: %1;}").arg(QColor(0, 255, 0, 255).name()); // 设置标题栏文本颜色为绿色 ui->widget->setStyleSheet(styleSheet); // 将新的样式表设置为标题栏样式表,以修改颜色 需要注意的是,由于不同平台上的窗口标题栏实现可能有所不同,因此您可能需要针对不同的平台编写特定的代码来确保与所需的效果一致。
评论 51
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一去丶二三里

有收获,再打赏!

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

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

打赏作者

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

抵扣说明:

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

余额充值