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

Qt自定义标题栏

效果如下:
在这里插入图片描述
代码如下:

// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();
protected:bool nativeEvent(const QByteArray&eventType,void *message,long*result) override;
private slots:void on_close();private:void mousePressEvent(QMouseEvent*ev);void mouseMoveEvent(QMouseEvent*ev);QPoint pos;
private:Ui::Widget *ui;int m_BorderWidth  =5;
};//2、titlebar
#ifndef CTABTITLEWIDGET_H
#define CTABTITLEWIDGET_H#include <QObject>
#include <QWidget>
#include<QPushButton>class CTabTitleWidget : public QWidget
{Q_OBJECT
public:explicit CTabTitleWidget(QWidget *parent = nullptr);~CTabTitleWidget();void setEmptyWidgetWidth(int w);protected:void paintEvent(QPaintEvent*event);void mousePressEvent(QMouseEvent*ev);void mouseDoubleClickEvent(QMouseEvent*event);signals:void sig_close();void sig_addtab();
private slots:void on_clicked();private:QPushButton* m_pAddBtn = nullptr;QWidget*     m_pEmptyWidget = nullptr;QPushButton* m_pUserBtn = nullptr;QPushButton* m_pMinBtn = nullptr;QPushButton* m_pMaxBtn = nullptr;QPushButton* m_pCloseBtn = nullptr;
};#endif // CTABTITLEWIDGET_H#endif // WIDGET_H//3.tabbrowser
#ifndef TABBROWSER_H
#define TABBROWSER_H#include <QObject>
#include <QWidget>
#include <QTabWidget>
#include <QMenu>
#include "ctabtitlewidget.h"
class tabbrowser : public QTabWidget
{Q_OBJECT
public:explicit tabbrowser(QWidget *parent = nullptr);enum TAB_FLAG{NEW,CLOSE,NORMAL,SPECIAL};protected:void resizeEvent(QResizeEvent*ev) override;private:void initTabWidget();void setTabBarFlag(TAB_FLAG);void createTabMenu();private slots:void on_newTab();void on_closeTab(int index);void onMenuShow(const QPoint&pos);void on_closeAllTab();private:CTabTitleWidget*m_pRightWidget = nullptr;QMenu* m_pTabMenu = nullptr;
signals:void sig_close();};#endif // TABBROWSER_H
.cpp
/./1.widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "tabbrowser.h"
#ifdef Q_OS_WIN
#include <qt_windows.h>
#include <Windows.h>
#include <windowsx.h>
#include <QHBoxLayout>
#include <QMouseEvent>
#endifWidget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 设置窗口为无边框setWindowFlag(Qt::FramelessWindowHint);setStyleSheet("background-color:#E3E4E7;");// 创建一个新的 tabbrowser 实例,并将其设置为此窗口的小部件tabbrowser* pTab = new tabbrowser(this);// 创建一个水平布局,并将 tabbrowser 添加到布局中QHBoxLayout* pHLay = new QHBoxLayout(this);pHLay->addWidget(pTab);pHLay->setContentsMargins(6, 6, 6, 6);setLayout(pHLay);// 连接 tabbrowser 的关闭信号到此窗口的 on_close 槽函数connect(pTab, &tabbrowser::sig_close, this, &Widget::on_close);
}Widget::~Widget()
{delete ui;
}// 处理自定义窗口行为的原生事件(例如,调整大小和移动)
bool Widget::nativeEvent(const QByteArray &eventType, void *message, long *result)
{Q_UNUSED(eventType)MSG* param = static_cast<MSG*>(message);switch (param->message){case WM_NCHITTEST:{int nX = GET_X_LPARAM(param->lParam) - this->geometry().x();int nY = GET_Y_LPARAM(param->lParam) - this->geometry().y();// 如果鼠标位于子控件上,则忽略此事件if (childAt(nX, nY) != nullptr)return QWidget::nativeEvent(eventType, message, result);// 当鼠标靠近边框时,进行调整大小操作if ((nX > 0) && (nX < m_BorderWidth))*result = HTLEFT;if ((nX > this->width() - m_BorderWidth) && (nX < this->width()))*result = HTRIGHT;if ((nY > 0) && (nY < m_BorderWidth))*result = HTTOP;if ((nY > this->height() - m_BorderWidth) && (nY < this->height()))*result = HTBOTTOM;if ((nX > 0) && (nX < m_BorderWidth) && (nY > 0) && (nY < m_BorderWidth))*result = HTTOPLEFT;if ((nX > this->width() - m_BorderWidth) && (nX < this->width()) && (nY > 0) && (nY < m_BorderWidth))*result = HTTOPRIGHT;if ((nX > 0) && (nX < m_BorderWidth) && (nY > this->height() - m_BorderWidth) && (nY < this->height()))*result = HTBOTTOMLEFT;if ((nX > this->width() - m_BorderWidth) && (nX < this->width()) && (nY > this->height() - m_BorderWidth) && (nY < this->height()))*result = HTBOTTOMRIGHT;return true;}}return QWidget::nativeEvent(eventType, message, result);
}// 处理关闭信号的槽函数
void Widget::on_close()
{close();
}// 处理鼠标按下事件以移动窗口
void Widget::mousePressEvent(QMouseEvent *ev)
{if (Qt::LeftButton == ev->button()){// 计算鼠标相对于窗口左上角的位置pos = ev->globalPos() - frameGeometry().topLeft();ev->accept();}
}// 处理鼠标移动事件以移动窗口
void Widget::mouseMoveEvent(QMouseEvent *ev)
{if (Qt::LeftButton & ev->buttons()){// 移动窗口到鼠标移动后的位置move(ev->globalPos() - pos);ev->accept();}
}

//2.titlebar
#include “CTabTitleWidget.h”

#include
#include
#include
#include

#ifdef Q_OS_WIN
#include <qt_windows.h>
#pragma comment(lib, “user32.lib”)
#endif
CTabTitleWidget::CTabTitleWidget(QWidget *parent)
: QWidget{parent}
{
setStyleSheet(“background-color:#E3E4E7”);
m_pAddBtn = new QPushButton(this);
m_pAddBtn->setFlat(true);
m_pAddBtn->setFixedSize(32, 32);
m_pAddBtn->setStyleSheet(“background-image:url(:/resources/add.svg)”);

m_pEmptyWidget = new QWidget(this);m_pUserBtn = new QPushButton(this);
m_pUserBtn->setFlat(true);
m_pUserBtn->setFixedSize(32, 32);
m_pUserBtn->setStyleSheet("background-image:url(:/resources/user)");m_pMinBtn = new QPushButton(this);
m_pMinBtn->setFlat(true);
m_pMinBtn->setFixedSize(32, 32);
m_pMinBtn->setStyleSheet("background-image:url(:/resources/min.svg)");m_pMaxBtn = new QPushButton(this);
m_pMaxBtn->setFlat(true);
m_pMaxBtn->setFixedSize(32, 32);
m_pMaxBtn->setStyleSheet("background-image:url(:/resources/max.svg)");m_pCloseBtn = new QPushButton(this);
m_pCloseBtn->setFlat(true);
m_pCloseBtn->setFixedSize(32, 32);
m_pCloseBtn->setStyleSheet("background-image:url(:/resources/close.svg)");QHBoxLayout* pHLay = new QHBoxLayout(this);
pHLay->addWidget(m_pAddBtn);
pHLay->addWidget(m_pEmptyWidget);
this->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
pHLay->addWidget(m_pUserBtn);
pHLay->addSpacing(8);
pHLay->addWidget(m_pMinBtn);
pHLay->addWidget(m_pMaxBtn);
pHLay->addWidget(m_pCloseBtn);
pHLay->setContentsMargins(1, 0, 1, 3);
setLayout(pHLay);connect(m_pAddBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);
connect(m_pMinBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);
connect(m_pMaxBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);
connect(m_pCloseBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);

}

CTabTitleWidget::~CTabTitleWidget()
{

}

void CTabTitleWidget::setEmptyWidgetWidth(int w)
{
m_pEmptyWidget->setMinimumWidth(w);
}

void CTabTitleWidget::paintEvent(QPaintEvent *event)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
QWidget::paintEvent(event);
}

void CTabTitleWidget::mousePressEvent(QMouseEvent ev)
{
if(ReleaseCapture())
{
QWidget
win = this->window();
if(win->isTopLevel())
{
SendMessage(HWND(win->winId()),WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0);
}
}
ev->ignore();
}

void CTabTitleWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
emit m_pMaxBtn->clicked();
}

void CTabTitleWidget::on_clicked()
{
QPushButtonbtn = qobject_cast<QPushButton>(sender());
QWidget*win = this->window();
if(win->isTopLevel())
{
if (btn == m_pAddBtn)
{
emit sig_addtab();
}
else if (btn == m_pMinBtn)
{
win->showMinimized();
}
else if (btn == m_pMaxBtn)
{
win->isMaximized() ? win->showNormal() : win->showMaximized();
}
else if (btn == m_pCloseBtn)
{
emit sig_close();
}
}
}
//3.tabbrowser
#include “tabbrowser.h”
#include
#include
#include
#include
#include

QString qss0 = “QTabBar::tab{
font: 75 12pt Arial;
text-align:left;
width:184px;
height:32;
background:#FFFFFF;
border:2px solid #FFFFFF;
border-bottom-color:#FFFFFF;
border-top-left-radius:4px;
border-top-right-radius:4px;
padding:2px;
margin-top:0px;
margin-right:1px;
margin-left:1px;
margin-bottom:0px;}
QTabBar::tab:selected{
color:#333333; /文字颜色/
background-color:#FFFFFF;}
QTabBar::tab:!selected{
color:#B2B2B2;
border-color:#FFFFFF;}
QTabBar::scroller{width: 0px;}”;

QString qss1 = "QTabBar::tab{ \
font: 75 12pt Arial; \
text-align:left; \
width:184px; \
height:32; \
background:#FFFFFF; \
border:2px solid #FFFFFF; \
border-bottom-color:#FFFFFF; \
border-top-left-radius:4px; \
border-top-right-radius:4px; \
padding:2px; \
margin-top:0px; \
margin-right:1px; \
margin-left:1px;  \
margin-bottom:0px;} \
QTabBar::tab:selected{  \color:#333333; /*文字颜色*/  \background-color:#FFFFFF;} \
QTabBar::tab:!selected{ \color:#B2B2B2; \border-color:#FFFFFF;} \
QTabBar::scroller{width: 36px;}";
tabbrowser::tabbrowser(QWidget *parent)
QTabWidget{parent}
{
this->addTab(new QWidget,u8"稻壳");
this->setUsesScrollButtons(true);//滚动鼠标可切换tab
this->setTabsClosable(true); //显示tab右侧的关闭按钮
this->setMovable(true);//设置可移动位置
initTabWidget();
setTabBarFlag(NORMAL);this->setStyleSheet(qss0);connect(this, &QTabWidget::tabCloseRequested,this, &tabbrowser::on_closeTab);

}

void tabbrowser::resizeEvent(QResizeEvent *ev)
{
setTabBarFlag(NORMAL);
QTabWidget::resizeEvent(ev);
}

void tabbrowser::initTabWidget()
{
this->setContextMenuPolicy(Qt::CustomContextMenu);
connect(this,&QTabWidget::customContextMenuRequested,this,&tabbrowser::onMenuShow);
createTabMenu();

m_pRightWidget = new CTabTitleWidget(this);this->setCornerWidget(m_pRightWidget, Qt::TopRightCorner);
connect(m_pRightWidget, &CTabTitleWidget::sig_addtab, this, &tabbrowser::on_newTab);
connect(m_pRightWidget, &CTabTitleWidget::sig_close, this, &tabbrowser::sig_close);

}

void tabbrowser::setTabBarFlag(TAB_FLAG flag)
{
int w = this->width();

int tabsWidth = 0;  //所有tab的总宽度
int tabsHeight = tabBar()->height();
int tabs = this->count();if (flag == NEW || flag == NORMAL)
{for (int i = 0; i < tabs; ++i){tabsWidth += tabBar()->tabRect(i).width();}
}
else
{for (int i = 0;i < tabs - 1;++i){tabsWidth += tabBar()->tabRect(i).width();}
}if (w > tabsWidth)
{m_pRightWidget->setEmptyWidgetWidth(w - tabsWidth - 32 * 5 - 15);this->setStyleSheet(qss0);
}
else
{//当所有tab的宽度大于整个tabWidget的宽时m_pRightWidget->setEmptyWidgetWidth(150);this->setStyleSheet(qss1);
}

}

void tabbrowser::createTabMenu()
{
m_pTabMenu = new QMenu(this);

QAction* pAcSave = new QAction(QIcon(":/resources/save.png"), u8"保存", m_pTabMenu);
m_pTabMenu->addAction(pAcSave);connect(pAcSave, &QAction::triggered, [=] {QMessageBox::information(this, u8"提示", u8"你点击了 保存");});QAction* pAcSaveAs = new QAction(QString(u8"另存为"), m_pTabMenu);
m_pTabMenu->addAction(pAcSaveAs);m_pTabMenu->addSeparator();QAction* pAcShareDoc = new QAction(QIcon(":/resources/share.png"), QString(u8"分享文档"), m_pTabMenu);
m_pTabMenu->addAction(pAcShareDoc);QAction* pAcSendToDevice = new QAction(QString(u8"发送到设备"), m_pTabMenu);
m_pTabMenu->addAction(pAcSendToDevice);m_pTabMenu->addSeparator();QAction* pAcNewName = new QAction(QString(u8"重命名"), m_pTabMenu);
m_pTabMenu->addAction(pAcNewName);QAction* pAcSaveToWPSCloud = new QAction(QString(u8"保存到WPS云文档"), m_pTabMenu);
m_pTabMenu->addAction(pAcSaveToWPSCloud);QAction* pAcCloseAll = new QAction(QString(u8"关闭所有文件"), m_pTabMenu);
m_pTabMenu->addAction(pAcCloseAll);
connect(pAcCloseAll, &QAction::triggered, this, &tabbrowser::on_closeAllTab);

}

void tabbrowser::on_newTab()
{
int nCount = count();
QString title = QString::number(nCount);
title = “Page” + title;

// 这里写的有问题,应该是 insertTab
this->addTab(new QWidget, title);if (!tabsClosable())
{setTabsClosable(true);
}setTabBarFlag(NEW);

}

void tabbrowser::on_closeTab(int index)
{
widget(index)->deleteLater();
setTabBarFlag(CLOSE);

//当只剩下1个tab时
if (count() == 1)
{setTabsClosable(false);setTabBarFlag(SPECIAL);
}

}

void tabbrowser::onMenuShow(const QPoint &pos)
{
int index = this->tabBar()->tabAt(pos);

#ifdef _DEBUG
qDebug() << u8"当前tab为:" << QString::number(index);
this->setCurrentIndex(index);
#endif

if (index != -1)
{m_pTabMenu->exec(QCursor::pos());
}

}

void tabbrowser::on_closeAllTab()
{

}

http://www.lryc.cn/news/355460.html

相关文章:

  • java如何向数组中插入元素
  • 4、PHP的xml注入漏洞(xxe)
  • 设计模式-解释器模式
  • NDIS驱动程序堆栈
  • 大数据开发面试题【数仓篇】
  • Leetcode刷题笔记5
  • 【Qt】Qt中的信号槽
  • VsCode个人插件
  • Docker环境安装并使用Elasticsearch
  • 中心渗透Ⅱ
  • 【webrtc】RtpToNtpEstimator:最小二乘法、ntp估计及c++实例
  • 【DevOps】Elasticsearch在Ubuntu 20.04上的安装与配置:详细指南
  • windows内存管理
  • c++ 将指针转换为 void* 后,转换为怎么判断原指针类型?
  • Swift 属性
  • 基于maxkey接入jeecgboot并实现账户同步
  • kafka Kerberos集群环境部署验证
  • [C++]debug介绍+debug时如何查看指针指向内存处的值
  • AI学习指南数学工具篇-凸优化在支持逻辑回归中的应用
  • Flutter 中的 AspectRatio 小部件:全面指南
  • 应用程序中的会话管理和Cookie安全指南
  • 备战秋招c++ 【持续更新】
  • 整数拆分~
  • 【Qt Creator】跨平台的C++图形用户界面应用程序开发框架---QT
  • KingbaseES数据库物理备份还原sys_rman
  • 【CV】视频图像背景分割MOG2,KNN,GMG
  • 使用 Python 简单几步去除 PDF 水印
  • 【香橙派 AIpro】OrangePi AIpro :教育、机器人、无人机领域的超级AI大脑,华为昇腾处理器驱动的AI开发板新标杆
  • 【Mac】 CleanMyMac X for mac V4.15.2中文修复版安装教程
  • 单片机通信协议(1):SPI简介