第一次写博客。刚发布出来,发现格式不满意就删了,结果回来看,保存的也没了,真伤。还好有个回收箱,又复制了一遍。
话不多上,先上效果图:
图片效果是加上了样式与透明效果。这里只讲标题栏的创建方法,透明效果与样式我会在下一次介绍。为了让大家能够看清楚效果,上图是我以桌面作为背景。
相信大家可能已经查了很多资料,或者说刚看到我的这篇博客,不过都没关系,因为,看完我这篇,你们这个问题就可以解决了。大家每次本来把样式整的漂漂亮亮的,却因为系统的自带标题栏,导致整个程序页面的美感多了一点瑕疵。
自定义标题栏不仅可以让我们自由在标题栏上添加东西,更方便设计主题,如下面的QQ音乐页面。下面介绍自定义标题栏的三种方法,第一二种方法只介绍思路,详细会介绍第三种方法,也是我目前认为比较好的方法:
第一种:
1.去掉系统自带的标题栏。
2.在界面文件中,用控件在界面顶部布局一个标题栏。
这种方法优点是方便样式的设置,能更好的设置主题,而且设计起来也更简单。缺点是每次都要在新创建的工程中重新布局,还要设置变量,非常的麻烦与浪费多余宝贵的时间,如果是MainWindow窗口,这个方法就不能用了。这个方法就不多去介绍了。
第二种方法:
1、创建一个新的QWidget类,将这个QWidget设计成标题栏,然后再将这个QWidget类加到UI界面文件的顶部,这样每次新建工程,只需要将标题栏的.c和.h文件加到工程中,复制使用代码,就可以加入自定义的标题栏了,非常的方便。但是这个方法缺点是,UI界面的定义必须留一段空的控件放标题栏,与第一种方法有相同的限制,而且遇到MainWindow,会覆盖在菜单栏上,使用代码调整位置也效果不大。这种的负面效果图当时没保存,就不重新花时间弄一遍了。
相信大家查找资料,很多都是第一种第二种方法,而且绝大部分资料都没有考虑MainWindow工程与自己自定的标题栏能不能适用。博主当时查找资料也没有看到满意的资料,我希望能自定义一个标题栏,然后不影响工程的界面文件设计,以后新建工程的时候,能直接把标题栏文件加入工程就可以用了。后来查找资料过程中受到一句话启发,终于完美的解决了这个问题。下面介绍第三种方法。
第三种方法:
第三种方法与第二种方法非常类似。下面介绍思路:
先定义一个新的QWidget类 ,设为TitleBar,将它设计成标题栏。再定义一个新的QWidget类,设为WidgetPar,这个类作为容器,后面说到。然后在创建的工程中的构造函数中,将新建的标题栏类和工程的界面文件做一个整体布局,然后把他们添加到WidgetPar这个类容器中,这样就实现了自定义标题栏。这个方法使得添加标题栏非常方便,不影响原有的UI界面文件设计,而且对界面文件是哪个基类没有任何影响。效果图就是最开始看到的那个了。
设计标题栏就不多介绍了,就是重写事件,将标题栏的那些功能在自定义的标题栏上实现。
下面介绍代码:
titlebar.c和titlebar.h就是标题栏文件。
使用方法,在工程新建一个QWidget类,名字可以取上面一样的,然后将下面的代码复制上去。(类名相同可以全部替换)
titlebar.h
#ifndef TITLEBAR_H
#define TITLEBAR_H
#include <QWidget>
#include <QLabel>
#include <QPushButton>
/*
定义一个新的QWidget类,将标题栏和UI界面都放到这个类里面,定义这个类是为了方便改变主题
*/
class WidgetPar : public QWidget
{
Q_OBJECT
public:
explicit WidgetPar(QWidget *parent = 0);
signals:
public slots:
//void paintEvent(QPaintEvent *event);
};
/*
自定义的标题栏类
*/
class TitleBar : public QWidget
{
Q_OBJECT
public:
explicit TitleBar(QWidget *parent = 0);
signals:
public slots:
//右上角三个按钮共用一个槽函数
void on_TiBar_Clicked();
protected:
//重写鼠标事件
virtual void mouseDoubleClickEvent(QMouseEvent *event);// 双击标题栏进行界面的最大化/还原
virtual void mousePressEvent(QMouseEvent *event);// 进行鼠界面的拖动
virtual bool eventFilter(QObject *obj, QEvent *event);// 设置界面标题与图标
// 标题栏跑马灯效果时钟;
//QTimer m_titleRollTimer;
private:
void updateMaximize();// 最大化/还原
private://自定义标题栏控件
QLabel *TiBar_pIconLabel; //左上角图标label
QLabel *TiBar_pTitleLabel; //中间标题栏label
QPushButton *TiBar_pMinimizeBtn; //右上角缩小到底部任务栏按钮,最小化
QPushButton *TiBar_pMaximizeBtn; //右上角放大缩小按钮
QPushButton *TiBar_pCloseBtn; //右上角关闭按钮
public:
};
#endif // TITLEBAR_H
titlebar.c
#include "titlebar.h"
#include <QHBoxLayout>
#include <QEvent>
#include <QMouseEvent>
#include <QApplication>
#include <qt_windows.h>
#include <QPainter>
#include <QDebug>
TitleBar::TitleBar(QWidget *parent) :
QWidget(parent)
{
TiBar_pIconLabel = new QLabel;
TiBar_pTitleLabel = new QLabel;
TiBar_pMinimizeBtn = new QPushButton;
TiBar_pMaximizeBtn = new QPushButton;
TiBar_pCloseBtn = new QPushButton;
TiBar_pIconLabel->setFixedSize(32, 32); //设置图标固定大小
TiBar_pIconLabel->setScaledContents(true); //设置图片显示合适大小
TiBar_pTitleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);//此属性保存窗口小部件的默认布局行为。
TiBar_pMinimizeBtn->setFixedSize(32, 32);//设置三个按钮的固定大小
TiBar_pMaximizeBtn->setFixedSize(32, 32);
TiBar_pCloseBtn->setFixedSize(32, 32);
TiBar_pTitleLabel->setFixedHeight(32);
TiBar_pMinimizeBtn->setIcon(QIcon(":/image/image/small.ico"));
TiBar_pMinimizeBtn->setIconSize(TiBar_pMinimizeBtn->size());
TiBar_pMaximizeBtn->setIcon(QIcon(":/image/image/max.ico"));
TiBar_pMaximizeBtn->setIconSize(TiBar_pMinimizeBtn->size());
TiBar_pCloseBtn->setIcon(QIcon(":/image/image/close.ico"));
TiBar_pCloseBtn->setIconSize(TiBar_pMinimizeBtn->size());
QPixmap icon(":/image/image/lk.ico");
TiBar_pIconLabel->setPixmap(icon);
//TiBar_pIconLabel->resize(icon.width(),icon.height());
TiBar_pTitleLabel->setObjectName("whiteLabel"); //此属性保存此对象的名称。
TiBar_pMinimizeBtn->setObjectName("minimizeButton");
TiBar_pMaximizeBtn->setObjectName("maximizeButton");
TiBar_pCloseBtn->setObjectName("closeButton");
TiBar_pMinimizeBtn->setToolTip("最小化"); //鼠标停留在上面的提示
TiBar_pMaximizeBtn->setToolTip("放大/缩小");
TiBar_pCloseBtn->setToolTip("关闭");
QHBoxLayout *pLayout = new QHBoxLayout(this);
pLayout->addWidget(TiBar_pIconLabel);
//pLayout->addSpacing(5);
pLayout->addWidget(TiBar_pTitleLabel);
pLayout->addWidget(TiBar_pMinimizeBtn);
pLayout->addWidget(TiBar_pMaximizeBtn);
pLayout->addWidget(TiBar_pCloseBtn);
pLayout->setSpacing(0);//设置控件之间的间距
pLayout->setContentsMargins(0, 0, 0, 0);//设置左上右下的边距
this->setLayout(pLayout);
connect(TiBar_pMinimizeBtn,SIGNAL(clicked()),this,SLOT(on_TiBar_Clicked()));
connect(TiBar_pMaximizeBtn,SIGNAL(clicked()),this,SLOT(on_TiBar_Clicked()));
connect(TiBar_pCloseBtn,SIGNAL(clicked()),this,SLOT(on_TiBar_Clicked()));
}
/* 标题栏右上角三个按钮的槽函数*/
void TitleBar::on_TiBar_Clicked()
{
QPushButton *pBtn = qobject_cast<QPushButton *>(sender());//如果在由信号激活的槽中调用,则返回指向发送信号的对象的指针; 否则它返回0.
/* 返回此窗口小部件的窗口,即具有(或可能具有)窗口系统框架的下一个祖先窗口小部件。 如果窗口小部件是窗口,则返回窗口小部件本身。*/
QWidget *pWindow = this->window();
if (pWindow->isWindow())//如果窗口小部件是独立窗口,则返回true,否则返回false。
{
if (pBtn == TiBar_pMinimizeBtn)
{
pWindow->showMinimized();//最小化窗口小部件,作为图标。调用此函数仅影响窗口。
}
else if (pBtn == TiBar_pMaximizeBtn)
{
pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized();//放大缩小
}
else if (pBtn == TiBar_pCloseBtn)
{
pWindow->close();//关闭窗口
}
}
}
void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_UNUSED(event);
emit TiBar_pMaximizeBtn->clicked();
}
void TitleBar::mousePressEvent(QMouseEvent *event)
{
if (ReleaseCapture())
{
QWidget *pWindow = this->window();
if (pWindow->isWindow())
{
SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
}
}
event->ignore();
}
bool TitleBar::eventFilter(QObject *obj, QEvent *event)
{
switch (event->type())
{
case QEvent::WindowTitleChange:
{
QWidget *pWidget = qobject_cast<QWidget *>(obj);
if (pWidget)
{
TiBar_pTitleLabel->setText(pWidget->windowTitle());
return true;
}
}
case QEvent::WindowIconChange:
{
QWidget *pWidget = qobject_cast<QWidget *>(obj);
if (pWidget)
{
QIcon icon = pWidget->windowIcon();
TiBar_pIconLabel->setPixmap(icon.pixmap(TiBar_pIconLabel->size()));
return true;
}
}
case QEvent::WindowStateChange:
case QEvent::Resize:
//updateMaximize();
return true;
default:
return false;
}
return QWidget::eventFilter(obj, event);
}
//窗口大小发生改变
void TitleBar::updateMaximize()
{
QWidget *pWindow = this->window();
if (pWindow->isTopLevel())
{
bool bMaximize = pWindow->isMaximized();
if (bMaximize)
{
TiBar_pMaximizeBtn->setToolTip(tr("Restore"));
TiBar_pMaximizeBtn->setProperty("maximizeProperty", "restore");
}
else
{
TiBar_pMaximizeBtn->setProperty("maximizeProperty", "maximize");
TiBar_pMaximizeBtn->setToolTip(tr("Maximize"));
}
TiBar_pMaximizeBtn->setStyle(QApplication::style());
}
}
WidgetPar::WidgetPar(QWidget *parent) :
QWidget(parent)
{
}
mainwindow.cpp
#include <QGridLayout>
#include "titlebar.h"
ui->setupUi(this);
WidgetPar *selMainWidget = new WidgetPar; //创建一个QWidget容器
selMainWidget->setWindowFlags(Qt::FramelessWindowHint);//将这个QWidget的边框去掉
this->setParent(selMainWidget);//重新设置这个UI界面的父对象为QWidget
TitleBar *pTitleBar = new TitleBar(selMainWidget); //定义一个标题栏类
//设置控件样式
//selMainWidget->setStyleSheet("background-color:#AFFFFF00");
this->installEventFilter(pTitleBar);//安装事件过滤器
QGridLayout *pLayout = new QGridLayout();//创建一个整体布局器
pLayout->addWidget(pTitleBar); //添加标题栏
pLayout->addWidget(this); //添加UI界面
pLayout->setSpacing(0); //布局之间的距离
pLayout->setContentsMargins(0, 0, 0,0); //布局器的四周边距
selMainWidget->setLayout(pLayout); //将这个布局器设置在QWidget上
selMainWidget->setAttribute(Qt::WA_TranslucentBackground, true);
selMainWidget->setSizePolicy(this->sizePolicy());
selMainWidget->setMaximumSize(this->maximumSize());
selMainWidget->setMaximumSize(this->maximumSize());
this->setWindowTitle("自定义标题栏成功 -----By DS_LK");
selMainWidget->show();//显示QWidge 最后添加
大家按照这个方法基本没问题了。QT版本是用的qt5.3的。
参考资料:一去丶二三里