Qt之自定义标题栏拓展(十)

Qt开发 系列文章 - user-defined-titlebars(十)


目录

前言

一、方式一

1.效果演示

2.创建标题栏类

3.可视化UI设计

4.定义相关函数

5.使用标题栏类

二、方式二

1.效果演示

2.创建标题栏类

3.定义相关函数

1.初始化函数

2.功能函数

3.窗口关联

4.使用标题栏类

三、方式三

1.实现方式

2.效果演示

总结


前言

Qt自带的窗口标题栏通常遵循操作系统的默认样式和布局,以确保在不同平台上都能提供一致且符合用户期望的用户体验,因此Qt自带的窗口标题栏无法自定义。但我们在Qt设计软件时,经常需要改变窗口标题栏的样式,以满足不同场合用户需求。本文紧接着上一篇博文Qt之修改窗口标题、图标以及自定义标题栏(九)-CSDN博客的基础上,在介绍几种实现自定义标题栏的方法,并提供简单示例。


一、方式一

上一篇博文Qt之修改窗口标题、图标以及自定义标题栏(九)实现该方式是通过直接手鲁编写标题栏UI代码,下面提供的方式是在可视化界面UI上来设计标题栏,简洁方便直观,然后绑定/链接到主窗口界面上。

1.效果演示

2.创建标题栏类

跟上一个有区别的是,在原有的项目上,添加新的类文件,选择带ui设计类的模版,选择如下。

然后,定义类和ui的名称为MyTitleBar,MyTitleBar类的头文件代码如下(示例):

/** 只提供与上一篇不一样的代码地方 **/
QT_BEGIN_NAMESPACE
namespace Ui { class MyTitleBar; }
QT_END_NAMESPACE

class MyTitleBar : public QWidget
{
private slots:
    // 按钮触发的槽;
    void on_m_pButtonClose_clicked();
    void on_m_pButtonMax_clicked();
    void on_m_pButtonRestore_clicked();
    void on_m_pButtonMin_clicked();
private:
    Ui::MyTitleBar *ui;
};

3.可视化UI设计

上面我们定义标题栏类的头文件,下面来在可视化界面UI上来设计标题栏,双击打开.ui文件,在图像化设计界面设计如下标题栏。

  

上面设计完后,Qt会自动生成相应的UI代码和头文件,相关类为Ui_MyTitleBar。

4.定义相关函数

设计好MyTitleBar的UI文件后,下面来说明相关功能函数。

#include "ui_mytitlebar.h"
#include "mytitlebar.h"

MyTitleBar::MyTitleBar(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MyTitleBar)
{
    // UI初始化
    ui->setupUi(this);
    // 初始化控件
    initControl();
    // 初始化标题栏色彩
    setBackgroundColor(m_colorR, m_colorG, m_colorB, m_isTransparent);
    // 加载本地样式 .css文件
    //loadStyleSheet("MyTitle");
    // 初始化标题栏色彩
    setBackgroundColor(230,232,250,0);

setStyleSheet("QToolButton#m_pButtonMenu,QPushButton#m_pButtonMin,QPushButton#m_pButtonMax,QPushButton#m_pButtonClose{\
    border-radius:3px;\
    color:#324C6C;\
    padding:3px;\
    margin:0px;\
    background:none;\
    border-style:none;\
    }");
                 setStyleSheet("QToolButton#m_pButtonMenu:hover,QPushButton#m_pButtonMin:hover,QPushButton#m_pButtonMax:hover{\
    color:#FFFFFF;\
    margin:1px 1px 2px 1px;\
    background-color:rgba(51,127,209,230);\
    }");
}
MyTitleBar::~MyTitleBar()
{
}
void MyTitleBar::initControl()
{
    m_colorR=0;
    m_colorG=153;
    m_colorB=153;
    m_isPressed=false;
    m_buttonType=MIN_MAX_BUTTON;
    m_windowBorderWidth=0;
    m_isTransparent=false;
    setFixedHeight(30);
    setWindowFlags(Qt::FramelessWindowHint);
    // 添加换肤菜单
    QStringList name;
    name << "银色" << "蓝色" << "浅蓝色" << "深蓝色";
    foreach (QString str, name) {
        QAction *action = new QAction(str, this);
        ui->m_pButtonMenu->addAction(action);
        connect(action, SIGNAL(triggered(bool)), this, SLOT(onButtonchangeStyle()));
    }
}
// 以下为按钮操作响应的槽
void MyTitleBar::onButtonchangeStyle()
{
    QAction *act = (QAction *)sender();
    QString name = act->text();
    //QString qssFile = "qss/blue.css";
    if (name == "银色") {
        //qssFile = "qss/silvery.css";
        setBackgroundColor(230,232,250,0);
    }
    else if (name == "蓝色"){
        //qssFile = "qss/blue.css";
        setBackgroundColor(50,76,108,0);
    }
    else if (name == "浅蓝色"){
        //qssFile = "qss/lightblue.css";
        setBackgroundColor(56,100,135,0);
    }
    else if (name == "深蓝色"){
        //qssFile = "qss/darkblue.css";
        setBackgroundColor(122,175,227,0);
    }
    //loadStyleSheet(qssFile);
    //emit signalchangeStyle(qssFile);
}
void MyTitleBar::on_m_pButtonClose_clicked()
{
    emit signalButtonCloseClicked();
}
void MyTitleBar::on_m_pButtonMax_clicked()
{
    ui->m_pButtonMax->setVisible(false);
    ui->m_pButtonRestore->setVisible(true);
    emit signalButtonMaxClicked();
}
void MyTitleBar::on_m_pButtonRestore_clicked()
{
    ui->m_pButtonRestore->setVisible(false);
    ui->m_pButtonMax->setVisible(true);
    emit signalButtonRestoreClicked();
}
void MyTitleBar::on_m_pButtonMin_clicked()
{
    emit signalButtonMinClicked();
}

