当前位置: 首页 > news >正文

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_NAMESPACEclass 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_OBJECTQ_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 csdsetTitle("**软件");
#elsesetTitle("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));//默认样式风格bluesetStyle(":/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文库。

相关文章:

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

Qt开发 系列文章 - user-defined-titlebars&#xff08;十&#xff09; 目录 前言 一、方式一 1.效果演示 2.创建标题栏类 3.可视化UI设计 4.定义相关函数 5.使用标题栏类 二、方式二 1.效果演示 2.创建标题栏类 3.定义相关函数 1.初始化函数 2.功能函数 3.窗口关…...

Verilog中initial的用法

在 Verilog 语言中&#xff0c;initial 语句用于在仿真开始时执行一次性初始化操作。它是顺序执行的&#xff0c;用来描述在仿真启动时立即运行的代码块&#xff0c;通常用于赋初值、生成波形或控制信号行为。 语法 initial begin // 语句1 // 语句2 ... end特点 只…...

(14)D-FINE网络,爆锤yolo系列

yolo过时了&#xff1f;传统的yolo算法在小目标检测方面总是不行&#xff0c;最新算法DEIM爆锤yolo&#xff0c;已经替yolo解决。 一、创新点 ​ 这个算法名为DEIM&#xff0c;全称是DETR with Improved Matching for Fast Convergence&#xff0c;其主要创新点在于提出了一…...

Python :冬至快乐

第1部分&#xff1a;基础设置 首先创建一个新的 Python 文件&#xff0c;命名为 fireworks.py。 步骤 1.1: 导入必要的库 import pygame import random import sys from pygame.locals import * import math import time这些库的作用&#xff1a; pygame: 用于创建游戏和图…...

重拾设计模式--状态模式

文章目录 状态模式&#xff08;State Pattern&#xff09;概述状态模式UML图作用&#xff1a;状态模式的结构环境&#xff08;Context&#xff09;类&#xff1a;抽象状态&#xff08;State&#xff09;类&#xff1a;具体状态&#xff08;Concrete State&#xff09;类&#x…...

稀疏矩阵的存储与计算 gaxpy

1, gaxpy 数学公式 其中&#xff1a; &#xff0c; &#xff0c; 2, 具体实例 3&#xff0c;用稠密矩阵的方法 本节将用于验证第4节中的稀疏计算的结果 hello_gaxpy_dense.cpp #include <stdio.h> #include <stdlib.h>struct Matrix_SP {float* val; //…...

基于LabVIEW的USRP信道测量开发

随着无线通信技术的不断发展&#xff0c;基于软件无线电的设备&#xff08;如USRP&#xff09;在信道测量、无线通信测试等领域扮演着重要角色。通过LabVIEW与USRP的结合&#xff0c;开发者可以实现信号生成、接收及信道估计等功能。尽管LabVIEW提供了丰富的信号处理工具和图形…...

基于LSTM长短期记忆神经网络的多分类预测【MATLAB】

在深度学习中&#xff0c;长短期记忆网络&#xff08;LSTM, Long Short-Term Memory&#xff09;是一种强大的循环神经网络&#xff08;RNN&#xff09;变体&#xff0c;专门为解决序列数据中的长距离依赖问题而设计。LSTM因其强大的记忆能力&#xff0c;广泛应用于自然语言处理…...

物联网:全面概述、架构、应用、仿真工具、挑战和未来方向

中文论文标题&#xff1a;物联网&#xff1a;全面概述、架构、应用、仿真工具、挑战和未来方向 英文论文标题&#xff1a;Internet of Things: a comprehensive overview, architectures, applications, simulation tools, challenges and future directions 作者信息&#x…...

volatility2工具的使用vol2工具篇

vol2工具 命令格式&#xff1a;vol.py -f [image] --profile[profile] [plugin] 1、查看系统的操作版本&#xff0c;系统镜像信息 2.查看用户名密码信息&#xff0c;当前操作系统中的password hash&#xff0c;例如SAM文件内容 3.从注册表提取LSA密钥信息&#xff08;已解密&…...

