当前位置: 首页 > 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.窗口关…...

设计模式之创建型

1、What 关注对象的创建过程&#xff0c;旨在通过不同的方式来创建对象&#xff0c;以解耦对象的创建与其使用过程。这些模式提供了创建对象的灵活性和可扩展性&#xff0c;使得代码更加易于维护和管理。 1.1 单例模式 确保一个类只有一个实例&#xff0c;并提供一个全局访问…...

记录一下自己对网络安全法的笔记

仅记录一下自己对网络安全法的笔记 文章来源&#xff08;https://www.cac.gov.cn/2016-11/07/c_1119867116_2.htm&#xff09;&#xff08;2016年11月7日第十二届全国人民代表大会常务委员会第二十四次会议通过&#xff09;该法自2017年6月1日起施行。《网络安全法》是我国第一…...

Mybatis-plus-Join--分页查询

数据表四张&#xff1a; user&#xff1a; id,username,create_time,update_time product&#xff1a; id,name,price,number(库存),create_time,update_times order&#xff1a; id,quantity,order_time(下单时间),update_time order_detail:id,product_id,order_id,quant…...

EE308FZ_Sixth Assignment_Beta Sprint_Sprint Essay 5

Assignment 6Beta SprintCourseEE308FZ[A] — Software EngineeringClass Link2401_MU_SE_FZURequirementsTeamwork—Beta SprintTeam NameFZUGOObjectiveSprint Essay 5_Day9-Day10 (12.19-12.20)Other Reference1. WeChat Mini Program Design Guide 2. Javascript Style Gui…...

【AI日记】24.12.19 kaggle 比赛 2-8 | 睡眠质量提高

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 工作 参加&#xff1a;kaggle 比赛 Regression with an Insurance Dataset时间&#xff1a;8 小时 读书 书名&#xff1a;富兰克林自传时间&#xff1a;0.5 小时阅读原因&#xff1a;100 美元纸币上的人物 …...

string

1.对象创建 // // Created by 徐昌真 on 2024/12/15. // #include <iostream> #include <string>using namespace std;int main() {string s "意思是不要沉迷于空洞的幻想 也不要追求无用的虚名 强调了做事要脚踏实地 专注于实际的目标与行动";// 1. 无…...

观龙鱼之态,察疾病之征

龙鱼&#xff0c;以其独特的外形、优雅的游姿&#xff0c;成为众多养鱼爱好者的心头好。然而&#xff0c;这些水中的 “精灵” 一旦患病&#xff0c;其状态会发生明显变化。了解龙鱼患病的表现&#xff0c;对于鱼主人及时发现并治疗至关重要。 当龙鱼出现食欲不振的情况时&…...

【NLP 16、实践 ③ 找出特定字符在字符串中的位置】

看着父亲苍老的白发和渐渐老态的面容 希望时间再慢一些 —— 24.12.19 一、定义模型 1.初始化模型 ① 初始化父类 super(TorchModel, self).__init__()&#xff1a; 调用父类 nn.Module 的初始化方法&#xff0c;确保模型能够正确初始化。 ② 创建嵌入层 self.embedding n…...

一.photoshop导入到spine

这里使用的是 photoshoptospine脚本 下载地址:https://download.csdn.net/download/boyxgb/90156744 脚本的使用,可以通过文件的脚本的浏览,浏览该脚本使用该脚本,也可以将该脚本放在photoshop安装文件夹里的script文件夹下,具体路径:Photoshop\Presets\Scripts,重启photosho…...

docsify

macos ➜ ~ node -v v16.20.2➜ ~ npm --version 8.19.4全局安装 docsify-cli 工具 npm i docsify-cli -g➜ ~ docsify -vdocsify-cli version:4.4.4初始化项目 docsify init ./docsls -ah docs . .. .nojekyll README.md index.htmlindex.html 入口文件README.md 会…...

在Windows Server路由和远程访问服务中启用L2TP/IPsec VPN