5.使用标题栏类

在用户的构造函数上面添加对标题栏类的使用,跟上一篇博文一样。

二、方式二

方式一实现自定义标题栏时,定义一个标题栏类,在生成标题栏时,会覆盖原有的MenuBar和ToolBar,方式二改进后,修改标题栏不覆盖,效果如下。

1.效果演示

2.创建标题栏类

跟上一篇博文一样,在原有的项目上,添加C++新的类文件,选择如下。

然后定义标题栏类,代码部分如下(示例):

#include <QDialog>
#include <QMutex>

class QLabel;
class QPushButton;
class QToolButton;
class QVBoxLayout;
class QHBoxLayout;
class QFrame;
class QSpacerItem;
class QLineEdit;
class QComboBox;
class QAbstractButton;
class QUIWidget : public QDialog
        #endif
{
    Q_OBJECT
    Q_ENUMS(Style)
    Q_PROPERTY(QString title READ getTitle WRITE setTitle)
    Q_PROPERTY(Qt::Alignment alignment READ getAlignment WRITE setAlignment)
public:
    explicit QUIWidget(QWidget *parent = 0);
    ~QUIWidget();
public Q_SLOTS:
    //设置主窗体
    void setMainWidget(QWidget *mainWidget);
    //设置部件图标
    void setIcon(QUIWidget::Widget widget, QChar str, quint32 size = 9);
    //设置部件图片
    void setPixmap(QUIWidget::Widget widget, const QString &file, const QSize &size = QSize(16, 16));
    //设置部件是否可见
    void setVisible(QUIWidget::Widget widget, bool visible = true);
    //设置只有关闭按钮
    void setOnlyCloseBtn();
    //设置标题栏高度
    void setTitleHeight(int height);
    //设置按钮统一宽度
    void setBtnWidth(int width);
    //设置标题及文本样式
    void setTitle(const QString &title);
    void setAlignment(Qt::Alignment alignment);
};

3.定义相关函数

1.初始化函数

在标题栏类构造函数上,初始化如下设置,代码如下。