R 基础运算

R 基础运算 R 是一种广泛使用的统计编程语言&#xff0c;它提供了强大的数据操作和分析功能。基础运算在 R 中非常重要&#xff0c;因为它们是进行更复杂计算和数据分析的基础。本文将详细介绍 R 中的基础运算&#xff0c;包括算术运算、逻辑运算、向量化和矩阵运算。 一、算…...

javaScriptBOM

1.1、BOM概述 1.1.1、BOM简介 BOM&#xff08;browser Object&#xff09;即浏览器对象模型&#xff0c;它提供了独立于内容而与浏览器窗口进行交互的对象&#xff0c;其核心对象是window。 BOM由一系列的对象构成&#xff0c;并且每个对象都提供了很多方法与属性 BOM缺乏标准…...

Godot RPG 游戏开发指南

Godot RPG 游戏开发指南 一、基础准备 1. 开发环境 下载并安装最新版 Godot 4.x选择使用 GDScript 或 C# 作为开发语言准备基础美术资源&#xff08;角色、地图、道具等&#xff09; 2. 项目结构 project/ ├── scenes/ # 场景文件 ├── scripts/ # 脚…...

目标检测数据集图片及标签同步旋转角度

前言 在深度学习领域&#xff0c;尤其是目标检测任务中&#xff0c;数据集的质量直接影响模型的性能。为了提升模型的鲁棒性和对各种场景的适应能力&#xff0c;数据增强技术被广泛应用于图像数据集处理。旋转角度是常见的数据增强方法&#xff0c;通过对图像及其对应的标签&am…...

2025前端面试热门题目——计算机网络篇

计算机网络篇——面试 1. 到底什么是 TCP 连接? TCP 连接的定义 TCP&#xff08;传输控制协议&#xff09;是一个面向连接的传输层协议。TCP 连接是通过 三次握手 确立的可靠数据通信链路&#xff0c;保证了在不可靠网络&#xff08;如互联网&#xff09;上的数据传输的准确…...

LEAST-TO-MOST PROMPTING ENABLES COMPLEX REASONING IN LARGE LANGUAGE MODELS---正文

题目 最少到最多的提示使大型语言模型能够进行复杂的推理 论文地址&#xff1a;https://arxiv.org/abs/2205.10625 摘要 思路链提示在各种自然语言推理任务中表现出色。然而&#xff0c;它在需要解决比提示中显示的示例更难的问题的任务上表现不佳。为了克服这种由易到难的概括…...

Java开发经验——日志治理经验

摘要 本文主要介绍了Java开发中的日志治理经验&#xff0c;包括系统异常日志、接口摘要日志、详细日志和业务摘要日志的定义和目的&#xff0c;以及错误码规范和异常处理规范。强调了日志治理的重要性和如何通过规范化错误码和日志格式来提高系统可观测性和问题排查效率。 1. …...

使用复数类在C#中轻松绘制曼德布洛集分形

示例在 C# 中绘制曼德布洛特集分形解释了如何通过迭代以下方程来绘制曼德布洛特集&#xff1a; 其中 Z(n) 和 C 是复数。程序迭代此方程&#xff0c;直到 Z(n) 的大小至少为 2 或程序执行最大迭代次数。 该示例在单独的变量中跟踪数字的实部和虚部。此示例使用Complex类来更轻松…...

VSCode 启用免费 Copilot

升级VSCode到 1.96版本&#xff0c;就可以使用每个月2000次免费额度了&#xff0c;按照工作日每天近80次免费额度&#xff0c;满足基本需求。前两天一直比较繁忙&#xff0c;今天周六有时间正好体验一下。 引导插件安装GitHub Copilot - Visual Studio Marketplace Extension f…...

常见问题整理

DevOps 和 CICD DevOps 全称Development & Operation 一种实现开发和运维一体化的协同模式&#xff0c;提供快速交付应用和服务的能力 用于协作&#xff1a;开发&#xff0c;部署&#xff0c;质量测试 整体生命周期工作内容&#xff0c;最终实现持续继承&#xff0c;持续部…...