背景 路由和远程访问服务&#xff08;Routing and Remote Access Services&#xff0c;RRAS&#xff09;是Windows Server上的一个角色&#xff0c;包含很多功能&#xff0c;可以用来搭建VPN。然而&#xff0c;在什么也不做的初始配置中&#xff0c;它只允许PPTP协议连接。然而…...

感知机收敛性定理证明

1. 问题描述 感知机收敛性定理假设&#xff1a; 存在一个参数向量 θ&#xff08;被归一化为单位向量&#xff0c;&#xff0c;以及一个正数 &#xff0c;使得对所有训练样本 满足&#xff1a; 这是线性可分的假设&#xff0c;意味着每个样本点与正确超平面之间有一个至少为的…...

监控易平台:提升IDC 数据中心运维效率与质量

一、引言 随着信息技术的飞速发展&#xff0c;IDC 数据中心作为信息存储、处理和传输的核心枢纽&#xff0c;其规模和复杂性不断增加。数据中心的稳定运行对于企业业务的连续性和发展至关重要&#xff0c;然而&#xff0c;传统的运维方式在面对日益增长的运维需求时&#xff0c…...

WordPress 资源展示型下载类主题 CeoMax-Pro_v7.6 开心版

WordPress 资源展示型下载类主题 CeoMax-Pro_v7.6 开心版&#xff1b; CeoMax-Pro是一款极致美观强大的WordPress付费资源下载主题&#xff0c;它能满足您所有付费资源下载的业务需求&#xff01; 你的想法与业务不能被主题所限制&#xff01;CeoMax-Pro强大的功能&#xff0…...

java数据类型(补充-引用类型)

Java还提供了引用数据类型&#xff08;Reference Types&#xff09;。这些类型的变量存储的是对象的引用&#xff0c;而不是直接存储值。引用数据类型主要包括以下几类&#xff1a; 类型描述类(Class)每个对象都有自己的状态&#xff08;属性或字段&#xff09;、行为&#xf…...

【WRF教程第四期】WRF 初始化概述:以4.5版本为例

WRF 初始化&#xff08;WRF Initialization&#xff09; Building Initialization Programs编译方式 理想案例初始化&#xff08;Initialization for Idealized Cases&#xff09;理想化案例的输入可用的理想化案例 现实案例初始化&#xff08;Initialization for Real Data Ca…...

「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台

本篇将带你实现一个虚拟音乐控制台。用户可以通过界面控制音乐的播放、暂停、切换歌曲&#xff0c;并查看当前播放的歌曲信息。页面还支持调整音量和动态显示播放进度&#xff0c;是音乐播放器界面开发的基础功能示例。 关键词 UI互动应用音乐控制播放控制动态展示状态管理按钮…...

Navicat 17 功能简介 | SQL 美化

SQL美化 本期&#xff0c;我们将深入挖掘 Navicat 的实用的SQL代码美化功能。你只需简单地点击“SQL 美化”按钮&#xff0c;即可轻松完成 SQL 的格式化。 随着 17 版本的发布&#xff0c;Navicat 也带来了众多的新特性&#xff0c;包括兼容更多数据库、全新的模型设计、可视化…...

C++ 只出现一次的数字 - 力扣(LeetCode)

点击链接即可查看题目&#xff1a;136. 只出现一次的数字 - 力扣&#xff08;LeetCode&#xff09; 一、题目 给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间…...

Unity3D仿星露谷物语开发5之角色单例模式

1、目的 使用单例模式创建角色对象&#xff0c;保证整个游戏中只有一个角色&#xff0c;并且让游戏对象具有全局可访问性。 2、流程 &#xff08;1&#xff09;创建SingletonMonobehaviour脚本 Assets下创建Scripts目录用于存放所有的脚本&#xff0c;再创建Misk子目录&…...

解析在OceanBase创建分区的常见问题|OceanBase 用户问题精粹