QUIWidget::QUIWidget(QWidget *parent) : QDialog(parent)
{
    //定义标题栏字体文本编码
    this->setTranslator(":/qm/qt_zh_CN.qm");
    this->setCode();
    this->initControl();
    this->initForm();
    //设置标题栏标题
#ifdef csd
    setTitle("**软件");
#else
    setTitle("csd演示版");
#endif
    //设置标题文本居中
    setAlignment(Qt::AlignCenter);
    //设置窗体可拖动大小
    setSizeGripEnabled(true);
    //设置换肤下拉菜单可见
    setVisible(QUIWidget::BtnMenu, true);
    //设置标题栏高度
    setTitleHeight(30);
    //设置按钮宽度
    setBtnWidth(30);
    //设置软件左上角图标--没有图标时显示图形字体
    setPixmap(QUIWidget::Lab_Ico, "ico/butterfly.ico", QSize(30,30));
    //默认样式风格blue
    setStyle(":/qss/blue.css");
    QFont font;
    font.setPointSize(12);
    this->setFont(font);
}
void QUIWidget::initControl()
{
    this->setObjectName(QString::fromUtf8("QUIWidget"));
    this->resize(900, 750);
    verticalLayout1 = new QVBoxLayout(this);
    verticalLayout1->setSpacing(0);
    verticalLayout1->setContentsMargins(11, 11, 11, 11);
    verticalLayout1->setObjectName(QString::fromUtf8("verticalLayout1"));
    verticalLayout1->setContentsMargins(1, 1, 1, 1);
    widgetMain = new QWidget(this);
    widgetMain->setObjectName(QString::fromUtf8("widgetMain"));
    widgetMain->setStyleSheet(QString::fromUtf8(""));
    verticalLayout2 = new QVBoxLayout(widgetMain);
    verticalLayout2->setSpacing(0);
    verticalLayout2->setContentsMargins(11, 11, 11, 11);
    verticalLayout2->setObjectName(QString::fromUtf8("verticalLayout2"));
    verticalLayout2->setContentsMargins(0, 0, 0, 0);
    widget_title = new QWidget(widgetMain);
    widget_title->setObjectName(QString::fromUtf8("widget_title"));
    QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
    sizePolicy.setHorizontalStretch(0);
    sizePolicy.setVerticalStretch(0);
    sizePolicy.setHeightForWidth(widget_title->sizePolicy().hasHeightForWidth());
    widget_title->setSizePolicy(sizePolicy);
    widget_title->setMinimumSize(QSize(0, 30));
    horizontalLayout4 = new QHBoxLayout(widget_title);
    horizontalLayout4->setSpacing(0);
    horizontalLayout4->setContentsMargins(11, 11, 11, 11);
    horizontalLayout4->setObjectName(QString::fromUtf8("horizontalLayout4"));
    horizontalLayout4->setContentsMargins(0, 0, 0, 0);
    lab_Ico = new QLabel(widget_title);
    lab_Ico->setObjectName(QString::fromUtf8("lab_Ico"));
    QSizePolicy sizePolicy1(QSizePolicy::Minimum, QSizePolicy::Preferred);
    sizePolicy1.setHorizontalStretch(0);
    sizePolicy1.setVerticalStretch(0);
    sizePolicy1.setHeightForWidth(lab_Ico->sizePolicy().hasHeightForWidth());
    lab_Ico->setSizePolicy(sizePolicy1);
    lab_Ico->setMinimumSize(QSize(30, 0));
    lab_Ico->setAlignment(Qt::AlignCenter);

    horizontalLayout4->addWidget(lab_Ico);

    lab_Title = new QLabel(widget_title);
    lab_Title->setObjectName(QString::fromUtf8("lab_Title"));
    QSizePolicy sizePolicy2(QSizePolicy::Expanding, QSizePolicy::Preferred);
    sizePolicy2.setHorizontalStretch(0);
    sizePolicy2.setVerticalStretch(0);
    sizePolicy2.setHeightForWidth(lab_Title->sizePolicy().hasHeightForWidth());
    lab_Title->setSizePolicy(sizePolicy2);
    lab_Title->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter);

    horizontalLayout4->addWidget(lab_Title);

    widget_menu = new QWidget(widget_title);
    widget_menu->setObjectName(QString::fromUtf8("widget_menu"));
    sizePolicy1.setHeightForWidth(widget_menu->sizePolicy().hasHeightForWidth());
    widget_menu->setSizePolicy(sizePolicy1);
    horizontalLayout = new QHBoxLayout(widget_menu);
    horizontalLayout->setSpacing(0);
    horizontalLayout->setContentsMargins(11, 11, 11, 11);
    horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
    horizontalLayout->setContentsMargins(0, 0, 0, 0);
    btnMenu = new QToolButton(widget_menu);
    btnMenu->setObjectName(QString::fromUtf8("btnMenu"));
    QSizePolicy sizePolicy3(QSizePolicy::Fixed, QSizePolicy::Expanding);
    sizePolicy3.setHorizontalStretch(0);
    sizePolicy3.setVerticalStretch(0);
    sizePolicy3.setHeightForWidth(btnMenu->sizePolicy().hasHeightForWidth());
    btnMenu->setSizePolicy(sizePolicy3);
    btnMenu->setMinimumSize(QSize(30, 0));
    btnMenu->setMaximumSize(QSize(30, 16777215));
    btnMenu->setFocusPolicy(Qt::NoFocus);
    btnMenu->setPopupMode(QToolButton::InstantPopup);

    horizontalLayout->addWidget(btnMenu);

    btnMenu_Min = new QPushButton(widget_menu);
    btnMenu_Min->setObjectName(QString::fromUtf8("btnMenu_Min"));
    QSizePolicy sizePolicy4(QSizePolicy::Minimum, QSizePolicy::Expanding);
    sizePolicy4.setHorizontalStretch(0);
    sizePolicy4.setVerticalStretch(0);
    sizePolicy4.setHeightForWidth(btnMenu_Min->sizePolicy().hasHeightForWidth());
    btnMenu_Min->setSizePolicy(sizePolicy4);
    btnMenu_Min->setMinimumSize(QSize(30, 0));
    btnMenu_Min->setMaximumSize(QSize(30, 16777215));
    btnMenu_Min->setCursor(QCursor(Qt::ArrowCursor));
    btnMenu_Min->setFocusPolicy(Qt::NoFocus);

    horizontalLayout->addWidget(btnMenu_Min);

    btnMenu_Max = new QPushButton(widget_menu);
    btnMenu_Max->setObjectName(QString::fromUtf8("btnMenu_Max"));
    sizePolicy3.setHeightForWidth(btnMenu_Max->sizePolicy().hasHeightForWidth());
    btnMenu_Max->setSizePolicy(sizePolicy3);
    btnMenu_Max->setMinimumSize(QSize(30, 0));
    btnMenu_Max->setMaximumSize(QSize(30, 16777215));
    btnMenu_Max->setCursor(QCursor(Qt::ArrowCursor));
    btnMenu_Max->setFocusPolicy(Qt::NoFocus);

    horizontalLayout->addWidget(btnMenu_Max);

    btnMenu_Close = new QPushButton(widget_menu);
    btnMenu_Close->setObjectName(QString::fromUtf8("btnMenu_Close"));
    sizePolicy3.setHeightForWidth(btnMenu_Close->sizePolicy().hasHeightForWidth());
    btnMenu_Close->setSizePolicy(sizePolicy3);
    btnMenu_Close->setMinimumSize(QSize(30, 0));
    btnMenu_Close->setMaximumSize(QSize(30, 16777215));
    btnMenu_Close->setCursor(QCursor(Qt::ArrowCursor));
    btnMenu_Close->setFocusPolicy(Qt::NoFocus);

    horizontalLayout->addWidget(btnMenu_Close);
    horizontalLayout4->addWidget(widget_menu);
    verticalLayout2->addWidget(widget_title);

    widget = new QWidget(widgetMain);
    widget->setObjectName(QString::fromUtf8("widget"));
    verticalLayout3 = new QVBoxLayout(widget);
    verticalLayout3->setSpacing(0);
    verticalLayout3->setContentsMargins(11, 11, 11, 11);
    verticalLayout3->setObjectName(QString::fromUtf8("verticalLayout3"));
    verticalLayout3->setContentsMargins(0, 0, 0, 0);

    verticalLayout2->addWidget(widget);
    verticalLayout1->addWidget(widgetMain);

    connect(this->btnMenu_Min, SIGNAL(clicked(bool)), this, SLOT(on_btnMenu_Min_clicked()));
    connect(this->btnMenu_Max, SIGNAL(clicked(bool)), this, SLOT(on_btnMenu_Max_clicked()));
    connect(this->btnMenu_Close, SIGNAL(clicked(bool)), this, SLOT(on_btnMenu_Close_clicked()));
}

