往期回顾:
【QT入门】 设计实现无边框窗口拉伸的公用类
我们想要做的就是把实现无边框窗口边框拉伸这一功能抽象出来,设计为一个公用类,这样需要的时候我们直接派生这个类就可以了。
一、如何派生
只需要在主类的.h文件和.cpp文件里简单修改一下派生的类就行,这个基础要知道。
1、MainWidget.h
class MainWidget : public CFrameLessWidgetBase
{
Q_OBJECT
public:
MainWidget(QWidget *parent = Q_NULLPTR);
MainWidget();
};
2、MainWidget.cpp
MainWidget::MainWidget(QWidget *parent)
: CFrameLessWidgetBase(parent)
{
initUI();
}
二、 公用类实现
这一块的逻辑实现我也写了注释,大家可以看一看,看不明白也没事,先会用。
1、CFrameLessWidgetBase.h
#pragma once
#include <QWidget>
class CFrameLessWidgetBase :
public QWidget
{
public:
CFrameLessWidgetBase(QWidget* p = nullptr);
~CFrameLessWidgetBase() {}
protected:
bool nativeEvent(const QByteArray& eventType, void* message, long* result) override;
private:
int m_nBorderWidth = 5;
};
2、CFrameLessWidgetBase.cpp
#include "CFrameLessWidgetBase.h"
#include <qt_windows.h>
#include <windows.h>
#include <windowsx.h>
#include <QDebug>
#pragma comment(lib, "user32.lib")
#pragma comment(lib,"dwmapi.lib")
CFrameLessWidgetBase::CFrameLessWidgetBase(QWidget* p)
:QWidget(p)
{
//this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
setAttribute(Qt::WA_Hover); //避免因多个部件无法识别
}
bool CFrameLessWidgetBase::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
MSG* param = static_cast<MSG*>(message);//将void*类型的message转换为MSG*类型,以便获取消息参数。
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 > m_nBorderWidth && nX < this->width() - m_nBorderWidth &&
nY > m_nBorderWidth && nY < this->height() - m_nBorderWidth)
{
qDebug() << "in the title ";
//检查鼠标位置是否在子控件上,如果是,则调用QWidget的nativeEvent函数进行处理。
if (childAt(nX, nY) != nullptr)
return QWidget::nativeEvent(eventType, message, result);
}
//根据鼠标位置的不同,设置*result为对应的窗口调整消息
if ((nX > 0) && (nX < m_nBorderWidth))
*result = HTLEFT;
if ((nX > this->width() - m_nBorderWidth) && (nX < this->width()))
*result = HTRIGHT;
if ((nY > 0) && (nY < m_nBorderWidth))
*result = HTTOP;
if ((nY > this->height() - m_nBorderWidth) && (nY < this->height()))
*result = HTBOTTOM;
//根据鼠标位置的不同,设置*result为对应的窗口角落调整消息
if ((nX > 0) && (nX < m_nBorderWidth) && (nY > 0)
&& (nY < m_nBorderWidth))
*result = HTTOPLEFT;
if ((nX > this->width() - m_nBorderWidth) && (nX < this->width())
&& (nY > 0) && (nY < m_nBorderWidth))
*result = HTTOPRIGHT;
if ((nX > 0) && (nX < m_nBorderWidth)
&& (nY > this->height() - m_nBorderWidth) && (nY < this->height()))
*result = HTBOTTOMLEFT;
if ((nX > this->width() - m_nBorderWidth) && (nX < this->width())
&& (nY > this->height() - m_nBorderWidth) && (nY < this->height()))
*result = HTBOTTOMRIGHT;
//返回true表示已经处理了该消息
return true;
}
}
//如果没有匹配到特定消息类型,会执行return false; ,表示未处理该消息
return false;
}
后面大家在需要实现无边框窗口拉伸功能的时候,直接把CFrameLessWidgetBase类添加进去,并派生就行。
都看到这里了,点个赞再走呗朋友~
加油吧,预祝大家变得更强!