1. 程式人生 > >【Qt】Qt之自定義介面(新增自定義標題欄)【轉】

【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事件中。

相關推薦

QtQt定義介面新增定義標題

簡述 通過上節內容,我們實現了自定義窗體的移動,但是我們缺少一個標題欄來顯示窗體的圖示、標題,以及控制窗體最小化、最大化、關閉的按鈕。 自定義標題欄後,所有的控制元件我們都可以定製,比如:在標題欄中新增換膚、設定按鈕以及其他控制元件。 簡述 效果 自定義標題欄 實現 介面說明

轉載統計學三大相關性係數pearson、spearman、kendall

三個相關性係數(pearson, spearman, kendall)反應的都是兩個變數之間變化趨勢的方向以及程度,其值範圍為-1到+1,0表示兩個變數不相關,正值表示正相關,負值表示負相關,值越大表示相關性越強。 person correlation coefficient(皮

QtQt定義介面實現無邊框、可移動

簡述 UI設計是指對軟體的人機互動、操作邏輯、介面美觀的整體設計。好的UI設計不僅是讓軟體變得有個性、有品位,還要讓軟體的操作變得舒適簡單、自由,充分體現軟體的定位和特點。 愛美之心人皆有之。其實軟體介面就像工業造型一樣,是產品的重要賣點。一個產品擁有美觀的介面會給人帶來舒適的視覺享受,拉近人與產品的

QtQt定義介面窗體縮放-跨平臺終極版

簡述 通過上一節內容,我們實現了窗體的縮放,功能很不錯,但是很遺憾-不支援跨平臺!如果對於多平臺來說,這是一個硬傷,所以,我們急需要一個能夠支援跨平臺的實現方案。 在網上看到過很多不同的實現方式,多多少少會存在一些問題-要麼融合度太高、要麼不能很好地進行移動、縮放。基於前人的分享與總結,最後,我花了很

QtQt定義介面右下角冒泡

簡述 網頁右下角上經常會出現一些提示性的資訊,桌面軟體中也比較常見,類似360新聞、QQ訊息提示一樣! 這種功能用動畫實現起來很簡單,這節我們暫時使用定時器來實現,後面章節會對動畫框架進行詳細講解。 下面我們來實現一個右下角冒泡的功能。 簡述 效果 實現原理 實現 效果

QtQt定義介面QMessageBox

簡述 通過前幾節的自定義窗體的學習,我們可以很容易的寫出一套屬於自己風格的介面框架,通用於各種窗體,比如:QWidget、QDialog、QMainWindow。 大多數窗體的實現都是採用控制元件堆積來完成的,只要思路清晰,再複雜的介面實現起來都遊刃有餘。下面我來列舉一個由QMessageBox擴充套

QtQt定義介面窗體縮放

簡述 通過前兩節內容,我們實現了自定義窗體的移動,以及自定義標題欄-用來顯示窗體的圖示、標題,以及控制窗體最小化、最大化、關閉。 在這之後,我們還缺少窗體的縮放-當滑鼠移動到窗體的邊框-左、上、右、下、左上角、左下角、右上角、右下角時候,滑鼠變為相應的樣式,並且窗體可以隨著滑鼠拖動而進行放大、縮小。

Qt 定義介面實現無邊框、可移動

簡述 UI設計是指對軟體的人機互動、操作邏輯、介面美觀的整體設計。好的UI設計不僅是讓軟體變得有個性、有品位,還要讓軟體的操作變得舒適簡單、自由,充分體現軟體的定位和特點。 愛美之心人皆有之。其實軟體介面就像工業造型一樣,是產品的重要賣點。一個產品擁有美觀的

Qt淺談五十介面定義

一、簡介       Qt自帶的介面不利於樣式的調整和美化,自定義介面便於設計風格。 二、詳解 1、程式碼 (1)pagenumbercontrol.h #ifndef PAGENUMBERCONTROL_H #define PAGENUMBERCONTROL_H

Qt 定義介面右下角冒泡

簡述 網頁右下角上經常會出現一些提示性的資訊,桌面軟體中也比較常見,類似360新聞、QQ訊息提示一樣! 這種功能用動畫實現起來很簡單,這節我們暫時使用定時器來實現,後面章節會對動畫框架進行詳細講解。 下面我們來實現一個右下角冒泡的功能。 | 效果

Qt 定義介面QMessageBox

簡述 通過前幾節的自定義窗體的學習,我們可以很容易的寫出一套屬於自己風格的介面框架,通用於各種窗體,比如:QWidget、QDialog、QMainWindow。 大多數窗體的實現都是採用控制元件堆積來完成的,只要思路清晰,再複雜的介面實現起來都遊刃有餘。下

Inno Setup修改安裝分割線前面的文字並定義風格顏色、字型大小等等

[Messages] BeveledLabel=少莫千華 [Code] procedure InitializeWizard(); begin WizardForm.BeveledLabel.

2、C++資料抽象/資料封裝/介面抽象類

一、C++資料抽象 1、定義     資料抽象是指,只向外界提供關鍵資訊,並隱藏其後臺的實現細節,即只表現必要的資訊而不呈現細節。資料抽象是一種依賴於介面和實現分離的程式設計(設計)技術。     C++類為資料抽象提供了可能。它們向外界提供了大量用於操作物件資料的公共方法,也就

Python正則表示式re模組

【轉】Python之正則表示式(re模組) 本節內容 re模組介紹 使用re模組的步驟 re模組簡單應用示例 關於匹配物件的說明 說說正則表示式字串前的r字首 re模組綜合應用例項 參考文件 提示: 由於該站對MARKDOWN的表格支援的不是很好,所以本文中的表

android定義View定義EditText新增刪除功能

           忙忙碌碌20天,新的專案終於接近尾聲了。今天公司召集幾個使用者體驗師和美工一起吐糟這20天做的這個新產品,對於產品提出了很多建議,這幾天就改介面了。在這個專案中大量的使用了EditText元件,並且添加了刪除功能。這裡面都是用RelativeLayou

Qt小心得1: QWidget中新增Q_OBJECT巨集, setStyleSheet設定了背景顏色不顯示

          QWidget在沒有新增Q_OBJECT巨集,在建構函式裡用setStyleSheet設定了背景顏色,是可以正常顯示,但添加了Q_OBJECT巨集後,QWidget就無法顯示背景色了, 百度了一下,發現了類似問題,說是QWidge

Learning Notes變分編碼器Variational Auto-Encoder,VAE

近年,隨著有監督學習的低枝果實被採摘的所剩無幾,無監督學習成為了研究熱點。VAE(Variational Auto-Encoder,變分自編碼器)[1,2] 和 GAN(Generative Adversarial Networks) 等模型,受到越來越多的關注

定製ListView的介面使用定義的列表項佈局,一邊顯示水果圖片,一邊顯示水果文字以及ListView的點選事件

只能顯示一段文字的ListView實在是太過單調,我們現在就來對ListView的介面進行定製,讓它可以顯示更加豐富的內容。 首先,我們需要準備好一組水果圖片,分別對應上面提供的每一種水果,待會我們要讓這些水果名稱的旁邊都有一個圖樣。   接著定義一個實體類,作為L

wif 系列C#單例模式Singleton最佳實踐

com value 快捷 lock 詳細介紹 筆記本 改進 奇怪 我不知道 目錄 介紹 第一個版本 ——不是線程安全的 第二個版本 —— 簡單的線程安全 第三個版本 - 使用雙重檢查鎖定嘗試線程安全 第四個版本 - 不太懶,不使用鎖且線程安全 第五版 - 完全懶惰的實例化

python+pyqt5+qt介面含資原始檔的生成

1.qt編寫介面 眾所周知,qt可以用ui設計出非常漂亮的介面,用生成ui的拖動視窗可實現介面.ui檔案的生成,示例如下圖 2.安裝pyqt5,python3.5: pip install pyqt