void QUIWidget::initForm()
{
    //设置图形字体
    setIcon(QUIWidget::Lab_Ico, QChar(0xf099), 11); //设置左上角图标-图形字体
    setIcon(QUIWidget::BtnMenu, 0xf0d7);
    setIcon(QUIWidget::BtnMenu_Min, 0xf068);
    setIcon(QUIWidget::BtnMenu_Max, 0xf067);
    setIcon(QUIWidget::BtnMenu_Close, 0xf00d);

    //设置标题及对齐方式
    setTitle("QUI Demo");
    setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    setVisible(QUIWidget::BtnMenu, false);

    mainWidget = 0;
    max = false;
    location = this->geometry();
    this->setProperty("form", true);
    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);//第一个参数是设置无边框。第二个参数是允许任务栏按钮右键菜单,第三个参数是允许最小化最大化与还原
    this->setWindowFlags(Qt::FramelessWindowHint);//任务栏单击图标后最小化后图标会消失,无法解决,因此不让最小化

    //绑定事件过滤器监听鼠标移动
    this->installEventFilter(this);
    this->widget_title->installEventFilter(this);

    //添加换肤菜单
    QStringList name;
    name << "银色" << "蓝色" << "浅蓝色" << "深蓝色" << "灰色" << "浅灰色" << "深灰色" << "黑色"
         << "浅黑色" << "深黑色" << "PS黑色" << "黑色扁平" << "白色扁平" << "浅紫色" << "橙色";
    foreach (QString str, name) {
        QAction *action = new QAction(str, this);
        this->btnMenu->addAction(action);
        connect(action, SIGNAL(triggered(bool)), this, SLOT(changeStyle()));
    }
}

2.功能函数

具体设置部件图标、设置部件图片、设置部件是否可见、设置标题栏高度、设置按钮统一宽度、设置标题及文本样式等等设置,代码如下。

