Qt自定义标题栏
程序员文章站
2022-07-13 23:14:20
...
#ifndef WINDOWHEADER_H
#define WINDOWHEADER_H
#include <QWidget>
#include <QLabel>
#include <QWidget>
#include <QToolButton>
#include <QHBoxLayout>
#include <QPoint>
#include <QString>
#include <QDebug>
// 自定义控件,可拖拽标题栏
class WindowHeader : public QWidget
{
Q_OBJECT
public:
// 构造函数
WindowHeader(const char* name, QWidget *parent);
// 设置关闭按钮icon
void SetCloseImage(const char* path);
// 设置最小化按钮icon
void SetMinImage(const char* path);
// 设置最大化按钮icon
void SetMaxImage(const char* path);
// 设置迷你模式按钮icon
void SetMiniImage(const char* path);
// 设置软件配置按钮icon
void SetSettingImage(const char* path);
// 设置皮肤按钮icon
void SetSkinImage(const char* path);
// 设置软件LOGO按钮icon
void SetAppLogo(const char* path,int w=20,int h=20);
// 获取软件名
QString GetAppName() { return m_name; }
protected:
// 重写鼠标事件
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
virtual bool eventFilter(QObject *obj, QEvent *event);
void paintEvent(QPaintEvent *event);
// 将信号中转,不直接处理信号
signals:
void ClickedClose();
void ClickedMin();
void ClickedMax();
void ClickedMini();
void ClickedSetting();
void ClickedSkin();
private:
// 应用名
QString m_name;
int m_height;
// 关闭按钮
QToolButton* m_toolbtnClose;
// 最小化按钮
QToolButton* m_toolbtnMin;
// 最大化按钮
QToolButton* m_toolbtnMax;
// 迷你模式按钮
QToolButton* m_toolbtnMini;
// 软件配置按钮
QToolButton* m_toolbtnSetting;
// 皮肤设置按钮
QToolButton* m_toolbtnSkin;
// 呈现应用名称
QLabel* m_lableAppName;
// 呈现应用LOGO
QLabel* m_lableAppLogo;
// 鼠标上次移动开始时相对屏幕的位置
QPoint m_pointStart;
// 鼠标是否持续按下
bool mbKeepPressed;
// 父窗口的指针
QWidget *m_widgetParent;
// 最大化/还原
void updateMaximize();
};
#endif // WINDOWHEADER_H
cpp文件
#include "WindowHeader.h"
#include <QEvent>
#include <QMouseEvent>
#include <QPixmap>
#include <QIcon>
#include <QPainter>
#include <QStyleOption>
WindowHeader::WindowHeader(const char* name, QWidget *parent)
:QWidget(parent),
m_name(name),
m_height(48)
{
// 父窗口指针赋值,并设置父窗口为透明的无边框模式,
//以后所有的控件将在父窗口中布局,包括菜单栏,工具栏,状态栏以及设置个主窗口,
m_widgetParent = parent;
m_widgetParent->setAttribute(Qt::WA_TranslucentBackground);
m_widgetParent->setWindowFlags(Qt::FramelessWindowHint | m_widgetParent->windowFlags());
//监听父窗口事件,主要用于窗口大小变化
m_widgetParent->installEventFilter(this);
//设置大小属性,横向伸展,竖向固定
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
this->resize(m_widgetParent->width(), m_height);
//绘制圆角需要设置这两个属性。
this->setAttribute(Qt::WA_TranslucentBackground);//设置窗口背景透明
this->setWindowFlags(Qt::FramelessWindowHint); //设置无边框窗口
// 初始化按钮
m_toolbtnClose = new QToolButton(this);
m_toolbtnClose->setText("关闭");
m_toolbtnMin = new QToolButton(this);
m_toolbtnMin->setText("最小化");
m_toolbtnMax = new QToolButton(this);
m_toolbtnMax->setText("最大化");
m_toolbtnMini = new QToolButton(this);
m_toolbtnSetting = new QToolButton(this);
m_toolbtnSkin = new QToolButton(this);
// 初始化标签
m_lableAppName = new QLabel(this);
m_lableAppName->setText(m_name);
m_lableAppLogo = new QLabel(this);
// 初始化布局
QHBoxLayout* mainLayout = new QHBoxLayout(this);
mainLayout->setContentsMargins(0,0,0,0);
mainLayout->setSpacing(2);
// 设置布局
mainLayout->addWidget(m_lableAppLogo);
mainLayout->addWidget(m_lableAppName);
// 设置“弹簧”,将呈现和按钮功能分开
mainLayout->addStretch();
mainLayout->addWidget(m_toolbtnSkin);
mainLayout->addWidget(m_toolbtnSetting);
mainLayout->addWidget(m_toolbtnMini);
mainLayout->addWidget(m_toolbtnMin);
mainLayout->addWidget(m_toolbtnMax);
mainLayout->addWidget(m_toolbtnClose);
// 将内部按钮信号全部发送出去,内部不做业务逻辑绑定
connect(m_toolbtnClose,SIGNAL(clicked(bool)),SIGNAL(ClickedClose()));
connect(m_toolbtnMax,SIGNAL(clicked(bool)),SIGNAL(ClickedMax()));
connect(m_toolbtnMin,SIGNAL(clicked(bool)),SIGNAL(ClickedMin()));
connect(m_toolbtnMini,SIGNAL(clicked(bool)),SIGNAL(ClickedMini()));
connect(m_toolbtnSetting,SIGNAL(clicked(bool)),SIGNAL(ClickedSetting()));
connect(m_toolbtnSkin,SIGNAL(clicked(bool)),SIGNAL(ClickedSkin()));
}
// 设置应用LOGO
void WindowHeader::SetAppLogo(const char *path,int w,int h)
{
QPixmap newPix = QPixmap(path).scaled(w,h,Qt::KeepAspectRatio);;
m_lableAppLogo->setPixmap(newPix);
}
void WindowHeader::SetSkinImage(const char *path)
{
QIcon icon(path);
m_toolbtnSkin->setIcon(icon);
}
void WindowHeader::SetSettingImage(const char *path)
{
QIcon icon(path);
m_toolbtnSetting->setIcon(icon);
}
void WindowHeader::SetMiniImage(const char *path)
{
QIcon icon(path);
m_toolbtnMini->setIcon(icon);
}
void WindowHeader::SetMaxImage(const char *path)
{
QIcon icon(path);
m_toolbtnMax->setIcon(icon);
}
void WindowHeader::SetMinImage(const char *path)
{
QIcon icon(path);
m_toolbtnMin->setIcon(icon);
}
void WindowHeader::SetCloseImage(const char *path)
{
QIcon icon(path);
m_toolbtnClose->setIcon(icon);
}
// 重写mouseMoveEvent
void WindowHeader::mouseMoveEvent(QMouseEvent *event)
{
// 持续按住才做对应事件
if (mbKeepPressed)
{
// 将父窗体移动到父窗体之前的位置加上鼠标移动的位置event->globalPos()- m_pointStart
m_widgetParent->move(m_widgetParent->geometry().topLeft() + event->globalPos()- m_pointStart);
// 将鼠标在屏幕中的位置替换为新的位置
m_pointStart = event->globalPos();
}
}
// 重写mousePressEvent
void WindowHeader::mousePressEvent(QMouseEvent *event)
{
// 鼠标左键按下事件
if (event->button() == Qt::LeftButton)
{
// 记录鼠标状态
mbKeepPressed = true;
// 记录鼠标在屏幕中的位置
m_pointStart = event->globalPos();
}
}
// 重写mouseReleaseEvent
void WindowHeader::mouseReleaseEvent(QMouseEvent *event)
{
// 鼠标左键释放
if (event->button() == Qt::LeftButton)
{
// 记录鼠标状态
mbKeepPressed = false;
}
}
void WindowHeader::updateMaximize()
{
QWidget *pWindow = this->window();
if (pWindow->isTopLevel())
{
bool bMaximize = pWindow->isMaximized();
if (bMaximize)
{
m_toolbtnMax->setToolTip("还原");
m_toolbtnMax->setText("还原");
// m_toolbtnMax->setProperty("maximizeProperty", "restore");
}
else
{
// m_toolbtnMax->setProperty("maximizeProperty", "maximize");
m_toolbtnMax->setToolTip("最大化");
m_toolbtnMax->setText("最大化");
}
}
}
bool WindowHeader::eventFilter(QObject *obj, QEvent *event)
{
if(obj == m_widgetParent)
{
if(event->type() == QEvent::WindowTitleChange)
{
m_name = m_widgetParent->windowTitle();
m_lableAppName->setText(m_name);
return true;
}
else if(event->type() == QEvent::WindowIconChange)
{
QIcon icon = m_widgetParent->windowIcon();
m_lableAppLogo->setPixmap(icon.pixmap(m_lableAppLogo->size()));
return true;
}
else if(event->type() == QEvent::WindowStateChange || event->type() == QEvent::Resize)
{
this->resize(m_widgetParent->width(), m_height);
updateMaximize();
return true;
}
}
return QWidget::eventFilter(obj, event);
}
void WindowHeader::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing); // 反锯齿;
painter.setBrush(QBrush(Qt::red));
painter.setPen(Qt::transparent);
QRect rect = this->rect();
painter.drawRoundedRect(rect, 10, 10);//绘制圆角矩形
//覆盖上面绘制圆角矩形的左下角和右下角
QRect rect2(QPoint(rect.left(), rect.center().y()), rect.bottomRight());
painter.drawRect(rect2);
// painter.fillRect(this->rect(), QColor(255, 0, 0, 80)); //QColor最后一个参数80代表背景的透明度
QWidget::paintEvent(event);
}
使用:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "windowheader.h"
#include <QVBoxLayout>
#include <QMenuBar>
#include <QToolBar>
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
void setMenuBar(QMenuBar* menuBar);
void setCentralWidget(QWidget *widget);
protected:
virtual void paintEvent(QPaintEvent *event);
private:
WindowHeader* m_titleBar;
QMenuBar* m_menuBar;
QWidget* m_centralWidget;
QVBoxLayout* m_mainLayout;
signals:
public slots:
};
#endif // WIDGET_H
#include "widget.h"
#include <QPainter>
#include <QDebug>
#include <QPushButton>
Widget::Widget(QWidget *parent) :
QWidget(parent)
{
m_titleBar = new WindowHeader(this->windowTitle().toStdString().c_str(), this);
connect(m_titleBar, SIGNAL(ClickedClose()),
this, SLOT(close()));
connect(m_titleBar, SIGNAL(ClickedMin()),
this, SLOT(showMinimized()));
connect(m_titleBar, SIGNAL(ClickedMax()),
this, SLOT(showMaximized()));
this->setWindowTitle("自定义窗口");
this->setWindowIcon(QIcon(":reboot.ico"));
m_menuBar = new QMenuBar(this);
QMenu* menu = new QMenu("文件(&F)", this);
m_menuBar->addMenu(menu);
menu->addAction("打开");
m_centralWidget = new QWidget(this);
m_centralWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_mainLayout = new QVBoxLayout;
m_mainLayout->setContentsMargins(2, 0, 2, 0);
// qDebug() << m_titleBar->height();
m_mainLayout->addSpacing(m_titleBar->height());
m_mainLayout->addWidget(m_menuBar);
m_mainLayout->addWidget(m_centralWidget);
// m_mainLayout->addStretch();
this->setLayout(m_mainLayout);
}
void Widget::setCentralWidget(QWidget* widget)
{
if(widget == NULL)
return;
m_mainLayout->replaceWidget(m_centralWidget, widget);
delete m_centralWidget;
m_centralWidget = widget;
m_centralWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// m_centralWidget->show();
}
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing); // 反锯齿;
QPen pen;
pen.setStyle(Qt::SolidLine);
pen.setWidth(1);
pen.setColor(Qt::red);
painter.setPen(pen);
//从标题栏左下角开始画
QRect rect = m_titleBar->rect();
QRect rect2(rect.bottomLeft(), this->rect().bottomRight()/* - QPoint(2, 0)*/);
painter.drawRect(rect2);
painter.fillRect(rect2, QColor(255, 0, 0, 30)); //QColor最后一个参数80代表背景的透明度
QWidget::paintEvent(event);
}
主程序调用:
Widget* w = new Widget;
w->setWindowTitle("标题栏");
w->resize(400, 300);
w->show();
QWidget* w2 = new QWidget;
w->setCentralWidget(w2);
QPushButton* btn = new QPushButton("OK", w2);
QVBoxLayout* layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(btn);
layout->addStretch();
w2->setLayout(layout);