在《分区策略和管理分区计划的实践方案》这篇文章中&#xff0c;我们介绍了在ODC中制定分区策略及有效管理分区计划的经验。有不少用户在该帖下提出了使用中的问题&#xff0c;其中一个关于创建分区的限制条件的问题&#xff0c;也是很多用户遭遇的老问题。因此本文以其为切入&…...

python学习路径(一)

学习 Python 的完整大纲应该从基础知识到高级应用层层递进&#xff0c;并以构建自己的项目为目标&#xff0c;最终形成自己的知识体系。以下是一个完整、详细且逻辑清晰的学习路径&#xff1a; 第一部分&#xff1a;Python 基础 1. 环境配置与工具 Python 安装与版本管理&…...

【Nginx-5】Nginx 限流配置指南:保护你的服务器免受流量洪峰冲击

在现代互联网应用中&#xff0c;流量波动是常态。无论是突发的用户访问高峰&#xff0c;还是恶意攻击&#xff0c;都可能导致服务器资源耗尽&#xff0c;进而影响服务的可用性。为了应对这种情况&#xff0c;限流&#xff08;Rate Limiting&#xff09;成为了一种常见的保护措施…...

OpenCV(python)从入门到精通——运算操作

加法减法操作 import cv2 as cv import numpy as npx np.uint8([250]) y np.uint8([10])x_1 np.uint8([10]) y_1 np.uint8([20])# 加法,相加最大只能为255 print(cv.add(x,y))# 减法&#xff0c;相互减最小值只能为0 print(cv.subtract(x_1,y_1))图像加法 import cv2 as…...

MFC 自定义网格控件

一、什么是 Custom Control&#xff1f; Custom Control&#xff08;自定义控件&#xff09; 是 MFC&#xff08;Microsoft Foundation Classes&#xff09;框架中提供的一种控件类型&#xff0c;用于实现自定义的外观和功能。当标准控件&#xff08;例如 CEdit、CButton、CLi…...

什么是卷积?卷积的意义

卷积是一种在数学和信号处理中广泛应用的运算方法&#xff0c;它通常被用于描述两个函数之间的关系。在信号处理中&#xff0c;卷积可以将两个信号进行组合&#xff0c;以得到一个新的信号&#xff0c;该信号反映了这两个原始信号之间的关系。 具体来说&#xff0c;假设有两个…...

μC/OS-Ⅱ源码学习(7)---软件定时器

快速回顾 μC/OS-Ⅱ中的多任务 μC/OS-Ⅱ源码学习(1)---多任务系统的实现 μC/OS-Ⅱ源码学习(2)---多任务系统的实现(下) μC/OS-Ⅱ源码学习(3)---事件模型 μC/OS-Ⅱ源码学习(4)---信号量 μC/OS-Ⅱ源码学习(5)---消息队列 μC/OS-Ⅱ源码学习(6)---事件标志组 本文进一…...

3D和AR技术在电商行业的应用有哪些?

3D展示和AR技术在电商行业的应用为消费者带来了更为直观、沉浸式的购物体验&#xff0c;显著提升了商品展示效果和销售转化率。以下是3D和AR技术在电商行业的具体应用&#xff1a; 1、商品3D展示&#xff1a; 通过3D技术&#xff0c;商品可以在电商平台上以三维形式呈现&…...

数据增强的几大方式

1. 随机擦除(Random Erasing) 说明 随机在图像中选取一个矩形区域&#xff0c;将其像素值随机化或设为零&#xff0c;以增加模型对部分缺失信息的鲁棒性。 import numpy as np import cv2def random_erasing(image, sl0.02, sh0.2, r10.3):h, w, _ image.shapearea h * wta…...

GraphReader: 将长文本结构化为图,并让 agent 自主探索,结合的大模型长文本处理增强方法

GraphReader: 将长文本结构化为图&#xff0c;并让 agent 自主探索&#xff0c;结合的大模型长文本处理增强方法 论文大纲理解为什么大模型和知识图谱不够&#xff1f;还要多智能体 设计思路数据分析解法拆解全流程核心模式提问为什么传统的长文本处理方法会随着文本长度增加而…...