void QUIWidget::setIcon(QUIWidget::Widget widget, QChar str, quint32 size)
{
    if (widget == QUIWidget::Lab_Ico) {
        IconHelper::Instance()->setIcon(this->lab_Ico, str, size);
    } else if (widget == QUIWidget::BtnMenu) {
        IconHelper::Instance()->setIcon(this->btnMenu, str, size);
    } else if (widget == QUIWidget::BtnMenu_Min) {
        IconHelper::Instance()->setIcon(this->btnMenu_Min, str, size);
    } else if (widget == QUIWidget::BtnMenu_Max) {
        IconHelper::Instance()->setIcon(this->btnMenu_Max, str, size);
    } else if (widget == QUIWidget::BtnMenu_Close) {
        IconHelper::Instance()->setIcon(this->btnMenu_Close, str, size);
    }
}

void QUIWidget::setPixmap(QUIWidget::Widget widget, const QString &file, const QSize &size)
{
    QPixmap pix = QPixmap(file);
    //按照宽高比自动缩放
    pix = pix.scaled(size, Qt::KeepAspectRatio);
    if (widget == QUIWidget::Lab_Ico) {
        this->lab_Ico->setPixmap(pix);
    } else if (widget == QUIWidget::BtnMenu) {
        this->btnMenu->setIcon(QIcon(file));
    } else if (widget == QUIWidget::BtnMenu_Min) {
        this->btnMenu_Min->setIcon(QIcon(file));
    } else if (widget == QUIWidget::BtnMenu_Max) {
        this->btnMenu_Max->setIcon(QIcon(file));
    } else if (widget == QUIWidget::BtnMenu_Close) {
        this->btnMenu_Close->setIcon(QIcon(file));
    }
}

void QUIWidget::setVisible(QUIWidget::Widget widget, bool visible)
{
    if (widget == QUIWidget::Lab_Ico) {
        this->lab_Ico->setVisible(visible);
    } else if (widget == QUIWidget::BtnMenu) {
        this->btnMenu->setVisible(visible);
    } else if (widget == QUIWidget::BtnMenu_Min) {
        this->btnMenu_Min->setVisible(visible);
    } else if (widget == QUIWidget::BtnMenu_Max) {
        this->btnMenu_Max->setVisible(visible);
    } else if (widget == QUIWidget::BtnMenu_Close) {
        this->btnMenu_Close->setVisible(visible);
    }
}

void QUIWidget::setOnlyCloseBtn()
{
    this->btnMenu->setVisible(false);
    this->btnMenu_Min->setVisible(false);
    this->btnMenu_Max->setVisible(false);
}

void QUIWidget::setTitleHeight(int height)
{
    this->widget_title->setFixedHeight(height);
}

void QUIWidget::setBtnWidth(int width)
{
    this->lab_Ico->setFixedWidth(width);
    this->btnMenu->setFixedWidth(width);
    this->btnMenu_Min->setFixedWidth(width);
    this->btnMenu_Max->setFixedWidth(width);
    this->btnMenu_Close->setFixedWidth(width);
}

void QUIWidget::setTitle(const QString &title)
{
    if (this->title != title) {
        this->title = title;
        this->lab_Title->setText(title);
        this->setWindowTitle(this->lab_Title->text());
    }
}

void QUIWidget::setAlignment(Qt::Alignment alignment)
{
    if (this->alignment != alignment) {
        this->alignment = alignment;
        this->lab_Title->setAlignment(alignment);
    }
}

void QUIWidget::on_btnMenu_Min_clicked()
{
    this->showMinimized();
}

void QUIWidget::on_btnMenu_Max_clicked()
{
    if (max) {
        this->setGeometry(location);
    } else {
        location = this->geometry();
        this->setGeometry(qApp->desktop()->availableGeometry());
    }
    max = !max;
}

void QUIWidget::on_btnMenu_Close_clicked()
{
    close();
}

3.窗口关联

打开主函数文件,在Main函数上将主窗口(用户)链接到标题栏窗口上,关联起来,代码如下。

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //定义用户窗口
    MainWindow *w = new MainWindow;
    //定义标题栏
    QUIWidget qui;
    //将主窗体链接/关联到标题栏窗口上
    qui.setMainWidget(w);
    qui.show();
    return a.exec();
}
void QUIWidget::setMainWidget(QWidget *mainWidget)
{
    //一个QUI窗体对象只能设置一个主窗体
    if (this->mainWidget == 0) {
        //将子窗体添加到布局
        this->widget->layout()->addWidget(mainWidget);
        //自动设置大小
        resize(mainWidget->width(), mainWidget->height() + this->widget_title->height());
        this->mainWidget = mainWidget;
        this->mainWidget->installEventFilter(this);
    }
}

4.使用标题栏类

