zoukankan      html  css  js  c++  java
  • 【Qt】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事件中。


    原文作者:一去丶二三里
    作者博客:去作者博客空间
    作者:芝麻科技
    出处:芝麻麻雀-Asp.Net学习之路
    技术:C++,C#
    向我打赏
    加我微信,聊一聊技术
  • 相关阅读:
    学习 Message(12): 整合鼠标 Down 消息
    合并两个 Wav 文件流的函数 回复 "刘文强" 的问题
    “博客无双”第一期拍卖活动获奖名单公告
    [获奖公告]“博客无双”12月27日第一期获奖名单
    “博客无双”活动拍卖时间调整公告
    致歉
    祝大家新年快乐
    博客园电子期刊2010年12月刊发布啦
    “博客无双”拍卖活动将于14:00开始
    2011年4月微软最有价值专家(MVP)申请截止时间:2011年1月13日
  • 原文地址:https://www.cnblogs.com/mzy-google/p/5162103.html
Copyright © 2011-2022 走看看