使用Vue创建前后端分离项目的过程(前端部分)

前端使用Vue.js作为前端开发框架&#xff0c;使用Vue CLI3脚手架搭建项目&#xff0c;使用axios作为HTTP库与后端API交互&#xff0c;使用Vue-router实现前端路由的定义、跳转以及参数的传递等&#xff0c;使用vuex进行数据状态管理&#xff0c;后端使用Node.jsexpress&#xf…...

【Springboot知识】Redis基础-springboot集成redis相关配置

文章目录 1. 添加依赖2. 配置Redis连接3. 配置RedisTemplate&#xff08;可选&#xff09;4. 使用RedisTemplate或StringRedisTemplate5. 测试和验证 集群配置在application.properties中配置在application.yml中配置 主从配置1. 配置Redis服务器使用配置文件使用命令行 2. 配置…...

网络安全概论——身份认证

一、身份证明 身份证明可分为以下两大类 身份验证——“你是否是你所声称的你&#xff1f;”身份识别——“我是否知道你是谁&#xff1f;” 身份证明系统设计的三要素&#xff1a; 安全设备的系统强度用户的可接受性系统的成本 实现身份证明的基本途径 所知&#xff1a;个…...

OpenHarmony-4.HDI 框架

HDI 框架 1.HDI介绍 HDI&#xff08;Hardware Device Interface&#xff0c;硬件设备接口&#xff09;是HDF驱动框架为开发者提供的硬件规范化描述性接口&#xff0c;位于基础系统服务层和设备驱动层之间&#xff0c;是连通驱动程序和系统服务进行数据流通的桥梁&#xff0c;是…...

leecode494.目标和

这道题目第一眼感觉就不像是动态规划&#xff0c;可以看出来是回溯问题&#xff0c;但是暴力回溯超时&#xff0c;想要用动态规划得进行一点数学转换 class Solution { public:int findTargetSumWays(vector<int>& nums, int target) {int nnums.size(),bagWeight0,s…...

在Spring中application 的配置属性(详细)

application 的配置属性。 这些属性是否生效取决于对应的组件是否声明为 Spring 应用程序上下文里的 Bean &#xff08;基本是自动配置 的&#xff09;&#xff0c;为一个不生效的组件设置属性是没有用的。 multipart multipart.enabled 开启上传支持&#xff08;默认&a…...

jvm符号引用和直接引用

在解析阶段中,符号引用和直接引用是Java类加载和内存管理中的重要概念,它们之间存在显著的区别。以下是对这两个概念的详细解析: 一、定义与特性 符号引用(Symbolic Reference) 定义:符号引用是编译器生成的用于表示类、方法、字段等的引用方式。特性: 独立性:符号引用…...

一文流:JVM精讲(多图提醒⚠️)

一文流系列是作者苦于技术知识学了-忘了,背了-忘了的苦恼,决心把技术知识的要点一笔笔✍️出来,一图图画出来,一句句讲出来,以求刻在🧠里。 该系列文章会把核心要点提炼出来,以求掌握精髓,至于其他细节,写在文章里,留待后续回忆。 目前进度请查看: :::info https:/…...

python 分段拟合笔记

效果图: 源代码: import numpy as np import cv2 import matplotlib.pyplot as plt from numpy.polynomial.polynomial import Polynomialdef nihe(x_points,y_points,p_id):# 按照 p_id 将 points 分成两组group_0_x = []group_0_y = []group_1_x = []group_1_y = []for i, …...

Mysql索引类型总结

按照数据结构维度划分&#xff1a; BTree 索引&#xff1a;MySQL 里默认和最常用的索引类型。只有叶子节点存储 value&#xff0c;非叶子节点只有指针和 key。存储引擎 MyISAM 和 InnoDB 实现 BTree 索引都是使用 BTree&#xff0c;但二者实现方式不一样&#xff08;前面已经介…...