因为在Main函数上,已经将主窗体链接/关联到标题栏窗口上,因此在用户层无需关注/设置标题栏相关参数。这里和方式一不一样的是,方式是将标题栏类作为主窗口的私有变量使用,而方式二只是将两个窗口界面关联起来而已。

至此方式二讲解完毕,该种方式有个缺点是需要手鲁UI设计代码。更快捷的是,通过可视化界面UI来设计标题栏,然后绑定/链接到主窗口界面上,跟方式一一样。

三、方式三

方式三的实现方式不同于上述两种(需要创建具体标题栏类),而这种方式三是不需要的,只需要在原项目上的主窗口UI上,绘制一个标题栏,然后影藏主标题栏,显示绘制的标题栏,即可。具体实现示例见文末链接处,下面介绍下实现思路。

1.实现方式

打开原有项目的可视化UI设计文件,进行如下设计。

在重新绘制的标题栏上面有原项目保留的菜单栏,在程序构造函数将其隐藏即可,另将其关联到新建的菜单栏上,避免再绘制,具体代码如下。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setWindowTitle("我的窗口");
    /*** 隐藏原有的工具栏和菜单栏 ***/
    ui->toolBar->hide();
    ui->menubar->hide();
    setBtnHeight(26);
    InitChart();
    /*** 注册事件过滤器 ***/
    ui->widget->installEventFilter(this);
    ui->tab->installEventFilter(this);
    ui->tab_2->installEventFilter(this);
    // 注册只点击标题栏移动事件过滤器
    ui->horizontalWidget->installEventFilter(this);
    /*** 创建右键菜单 ***/
    CreateMenu(ui->widget);
    CreateMenu(ui->tab);
    CreateMenu(ui->tab_2);
    // 添加换肤菜单
    QStringList name;
    name << "浅蓝色" << "浅青色" << "浅灰色" << "浅灰色" << "浅红色" << "浅紫色" << "浅橙色";
    foreach (QString str, name) {
        QAction *action = new QAction(str, this);
        ui->toolButton->addAction(action);
        connect(action, SIGNAL(triggered(bool)), this, SLOT(onButtonchangeStyle()));
    }
    // 关联/添加到新的菜单栏上
    menubar = new QMenuBar(ui->horizontalWidget_2);
    menubar->setObjectName(QString::fromUtf8("menubar"));
    menubar->setGeometry(QRect(0, 0, 785, 23));
    menubar->addAction(ui->menu->menuAction());
    menubar->addAction(ui->menu_2->menuAction());
    menubar->addAction(ui->menu_3->menuAction());
}
void MainWindow::setBtnHeight(int Height)
{
    ui->label->setFixedHeight(Height);
    ui->label_2->setFixedHeight(Height);
    ui->toolButton->setFixedHeight(Height);
    ui->min->setFixedHeight(Height);
    ui->max->setFixedHeight(Height);
    ui->close->setFixedHeight(Height);
}
// 以下为按钮操作响应的槽
void MainWindow::onButtonchangeStyle()
{
    QAction *act = (QAction *)sender();
    QString name = act->text();
    if (name == "浅蓝色")
        setStyleSheet("background-color: rgb(193,210,240)");
    else if (name == "浅青色")
        setStyleSheet("background-color: rgb(173, 255, 196)");
    else if (name == "浅灰色")
        setStyleSheet("background-color: rgb(211, 211, 211)");
    else if (name == "浅灰色")
        setStyleSheet("background-color: rgb(192, 192, 192)");
    else if (name == "浅红色")
        setStyleSheet("background-color: rgb(255, 182, 193)");
    else if (name == "浅紫色")
        setStyleSheet("background-color: rgb(171, 145, 204)");
    else if (name == "浅橙色")
        setStyleSheet("background-color: rgb(254, 216, 177)");
}

以上完成重新标题栏的绘制和菜单栏的关联,但是窗口无法移动,下面在通过鼠标使窗口移动,实现如下。

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

以上代码实现功能是点击窗口任意地方,整个窗口移动,若只需要点击标题栏使整个窗口移动,则需要将上述代码屏蔽,添加如下代码实现。