VTK 模型封闭 closeSurface 补洞, 网格封闭性检测

网格封闭性检测 见&#xff1a; vtk Edges 特征边 提取 网格封闭性检测_vtkfeatureedges-CSDN博客 由于以前做过3D打印模型&#xff0c;要求模型必须是封闭的&#xff0c;原来对模型封闭有研究过&#xff0c;不过没有记录&#xff1b;现在又遇到&#xff0c;整理一下&#xff…...

【译】仅有 Text2SQL 是不够的: 用 TAG 统一人工智能和数据库

原文地址&#xff1a;Text2SQL is Not Enough: Unifying AI and Databases with TAG 摘要 通过数据库为自然语言问题提供服务的人工智能系统有望释放出巨大的价值。此类系统可让用户利用语言模型&#xff08;LM&#xff09;的强大推理和知识能力&#xff0c;以及数据管理系统…...

Java:链接redis报错:NoSuchElementException: Unable to validate object

目录 前言报错信息排查1、确认redis密码设置是否有效2、确认程序配置文件&#xff0c;是否配置了正确的redis登录密码3、检测是否是redis持久化的问题4、确认程序读取到的redis密码没有乱码 原因解决 前言 一个已经上线的项目&#xff0c;生产环境的redis居然没有设置密码&…...

每日一题 334. 递增的三元子序列

