最近正在学习Qt,已经学习到无边框窗口相关的内容了,还是记录一些学习心得,这些内容是基于Qt6.10版本的。
1.无边框窗口(基于QWidget)
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);
通过这串代码我们可以构建出一个基本的无边框窗口,但是,它只是一个窗口,什么也做不了,甚至无法拖动和缩放,那么应该如何让窗口“动起来”呢?
首先是窗口的拖动,一般来讲,这个是加在标题栏上的,因为一般的应用都是标题栏处理拖动和一些基本的功能,所以这个可以放在标题栏类中作为功能,它一共有两种实现方式。
1.通过重写Qt中的void mouseMoveEvent(QMouse* event)和void mousePressEvent(QMouse* event)来实现通用的鼠标拖拽功能,代码实现如下:
#include <QMouseEvent>
#include <QtWidgets/QWidget>
class noBorderWindow : public QWidget
{
QOBJECT
public:
noBorderWindow(QWidget* parent = nullptr);
~noBorderWindow();
private:
QPoint diff_pos;//这个是窗口左上角和鼠标的坐标差
QPoint window_pos;//窗口坐标
QPoint mouse_pos;//鼠标坐标
private:
void mousePressEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
}
#include "noBorderWindow.h"
noBorderWindow::noBorderWindow(QWidget* parent)
: QWidget(parent)
{
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);
}
noBorderWindow::~noBorderWindow()
{}
void hand_write_tecent::mousePressEvent(QMouseEvent* event)
{
mouse_pos = event->globalPosition().toPoint();
window_pos = this->pos();
diff_pos = mouse_pos - window_pos;
}//先获取相关坐标,再获得diff_pos,否则重点击时会出现鼠标跳动到上次位置的情况
void hand_write_tecent::mouseMoveEvent(QMouseEvent* event)
{
QPoint pos = event->globalPosition().toPoint();
this->move(pos - diff_pos);
}
这样就可以实现窗口的移动效果了
2.通过windows中的接口实现简洁的窗口移动:
void noBorderWindow::mousePressEvent(QMouseEvent* event)
{
if (ReleaseCapture())
{
QWidget* pWindow = this->window();
if (pWindow->isWindow())
{
SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
}
}
}
ReleaseCapture 是一个 Windows API 函数,释放鼠标捕获。如果一个窗口在捕获鼠标,用户点击其他窗口不会改变鼠标捕获目标。再通过this->window() 返回当前窗口部件的顶级窗口指针。如果此时pWindow是顶部指针,那么就会使用Windows中的SendMessage实现鼠标拖动窗口。其中:
pWindow->winId()返回窗口的系统句柄,将其转换为HWND。WM_SYSCOMMAND是 Windows 消息,表示系统命令。SC_MOVE + HTCAPTION触发窗口的移动操作,将鼠标点击的事件视为标题栏的拖动操作。
这个代码不适用于跨平台的鼠标拖拽哦
接下来是窗口拉伸效果,这个实现了窗口的第二大基础功能,一般可以把它单独封装成一个类用来作为父窗口,Windows的实现一般是重写bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override;方法
#pragma once
#include <QtWidgets/QWidget>
#include <QMouseEvent>
#include <windows.h>
#include <windowsx.h>
class CFrameLessWidgetBase: public QWidget
{
public:
CFrameLessWidgetBase(QWidget* prant = nullptr);
~CFrameLessWidgetBase();
protected:
bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override;
private:
int m_nBorderWidth;//这个是当鼠标位于离窗口边缘多远时拉伸窗口
};
#include "CFrameLessWidgetBase.h"
CFrameLessWidgetBase::CFrameLessWidgetBase(QWidget* prant)
:QWidget(prant),
m_nBorderWidth(5)
{
this->setWindowFlags(Qt::FramelessWindowHint);
this->setAttribute(Qt::WA_Hover);
}
CFrameLessWidgetBase::~CFrameLessWidgetBase()
{
}
bool CFrameLessWidgetBase::nativeEvent(const QByteArray& eventType, void* message, qintptr* result)
{
Q_UNUSED(eventType);
MSG* param = static_cast<MSG*>(message);
if (param->message == WM_NCHITTEST) {
QScreen* screen = QGuiApplication::primaryScreen();
qreal dpiScale = screen->devicePixelRatio();
POINT pt = { GET_X_LPARAM(param->lParam), GET_Y_LPARAM(param->lParam) };
QRect windowRect = this->geometry();
int left = windowRect.x() * dpiScale;
int top = windowRect.y() * dpiScale;
int right = left + windowRect.width() * dpiScale;
int bottom = top + windowRect.height() * dpiScale;
int scaledBorderWidth = static_cast<int>(m_nBorderWidth * dpiScale);
bool inLeft = (pt.x >= left && pt.x < left + scaledBorderWidth);
bool inRight = (pt.x <= right && pt.x > right - scaledBorderWidth);
bool inTop = (pt.y >= top && pt.y < top + scaledBorderWidth);
bool inBottom = (pt.y <= bottom && pt.y > bottom - scaledBorderWidth);
if (inLeft && inTop) {
*result = HTTOPLEFT;
}
else if (inRight && inTop) {
*result = HTTOPRIGHT;
}
else if (inLeft && inBottom) {
*result = HTBOTTOMLEFT;
}
else if (inRight && inBottom) {
*result = HTBOTTOMRIGHT;
}
else if (inLeft) {
*result = HTLEFT;
}
else if (inRight) {
*result = HTRIGHT;
}
else if (inTop) {
*result = HTTOP;
}
else if (inBottom) {
*result = HTBOTTOM;
}
else {
return false;
}
return true;
}
return QWidget::nativeEvent(eventType, message, result);
}
这样就实现了无边框窗口的拉伸,可以把它作为主类的继承父类使用
6189

被折叠的 条评论
为什么被折叠?