protected:
    //void mousePressEvent(QMouseEvent *event) override;
    //void mouseMoveEvent(QMouseEvent *event) override;

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if(watched == ui->widget) {
        if(event->type() == QEvent::MouseButtonPress)
            menu_widget->exec(cursor().pos());  //菜单显示的位置跟随鼠标
    }
    /*** 点击标题栏移动 ***/
    else if (watched == ui->horizontalWidget) {
         QMouseEvent *pMouseEvent = (QMouseEvent*)event;
        if(pMouseEvent->button() == Qt::LeftButton)
            whereismouse = pMouseEvent->pos();
        if(pMouseEvent->buttons() == Qt::LeftButton)
        {
            //当窗口最大化或最小化时也不进行触发
            if(MainWindow::isMaximized() || MainWindow::isMinimized())
                return 0;
            else {
                //当在按钮之类需要鼠标操作的地方不进行触发(防误触)
                if (ui->close->underMouse()||ui->max->underMouse()||ui->min->underMouse()) {
                }
                else {
                    MainWindow::move(MainWindow::mapToGlobal(pMouseEvent->pos()-whereismouse));//移动
                }
            }
        }
        event->accept();
    }
    return QObject::eventFilter(watched, event);
}

2.效果演示

编译运行完效果如下。


总结

方式一:实现方式是在原项目上新建一个带UI的设计类,在新建UI上完成标题栏的绘制,然后将该类设置为原主窗口的私有变量;
方式二:实现方式是在原项目上新建一个不带UI的C++类,然后通过手鲁代码编写标题栏,然后在Main函数上将主窗口和标题栏窗口链接/关联起来;
方式三:实现方式是在原项目上的主窗口UI上,绘制一个标题栏,然后影藏主标题栏,显示绘制的标题栏;

博文中相应的工程代码Qt-Case.zip 利用Qt开发软件进行编的例程,为博文提供案例-CSDN文库。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/939723.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鱼跃医疗获评2024年国家级“绿色工厂”,以绿色制造树立行业标杆

近日&#xff0c;工业和信息化部公布了2024年度绿色制造名单&#xff0c;鱼跃医疗凭借在绿色制造和可持续发展方面的卓越表现&#xff0c;成功入选并获评国家级“绿色工厂”。 “绿色工厂”是工信部为贯彻落实国家《工业绿色发展规划》&#xff0c;加快推动绿色制造体系建设&a…

【数据集】玻璃门窗缺陷检测数据集3085张5类YIOLO+VOC格式

数据集格式&#xff1a;VOC格式YOLO格式 压缩包内含&#xff1a;3个文件夹&#xff0c;分别存储图片、xml、txt文件 JPEGImages文件夹中jpg图片总计&#xff1a;3085 Annotations文件夹中xml文件总计&#xff1a;3085 labels文件夹中txt文件总计&#xff1a;3085 标签种类数&am…

一、LRU缓存

LRU缓存 1.LRU缓存介绍2.LRU缓存实现3.LRU缓存总结3.1 LRU 缓存的应用3.2 LRU 缓存的优缺点 1.LRU缓存介绍 LRU是Least Recently Used 的缩写&#xff0c;意为“最近最少使用”。它是一种常见的缓存淘汰策略&#xff0c;用于在缓存容量有限时&#xff0c;决定哪些数据需要被删…

【视频生成模型】——Hunyuan-video 论文及代码讲解和实操

&#x1f52e;混元文生视频官网 | &#x1f31f;Github代码仓库 | &#x1f3ac; Demo 体验 | &#x1f4dd;技术报告 | &#x1f60d;Hugging Face 文章目录 论文详解基础介绍数据预处理 &#xff08;Data Pre-processing&#xff09;数据过滤 (Data Filtering)数据标注 (Data…

【C++】函数计算题解论

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;思路解析3.1 函数的递归定义3.2 边界条件控制3.3 记忆化搜索 &#x1f4af;C实现代码&#x1f4af;添加解释&#x1f4af;小结 &#x1f4af;前言 在…

低温高海拔大载重无人机吊运技术详解

低温高海拔大载重无人机吊运技术是一项复杂而先进的技术&#xff0c;它结合了无人机的飞行控制、吊装系统的操作以及特殊环境下的适应性等多个方面。以下是对该技术的详细解析&#xff1a; 一、无人机基础知识与结构特点 低温高海拔大载重无人机通常采用旋翼设计&#xff0c;…

Java设计模式 —— 【结构型模式】适配器模式(类的适配器、对象适配器、接口适配器)详解

文章目录 基本介绍一、类的适配器二、对象适配器三、接口适配器总结 基本介绍 生活中有很多例子&#xff1a; 不同国家的插座接口不同&#xff0c;需要转换器&#xff1b;家用电源220V&#xff0c;手机只接受5V充电&#xff0c;需要转换器&#xff1b;读卡器&#xff0c;拓展…

系列2:基于Centos-8.6Kubernetes 集成GPU资源信息

每日禅语 自省&#xff0c;就是自我反省、自我检查&#xff0c;自知己短&#xff0c;从而弥补短处、纠正过失。佛陀强调自觉觉他&#xff0c;强调以达到觉行圆满为修行的最高境界。要改正错误&#xff0c;除了虚心接受他人意见之外&#xff0c;还要不忘时时观照己身。自省自悟之…