334. 递增的三元子序列 使用贪心来找到三个数字 class Solution { public:bool increasingTriplet(vector<int>& nums) {int first INT_MAX;int second INT_MAX;for(int num : nums){if(num < first){first num;}else if(num < second){second num;}els…...

金仓 Kingbase 日常运维 SQL 汇总

金仓 Kingbase 日常运维 SQL 汇总 1 单机启停 sys_ctl start|stop|restart 或指定data路径和端口等 sys_ctl start|stop|restart -D /data/kingbase/data -p 543222 集群启停 sys_monitor start|stop|restart3 修改配置后重新加载 sys_ctl reload4 初始化实例 initdb -E ut…...

JAVA开发ERP时在 PurchaseOrderServiceImpl.java 中添加日志记录进行调试

在 PurchaseOrderServiceImpl.java 中添加日志记录&#xff0c;以便在保存订单时输出参数进行调试。可以使用 Spring 的日志框架&#xff08;SLF4J 和 Logback&#xff09;来实现这一点。 添加日志记录 引入 SLF4J 依赖: 确保项目中已经包含了 SLF4J 和 Logback 的依赖。通常在…...

36.3 grafana-dashboard看图分析

kube-prometheus中的grafana总结 db使用 sqlit&#xff0c;volume类型为emptydir 无法持久化&#xff0c;pod扩缩就重新创建通过configMap设置的prometheus DataSource 通过 prometheus-k8s svc对应的 域名访问下面对应两个prometheus容器&#xff0c;有HA 各个dashboard通过 …...

面试题整理5----进程、线程、协程区别及僵尸进程处理

面试题整理5----进程、线程、协程区别及僵尸进程处理 1. 进程、线程与协程的区别1.1 进程&#xff08;Process&#xff09;1.2 线程&#xff08;Thread&#xff09;1.3 协程&#xff08;Coroutine&#xff09;2. 总结对比 3. 僵尸进程3.1 什么是僵尸进程&#xff1f;3.2 僵尸进…...

【C语言程序设计——基础】顺序结构程序设计(头歌实践教学平台习题)【合集】

目录&#x1f60b; <第1关&#xff1a;顺序结构的应用> 任务描述 相关知识 编程要求 测试说明 我的通关代码: 测试结果&#xff1a; <第2关&#xff1a;交换变量值> 任务描述 相关知识 编程要求 测试说明 我的通关代码: 测试结果&#xff1a; <第…...

LLM大语言模型私有化部署-OpenEuler22.03SP3上容器化部署Dify与Qwen2.5

背景 Dify 是一款开源的大语言模型(LLM) 应用开发平台。其直观的界面结合了 AI 工作流、 RAG 管道、 Agent 、模型管理、可观测性功能等&#xff0c;让您可以快速从原型到生产。相比 LangChain 这类有着锤子、钉子的工具箱开发库&#xff0c; Dify 提供了更接近生产需要的完整…...

C语言中的转义字符

C语言中的转义字符 常见字符ASCII码表...

ilqr算法原理推导及代码实践

目录 一. ilqr原理推导1.1 ilqr问题描述1.2 ilqr算法原理1.3 ilqr算法迭代过程 二. ilqr实践代码 一. ilqr原理推导 1.1 ilqr问题描述 本文参考知乎博主: LQR与iLQR&#xff1a;从理论到实践【详细】 基础LQR只能处理线性系统 (指可以使用 x ( k 1 ) A x ( k ) B u ( k )…...

系列1:基于Centos-8.6部署Kubernetes (1.24-1.30)

每日禅语 “木末芙蓉花&#xff0c;山中发红萼&#xff0c;涧户寂无人&#xff0c;纷纷开自落。​”这是王维的一首诗&#xff0c;名叫《辛夷坞》​。这首诗写的是在辛夷坞这个幽深的山谷里&#xff0c;辛夷花自开自落&#xff0c;平淡得很&#xff0c;既没有生的喜悦&#xff…...

finereport新的数据工厂插件使用场景一 通过accessToken获取数据

1 有两个接口,一个接口获取一个accessToken,一个接口根据accessToken来获取数据。代码示例为: @RequestMapping(value = {"df_test/getAccessToken"},method = {RequestMethod.GET})@ResponseBodypublic String getAccessToken(HttpServletRequest req, HttpServ…...

matlab绘图时设置左、右坐标轴为不同颜色

目录 一、需求描述 二、实现方法 一、需求描述 当图中存在两条曲线&#xff0c;需要对两条曲线进行分别描述时&#xff0c;应设置左、右坐标轴为不同颜色&#xff0c;并设置刻度线&#xff0c;且坐标轴颜色需要和曲线颜色相同。 二、实现方法 1.1、可以实现&#xff1a; 1…...

魏裕雄的JAVA学习总结

JAVA学习总结 Java面向对象程序设计知识总结第1章 初识Java与面向对象程序设计JAVA概述面向对象程序设计思想JAVA开发环境搭建第一个JAVA程序JAVA常用开发工具 第2章 Java编程基础变量与常量运算符与表达式选择结构循环结构方法数组JVM中的堆内存与栈内存 第3章 面向对象程序设…...

深度学习从入门到精通——图像分割实战DeeplabV3

DeeplabV3算法 参数配置关于数据集的配置训练集参数 数据预处理模块DataSet构建模块测试一下数据集去正则化模型加载模块DeepLABV3 参数配置 关于数据集的配置 parser argparse.ArgumentParser()# Datset Optionsparser.add_argument("--data_root", typestr, defa…...

SAP抓取外部https报错SSL handshake处理方法

一、问题描述 SAP执行报表抓取https第三方数据,数据获取失败。 报错消息: SSL handshake with XXX.COM:449 failed: SSSLERR_SSL_READ (-58)#SAPCRYPTO:SSL_read() failed##SapSSLSessionStartNB()==SSSLERR_SSL_READ# SSL:SSL_read() failed (536875120/0x20001070)# …...

Electron-Vue 开发下 dev/prod/webpack server各种路径设置汇总

背景 在实际开发中&#xff0c;我发现团队对于这几个路径的设置上是纯靠猜的&#xff0c;通过一点点地尝试来找到可行的路径&#xff0c;这是不应该的&#xff0c;我们应该很清晰地了解这几个概念&#xff0c;以下通过截图和代码进行细节讲解。 npm run dev 下的路径如何处理&…...