Qt 自定义窗口的标题栏,重写鼠标事件实现,关闭隐藏,最大化/最小化,重写窗口事件函数,实现鼠标选中边框拉大拉小,双击标题栏切换窗口最大化和最小化
1、main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
2、widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
// 重写窗口事件函数,实现鼠标选中边框拉大拉小
#include <windows.h>
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
protected:
// 重写鼠标事件,实现(隐藏窗口,最大化/最小化窗口,关闭窗口)
void mousePressEvent(QMouseEvent *event) override; // 重写鼠标按下事件
void mouseMoveEvent(QMouseEvent *event) override; // 重写鼠标移动事件
void mouseReleaseEvent(QMouseEvent *event) override; // 重写鼠标释放事件
// 重写窗口事件函数,实现鼠标选中边框拉大拉小
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
// 双击titleBar切换窗口最大化和最小化,重写mouseDoubleClickEvent函数,这个函数会在鼠标双击事件发生时被调用
void mouseDoubleClickEvent(QMouseEvent *event) override;
/* 1、将函数声明为virtual的作用是允许这两个函数在派生类中被重写(override),
* 因为resizeEvent()和moveEvent()是QWidget类中的虚函数,因此在派生类中也要将其声明为virtual,
* 这样就可以在派生类中重新定义这两个函数,以实现派生类中对窗口大小改变和窗口移动事件的处理
*/
virtual void resizeEvent(QResizeEvent *event);
virtual void moveEvent(QMoveEvent *event);
private:
QWidget *content; // 中央控件
QWidget *titleBar; // 自定义标题栏
bool isPressed; // 鼠标是否按下
QPoint startPos; // 鼠标按下时的位置
QPoint endPos; // 鼠标释放时的位置
int edge; // 窗口边缘宽度
// 声明标题栏槽函数(隐藏窗口,最大化/最小化窗口,关闭窗口)
private slots:
void on_tbn_min_clicked();
void on_tbn_max_clicked();
void on_tbn_close_clicked();
};
#endif // WIDGET_H
3、widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QMouseEvent> // 1、包含QMouseEvent类的头文件
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QDesktopWidget>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
isPressed = false;
edge = 5;
// 设置窗口无边框和透明背景
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
// 2、去除默认的标题栏和边框
// Qt::FramelessWindowHint:这是一个窗口提示,表示窗口没有边框
// Qt::WindowMinimizeButtonHint:这是一个窗口提示,表示窗口有最小化按钮
// Qt::WindowMaximizeButtonHint:这是一个窗口提示,表示窗口有最大化按钮
// Qt::WindowCloseButtonHint:这是一个窗口提示,表示窗口有关闭按钮
//this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
// 创建content容器,放到Widget窗口上
content = new QWidget(this);
// 设置 objectName 属性,QSS 文件中使用 #objectName 来定位到该控件
content->setObjectName("content");
// 设置content的大小策略,就是当窗口大小变化时,content怎么调整自己的大小,第一个参数是水平方向上的策略,第二个参数是垂直方向上的策略
content->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// 设置content的位置和大小,参数是x坐标、y坐标、宽度和高度
content->setGeometry(0, 0, width(), height());
content->setStyleSheet("background-color:red;");
// 在content上创建一个垂直布局,下面的2种方法都可以
// content->setLayout(contentVLayout);
QVBoxLayout *contentVLayout = new QVBoxLayout(content);
// 3、自定义标题栏(隐藏窗口,最大化/最小化窗口,关闭窗口)
// 创建titleBar容器,放到content容器里
// titleBar = new QWidget(content);
titleBar = new QWidget();
titleBar->setObjectName("titleBar");
titleBar->setStyleSheet("background-color:blue;");
// 把titleBar添加到contentVLayout布局中
contentVLayout->addWidget(titleBar);
// 设置对齐方式为顶部对齐,让titleBar显示在垂直布局中的最上面
contentVLayout->setAlignment(titleBar, Qt::AlignTop);
// 设置内容边距为0,让它的子部件紧贴着它的边缘
// 给contentVLayout这个垂直布局设置内边距为0,内边距是指布局和它的子部件之间的空隙
// setContentsMargins()方法4个参数,分别表示左边距,上边距,右边距和下边距
contentVLayout->setContentsMargins(0, 0, 0, 0);
// 水平方向上可以自动扩展,在垂直方向上保持固定大小
titleBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
// 设置标题栏控件的位置和大小
titleBar->setGeometry(0, 0, width(), 60);
// 在titleBar上创建一个水平布局
QHBoxLayout *titleBarHLayout = new QHBoxLayout(titleBar);
// Qt::AlignLeft 水平方向靠左
// Qt::AlignRight 水平方向靠右
// Qt::AlignHCenter 水平方向居中
// Qt::AlignTop 垂直方向靠上
titleBarHLayout->setAlignment(Qt::AlignHCenter);
// 在titleBarHLayout上添加你想要的控件,比如图标、标题、最小化按钮、最大化按钮、关闭按钮等
QLabel *iconLabel = new QLabel(titleBar); // 创建图标标签
iconLabel->setPixmap(QPixmap(":/imagenns/icon.png")); // 设置图标标签的图片
iconLabel->setScaledContents(true); // 设置图标标签的图片自动缩放
iconLabel->setFixedSize(20, 20); // 设置图标标签的固定大小
QLabel *titleLabel = new QLabel(titleBar); // 创建标题标签
titleLabel->setText("QWidget布局"); // 设置标题标签的文本
titleLabel->setFont(QFont("Arial", 12, QFont::Bold)); // 设置标题标签的字体
QPushButton *minButton = new QPushButton(titleBar); // 创建最小化按钮
minButton->setText("-"); // 设置最小化按钮的文本
minButton->setFixedSize(20, 20); // 设置最小化按钮的固定大小
QPushButton *maxButton = new QPushButton(titleBar); // 创建最大化按钮
maxButton->setText("+"); // 设置最大化按钮的文本
maxButton->setFixedSize(20, 20); // 设置最大化按钮的固定大小
QPushButton *closeButton = new QPushButton(titleBar); // 创建关闭按钮
closeButton->setText("x"); // 设置关闭按钮的文本
closeButton->setFixedSize(20, 20); // 设置关闭按钮的固定大小
// 将这些控件添加到水平布局中,并设置合适的间距和弹簧
titleBarHLayout->addWidget(iconLabel); // 将图标标签添加到水平布局中
titleBarHLayout->addSpacing(10); // 添加10像素的间距
titleBarHLayout->addWidget(titleLabel); // 将标题标签添加到水平布局中
titleBarHLayout->addStretch(); // 添加弹簧,使得后面的按钮靠右对齐
titleBarHLayout->addWidget(minButton); // 将最小化按钮添加到水平布局中
titleBarHLayout->addWidget(maxButton); // 将最大化按钮添加到水平布局中
titleBarHLayout->addWidget(closeButton); // 将关闭按钮添加到水平布局中
connect (minButton, SIGNAL (clicked ()), this, SLOT (on_tbn_min_clicked ())); // 连接最小化按钮的信号和槽
connect (maxButton, SIGNAL (clicked ()), this, SLOT (on_tbn_max_clicked ())); // 连接最大化按钮的信号和槽
connect (closeButton, SIGNAL (clicked ()), this, SLOT (on_tbn_close_clicked ())); // 连接关闭按钮的信号和槽
}
Widget::~Widget()
{
delete ui;
}
// 最小化按钮的槽函数
void Widget::on_tbn_min_clicked()
{
// 最小化窗口
showMinimized();
}
// 最大化按钮的槽函数
void Widget::on_tbn_max_clicked()
{
if (isMaximized()) {
// 还原窗口
showNormal();
// 切换图标
qobject_cast<QPushButton *>(sender())->setText("+"); // 使用qobject_cast转换类型,并修改文本
} else {
// 最大化窗口
showMaximized();
qobject_cast<QPushButton *>(sender())->setText("-");
}
}
// 关闭按钮的槽函数
void Widget::on_tbn_close_clicked()
{
close();
}
// 重写鼠标事件,实现窗口的移动
void Widget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) // 如果是左键按下
{
isPressed = true; // 设置鼠标按下标志为真
startPos = event->globalPos(); // 记录鼠标按下时的全局坐标
endPos = this->frameGeometry().topLeft(); // 记录窗口左上角的坐标
}
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
if (isPressed) // 如果鼠标按下
{
QPoint movePos = event->globalPos() - startPos; // 计算鼠标移动的偏移量
this->move(endPos + movePos); // 移动窗口到新的位置
}
}
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) // 如果是左键释放
{
isPressed = false; // 设置鼠标按下标志为假
int x = this->x(); // 获取窗口当前的x坐标
int y = this->y(); // 获取窗口当前的y坐标
// 判断窗口是否超出屏幕边缘,如果超出则调整位置
if (x < 0)
x = 0;
if (y < 0)
y = 0;
if (x + this->width() > QApplication::desktop()->width())
x = QApplication::desktop()->width() - this->width();
if (y + this->height() > QApplication::desktop()->height())
y = QApplication::desktop()->height() - this->height();
this->move(x, y); // 移动窗口到新的位置
}
}
// 鼠标选中窗口边框拉大拉小
bool Widget::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
MSG* msg = (MSG*)message;
switch (msg->message)
{
case WM_NCHITTEST: // 处理鼠标在窗口边缘的事件
{
int xPos = GET_X_LPARAM(msg->lParam) - this->frameGeometry().x(); // 获取鼠标相对于窗口左上角的x坐标
int yPos = GET_Y_LPARAM(msg->lParam) - this->frameGeometry().y(); // 获取鼠标相对于窗口左上角的y坐标
// 根据鼠标位置判断返回值,改变鼠标样式和窗口拉伸方向
if(xPos < edge && yPos < edge) // 左上角
*result = HTTOPLEFT;
else if(xPos < edge && yPos > height() - edge) // 左下角
*result = HTBOTTOMLEFT;
else if(xPos > width() - edge && yPos < edge) // 右上角
*result = HTTOPRIGHT;
else if(xPos > width() - edge && yPos > height() - edge)// 右下角
*result = HTBOTTOMRIGHT;
else if(xPos < edge) // 左边
*result = HTLEFT;
else if(xPos > width() - edge) // 右边
*result = HTRIGHT;
else if(yPos < edge) // 上边
*result = HTTOP;
else if(yPos > height() - edge) // 下边
*result = HTBOTTOM;
else // 其他部分不做处理,返回false,留给其他事件处理器处理
return false;
return true;
}
default:
break;
}
return QWidget::nativeEvent(eventType, message, result); // 将事件传递给父类处理
}
/* 如果要实现widget窗口跟随鼠标拖动并自动跟随窗口缩放,
* 需要在QWidget类中重写resizeEvent()函数和moveEvent()函数
*/
// 在resizeEvent()函数中,重新设置widget窗口的大小和位置
void Widget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event); // 调用父类的resizeEvent()函数
if(this->content) // 判断是否有widget被添加到Material窗口中
{
// 获取Material窗口的大小
int w = this->width();
int h = this->height();
// 设置widget的大小为Material窗口的大小
this->content->setGeometry(0, 0, w, h);
}
}
// 在moveEvent()函数中,重新设置widget窗口的位置
void Widget::moveEvent(QMoveEvent *event)
{
QWidget::moveEvent(event);
if(this->content)
{
this->content->move(0, 0);
}
}
// 双击titleBar切换窗口最大化和最小化,重写mouseDoubleClickEvent函数,这个函数会在鼠标双击事件发生时被调用
void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
// 如果是左键双击
if (event->button() == Qt::LeftButton)
{
// 获取父窗口的指针
QWidget *pWindow = this->window();
// 判断当前是否是最大化状态
if (pWindow->isMaximized())
{
// 如果是,恢复到正常大小
pWindow->showNormal();
}
else
{
// 如果不是,最大化窗口
pWindow->showMaximized();
}
}
}
4、效果展示文章来源:https://www.toymoban.com/news/detail-577034.html
5、完成文章来源地址https://www.toymoban.com/news/detail-577034.html
到了这里,关于Qt 自定义窗口的标题栏,重写鼠标事件实现,关闭隐藏,最大化/最小化,重写窗口事件函数,实现鼠标选中边框拉大拉小,双击标题栏切换窗口最大化和最小化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!