leetcode17:电话号码的字母组合

给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits "23" 输出&#…

OpenHarmony-3.HDF Display子系统(6)

Display 子系统 1.Display驱动模型介绍 当前操作系统和 SOC 种类繁多&#xff0c;各厂商的显示屏器件也各有不同&#xff0c;随之针对器件的驱动代码也不尽相同&#xff0c;往往是某一款器件驱动&#xff0c;只适用于某单一内核系统或 SOC&#xff0c;如果要迁移到其他内核或者…

AQS源码学习

一、park/unpark阻塞唤醒线程 LockSupport是JDK中用来实现线程阻塞和唤醒的工具。使用它可以在任何场合使线程阻塞&#xff0c;可以指定任何线程进行唤醒&#xff0c;并且不用担心阻塞和唤醒操作的顺序&#xff0c;但要注意连续多次唤醒的效果和一次唤醒是一样的。JDK并发包下…

GUI07-学工具栏,懂MVC

MVC模式&#xff0c;是天底下编写GUI程序最为经典、实效的一种软件架构模式。当一个人学完菜单栏、开始学习工具栏时&#xff0c;就是他的一生中&#xff0c;最适合开始认识 MVC 模式的好时机之一。这节将安排您学习&#xff1a; Model-View-Controller 模式如何创建工具栏以及…

C++----类与对象(中篇)

引言 以C语言栈的实现为例&#xff0c;在实际开发中&#xff0c;我们可能会遇到以下两个问题&#xff1a; 1.初始化和销毁管理不当&#xff1a;C语言中的栈实现通常需要手动管理内存&#xff08;如使用malloc和free&#xff09;&#xff0c;这导致初始化和销毁栈时容易出错或…

linux打包qt程序

Linux下Qt程序打包_linuxdeployqt下载-CSDN博客 Linux/Ubuntu arm64下使用linuxdeployqt打包Qt程序_linuxdeployqt arm-CSDN博客 本篇文章的系统环境是 : 虚拟机ubuntu18.04 用下面这个qmake路径 进行编译 在 ~/.bashrc 文件末尾&#xff0c;qmake目录配置到文件末尾 将上图中…

气象与旅游之间的关系,如果借助高精度预测提高旅游的质量

气象与旅游之间存在密切的关系,天气条件直接影响旅游者的出行决策、旅游体验和安全保障。通过高精度气象预测技术,可以有效提升旅游质量,为游客和旅游行业带来显著的优势。 1. 提高游客出行决策效率 个性化天气服务:基于高精度气象预测,旅游平台可以提供个性化的天气预报服…

华为OD --- 靠谱的车

华为OD --- 靠谱的车 题目OJ用例独立实现思路源码 参考实现思路源码实现 题目 OJ用例 测试用例case 独立实现 思路 独立实现的思路比较简单,直接建一个长度为N的数组,然后找出index中不包含4的项数即可 源码 const rl require("readline").createInterface({ …

可视化平台FineReport的安装及简单使用

1. FineReport产品 FineReport介绍 FineReport报表软件是一款纯Java编写的、集数据展示(报表)和数据录入(表单)功能于一身的企业级web报表工具&#xff0c;它专业、简捷、灵活的特点和无码理念&#xff0c;仅需简单的拖拽操作便可以设计复杂的中国式报表&#xff0c;搭建数据决…

OkHttp源码分析:分发器任务调配,拦截器责任链设计,连接池socket复用

目录 一&#xff0c;分发器和拦截器 二&#xff0c;分发器处理异步请求 1.分发器处理入口 2.分发器工作流程 3.分发器中的线程池设计 三&#xff0c;分发器处理同步请求 四&#xff0c;拦截器处理请求 1.责任链设计模式 2.拦截器工作原理 3.OkHttp五大拦截器 一&#…

Nginx主要知识点总结

1下载nginx 到nginx官网nginx: download下载nginx&#xff0c;然后解压压缩包 然后双击nginx.exe就可以启动nginx 2启动nginx 然后在浏览器的网址处输入localhost&#xff0c;进入如下页面说明nginx启动成功 3了解nginx的配置文件 4熟悉nginx的基本配置和常用操作 Nginx 常…

概率论得学习和整理27:关于离散的数组 随机变量数组的均值,方差的求法3种公式,思考和细节。

目录 1 例子1&#xff1a;最典型的&#xff0c;最简单的数组的均值&#xff0c;方差的求法 2 例子1的问题&#xff1a;例子1只是1个特例&#xff0c;而不是普遍情况。 2.1 例子1各种默认假设&#xff0c;导致了求均值和方差的特殊性&#xff0c;特别简单。 2.2 我觉得 加权…