Qt 无边框窗口自定义标题栏

2024-04-26 09:18

本文主要是介绍Qt 无边框窗口自定义标题栏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

实现了自定义标题栏的最小化,最大化(自适应任务栏),关闭,拉伸,拖曳。

因为不想引入其他资源,所以按钮,背景都是系统提供的。

效果图:



直接上代码。

用法:

#include "widget.h"
#include <QApplication>
#include "CustomFrame.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget *w = new Widget();CustomFrame frame(w, "CustomFrame");frame.show();return a.exec();
}

#pragma once#include <QFrame>class QToolButton;
class CustomFrame : public QFrame
{Q_OBJECT
public:explicit CustomFrame(QWidget *contentWidget, const QString &title);public slots:void slotShowSmall();void slotShowMaxRestore();protected:void mousePressEvent(QMouseEvent *);void mouseMoveEvent(QMouseEvent *);void mouseReleaseEvent(QMouseEvent *);bool nativeEvent(const QByteArray & eventType, void * message, long * result);void paintEvent(QPaintEvent *);private:bool isMax_;bool isPress_;QPoint startPos_;QPoint clickPos_;QWidget *contentWidget_;QPixmap maxPixmap_;QPixmap restorePixmap_;QToolButton *maxButton_;
};


#include "CustomFrame.h"
#include <QtWidgets>static const int TITLE_HEIGHT = 30;
static const int FRAME_BORDER = 2;
CustomFrame::CustomFrame(QWidget *contentWidget, const QString &title): contentWidget_(contentWidget)
{this->setWindowFlags(Qt::FramelessWindowHint);this->setAttribute(Qt::WA_TranslucentBackground);this->setMouseTracking(true);isMax_ = false;isPress_ = false;QLabel *logoLabel = new QLabel();QPixmap logoPixmap = this->style()->standardPixmap(QStyle::SP_TitleBarMenuButton);logoLabel->setPixmap(logoPixmap);logoLabel->setFixedSize(16, 16);logoLabel->setScaledContents(true);QLabel *titleLabel = new QLabel();titleLabel->setText(title);QFont titleFont = titleLabel->font();titleFont.setBold(true);titleLabel->setFont(titleFont);titleLabel->setObjectName("whiteLabel");QToolButton *minButton = new QToolButton();QPixmap minPixmap = this->style()->standardPixmap(QStyle::SP_TitleBarMinButton);minButton->setIcon(minPixmap);connect(minButton, SIGNAL(clicked()), this, SLOT(slotShowSmall()));maxButton_ = new QToolButton();maxPixmap_ = this->style()->standardPixmap(QStyle::SP_TitleBarMaxButton);restorePixmap_ = this->style()->standardPixmap(QStyle::SP_TitleBarNormalButton);maxButton_->setIcon(maxPixmap_);connect(maxButton_, SIGNAL(clicked()), this, SLOT(slotShowMaxRestore()));QToolButton *closeButton = new QToolButton();QPixmap closePixmap = this->style()->standardPixmap(QStyle::SP_TitleBarCloseButton);closeButton->setIcon(closePixmap);connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));QHBoxLayout *titleLayout = new QHBoxLayout();titleLayout->addWidget(logoLabel);titleLayout->addWidget(titleLabel);titleLabel->setContentsMargins(5, 0, 0, 0);titleLayout->addStretch();titleLayout->addWidget(minButton, 0, Qt::AlignTop);titleLayout->addWidget(maxButton_, 0, Qt::AlignTop);titleLayout->addWidget(closeButton, 0, Qt::AlignTop);titleLayout->setSpacing(0);titleLayout->setContentsMargins(5, 0, 0, 0);QWidget *titleWidget = new QWidget();titleWidget->setLayout(titleLayout);titleWidget->installEventFilter(0);QVBoxLayout *mainLayout = new QVBoxLayout();mainLayout->addWidget(titleWidget);mainLayout->addWidget(contentWidget_);mainLayout->setSpacing(0);mainLayout->setMargin(5);this->setLayout(mainLayout);
}void CustomFrame::slotShowSmall()
{this->showMinimized();
}void CustomFrame::slotShowMaxRestore()
{if (isMax_) {this->showNormal();maxButton_->setIcon(maxPixmap_);} else {this->showMaximized();maxButton_->setIcon(restorePixmap_);}isMax_ = !isMax_;
}void CustomFrame::mousePressEvent(QMouseEvent *e)
{startPos_ = e->globalPos();clickPos_ = e->pos();if (e->button() == Qt::LeftButton) {if (e->type() == QEvent::MouseButtonPress) {isPress_ = true;} else if (e->type() == QEvent::MouseButtonDblClick && e->pos().y() <= TITLE_HEIGHT) {this->slotShowMaxRestore();}}
}void CustomFrame::mouseMoveEvent(QMouseEvent *e)
{if (isMax_ || !isPress_) {return;}this->move(e->globalPos() - clickPos_);
}void CustomFrame::mouseReleaseEvent(QMouseEvent *)
{isPress_ = false;
}bool CustomFrame::nativeEvent(const QByteArray & eventType, void * message, long * result)
{Q_UNUSED(eventType);const int HIT_BORDER = 5;const MSG *msg=static_cast<MSG*>(message);if(msg->message == WM_NCHITTEST) {int xPos = ((int)(short)LOWORD(msg->lParam)) - this->frameGeometry().x();int yPos = ((int)(short)HIWORD(msg->lParam)) - this->frameGeometry().y();if(this->childAt(xPos,yPos) == 0) {*result = HTCAPTION;} else {return false;}if(xPos > 0 && xPos < HIT_BORDER) {*result = HTLEFT;}if(xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0)) {*result = HTRIGHT;}if(yPos > 0 && yPos < HIT_BORDER) {*result = HTTOP;}if(yPos > (this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {*result = HTBOTTOM;}if(xPos > 0 && xPos < HIT_BORDER && yPos > 0 && yPos < HIT_BORDER) {*result = HTTOPLEFT;}if(xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos > 0 && yPos < HIT_BORDER) {*result = HTTOPRIGHT;}if(xPos > 0 && xPos < HIT_BORDER && yPos > (this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {*result = HTBOTTOMLEFT;}if(xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos > (this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {*result = HTBOTTOMRIGHT;}return true;}return false;
}void CustomFrame::paintEvent(QPaintEvent *e)
{int border = FRAME_BORDER;if (this->isMaximized()) {border = 0;}QPainter painter(this);QPainterPath painterPath;painterPath.setFillRule(Qt::WindingFill);painterPath.addRect(border, border, this->width()-2*border, this->height()-2*border);painter.setRenderHint(QPainter::Antialiasing, true);painter.fillPath(painterPath, QBrush(Qt::white));QColor color(200, 200, 200);for (int i=0; i<border; i++) {color.setAlpha((i+1)*30);painter.setPen(color);painter.drawRect(border-i, border-i, this->width()-(border-i)*2, this->height()-(border-i)*2);}painter.setPen(Qt::NoPen);painter.setBrush(Qt::white);// 这里可以在资源中指定一张标题背景图片//painter.drawPixmap(QRect(border, border, this->width()-2*border, this->height()-2*border), QPixmap(DEFAULT_SKIN));painter.drawRect(QRect(border, TITLE_HEIGHT, this->width()-2*border, this->height()-TITLE_HEIGHT-border));QFrame::paintEvent(e);
}


这篇关于Qt 无边框窗口自定义标题栏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/937181

相关文章

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

QT Creator配置Kit的实现示例

《QTCreator配置Kit的实现示例》本文主要介绍了使用Qt5.12.12与VS2022时,因MSVC编译器版本不匹配及WindowsSDK缺失导致配置错误的问题解决,感兴趣的可以了解一下... 目录0、背景:qt5.12.12+vs2022一、症状:二、原因:(可以跳过,直奔后面的解决方法)三、解决方

聊聊springboot中如何自定义消息转换器

《聊聊springboot中如何自定义消息转换器》SpringBoot通过HttpMessageConverter处理HTTP数据转换,支持多种媒体类型,接下来通过本文给大家介绍springboot中... 目录核心接口springboot默认提供的转换器如何自定义消息转换器Spring Boot 中的消息

Python自定义异常的全面指南(入门到实践)

《Python自定义异常的全面指南(入门到实践)》想象你正在开发一个银行系统,用户转账时余额不足,如果直接抛出ValueError,调用方很难区分是金额格式错误还是余额不足,这正是Python自定义异... 目录引言:为什么需要自定义异常一、异常基础:先搞懂python的异常体系1.1 异常是什么?1.2

Qt中实现多线程导出数据功能的四种方式小结

《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方... 目录前言导出文件的示例工具类QThreadQObject的moveToThread方法实现多线程QC

Linux中的自定义协议+序列反序列化用法

《Linux中的自定义协议+序列反序列化用法》文章探讨网络程序在应用层的实现,涉及TCP协议的数据传输机制、结构化数据的序列化与反序列化方法,以及通过JSON和自定义协议构建网络计算器的思路,强调分层... 目录一,再次理解协议二,序列化和反序列化三,实现网络计算器3.1 日志文件3.2Socket.hpp

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束

PostgreSQL中rank()窗口函数实用指南与示例

《PostgreSQL中rank()窗口函数实用指南与示例》在数据分析和数据库管理中,经常需要对数据进行排名操作,PostgreSQL提供了强大的窗口函数rank(),可以方便地对结果集中的行进行排名... 目录一、rank()函数简介二、基础示例:部门内员工薪资排名示例数据排名查询三、高级应用示例1. 每