Qt开发 系列文章 - user-defined-titlebars(十)
目录
前言
一、方式一
1.效果演示
2.创建标题栏类
3.可视化UI设计
4.定义相关函数
5.使用标题栏类
二、方式二
1.效果演示
2.创建标题栏类
3.定义相关函数
4.使用标题栏类
总结
前言
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来设计标题栏,然后绑定/链接到主窗口界面上,跟方式一一样。
总结
博文中相应的工程代码Qt-Case.zip 利用Qt开发软件进行编的例程,为博文提供案例-CSDN文库。