重构无边框窗体,鼠标拖动窗口改变大小功能,使得更加流畅不再依赖windows api

This commit is contained in:
JackLee_CN 2024-11-08 20:39:14 +08:00
parent 414fa36433
commit db02113c2a
4 changed files with 270 additions and 98 deletions

View File

@ -97,34 +97,34 @@ QPushButton#btn_min,QPushButton#btn_max,QPushButton#btn_close{
font: bold 12px; font: bold 12px;
} }
QPushButton#btn_min{ QPushButton#btn_min{
image:url(":/res/img/btn/btn_min.png"); image:url(":/res/img/btn/btn_min.png");
border:none; border:none;
width:25px; width:20px;
height:25px; height:20px;
} }
QPushButton#btn_max{ QPushButton#btn_max{
image:url(":/res/img/btn/btn_max.png"); image:url(":/res/img/btn/btn_max.png");
border:none; border:none;
width:25px; width:20px;
height:25px; height:20px;
} }
QPushButton#btn_max[maximizeProperty='maximize'] { QPushButton#btn_max[maximizeProperty='maximize'] {
image:url(":/res/img/btn/btn_max.png"); image:url(":/res/img/btn/btn_max.png");
border:none; border:none;
width:25px; width:20px;
height:25px; height:20px;
} }
QPushButton#btn_max[maximizeProperty='restore'] { QPushButton#btn_max[maximizeProperty='restore'] {
image:url(":/res/img/btn/btn_max_restore.png"); image:url(":/res/img/btn/btn_max_restore.png");
border:none; border:none;
width:25px; width:20px;
height:25px; height:20px;
} }
QPushButton#btn_close{ QPushButton#btn_close{
image:url(":/res/img/btn/btn_close.png"); image:url(":/res/img/btn/btn_close.png");
border:none; border:none;
width:25px; width:20px;
height:25px; height:20px;
} }
QPushButton#btn_min:hover,QPushButton#btn_max:hover,QPushButton#btn_close:hover{ QPushButton#btn_min:hover,QPushButton#btn_max:hover,QPushButton#btn_close:hover{

View File

@ -73,32 +73,32 @@ QPushButton#btn_min,QPushButton#btn_max,QPushButton#btn_close{
QPushButton#btn_min{ QPushButton#btn_min{
image:url(":/res/img/btn/btn_min.png"); image:url(":/res/img/btn/btn_min.png");
border:none; border:none;
width:25px; width:20px;
height:25px; height:20px;
} }
QPushButton#btn_max{ QPushButton#btn_max{
image:url(":/res/img/btn/btn_max.png"); image:url(":/res/img/btn/btn_max.png");
border:none; border:none;
width:25px; width:20px;
height:25px; height:20px;
} }
QPushButton#btn_max[maximizeProperty='maximize'] { QPushButton#btn_max[maximizeProperty='maximize'] {
image:url(":/res/img/btn/btn_max.png"); image:url(":/res/img/btn/btn_max.png");
border:none; border:none;
width:25px; width:20px;
height:25px; height:20px;
} }
QPushButton#btn_max[maximizeProperty='restore'] { QPushButton#btn_max[maximizeProperty='restore'] {
image:url(":/res/img/btn/btn_max_restore.png"); image:url(":/res/img/btn/btn_max_restore.png");
border:none; border:none;
width:25px; width:20px;
height:25px; height:20px;
} }
QPushButton#btn_close{ QPushButton#btn_close{
image:url(":/res/img/btn/btn_close.png"); image:url(":/res/img/btn/btn_close.png");
border:none; border:none;
width:25px; width:20px;
height:25px; height:20px;
} }
QPushButton#btn_min:hover,QPushButton#btn_max:hover,QPushButton#btn_close:hover{ QPushButton#btn_min:hover,QPushButton#btn_max:hover,QPushButton#btn_close:hover{

View File

@ -6,7 +6,7 @@ sui::sui(QWidget *parent)
m_press(false), m_press(false),
m_border_width(5) m_border_width(5)
{ {
m_title=new sui_title(this); m_title = new sui_title(this);
setObjectName(tr("m_widget")); setObjectName(tr("m_widget"));
m_layout->addWidget(m_title); m_layout->addWidget(m_title);
m_title->setMouseTracking(true); m_title->setMouseTracking(true);
@ -22,7 +22,6 @@ sui::sui(QWidget *parent)
} }
sui::~sui() sui::~sui()
{ {
} }
void sui::showEvent(QShowEvent *event) void sui::showEvent(QShowEvent *event)
{ {
@ -41,78 +40,242 @@ void sui::paintEvent(QPaintEvent *event)
QWidget::paintEvent(event); QWidget::paintEvent(event);
} }
void sui::region(const QPoint &currentGlobalPoint)
{
// 获取窗体在屏幕上的位置区域topLeft为坐上角点rightButton为右下角点
QRect rect = this->rect();
// 将左上角的(0,0)转化为全局坐标
QPoint topLeft = this->mapToGlobal(rect.topLeft());
QPoint rightButton = this->mapToGlobal(rect.bottomRight());
// 当前鼠标的坐标
int x = currentGlobalPoint.x();
int y = currentGlobalPoint.y();
if (((topLeft.x() + m_border_width >= x) && (topLeft.x() <= x)) && ((topLeft.y() + m_border_width >= y) && (topLeft.y() <= y)))
{
// 左上角
ori = LEFTTOP;
// 设置光标形状
this->setCursor(QCursor(Qt::SizeFDiagCursor));
}
else if (((x >= rightButton.x() - m_border_width) && (x <= rightButton.x())) && ((y >= rightButton.y() - m_border_width) && (y <= rightButton.y())))
{
// 右下角
ori = RIGHTBOTTOM;
this->setCursor(QCursor(Qt::SizeFDiagCursor));
}
else if (((x <= topLeft.x() + m_border_width) && (x >= topLeft.x())) && ((y >= rightButton.y() - m_border_width) && (y <= rightButton.y())))
{
// 左下角
ori = LEFTBOTTOM;
this->setCursor(QCursor(Qt::SizeBDiagCursor));
}
else if (((x <= rightButton.x()) && (x >= rightButton.x() - m_border_width)) && ((y >= topLeft.y()) && (y <= topLeft.y() + m_border_width)))
{
// 右上角
ori = RIGHTTOP;
this->setCursor(QCursor(Qt::SizeBDiagCursor));
}
else if ((x <= topLeft.x() + m_border_width) && (x >= topLeft.x()))
{
// 左边
ori = LEFT;
this->setCursor(QCursor(Qt::SizeHorCursor));
}
else if ((x <= rightButton.x()) && (x >= rightButton.x() - m_border_width))
{
// 右边
ori = RIGHT;
this->setCursor(QCursor(Qt::SizeHorCursor));
}
else if ((y >= topLeft.y()) && (y <= topLeft.y() + m_border_width))
{
// 上边
ori = UP;
this->setCursor(QCursor(Qt::SizeVerCursor));
}
else if ((y <= rightButton.y()) && (y >= rightButton.y() - m_border_width))
{
// 下边
ori = DOWN;
this->setCursor(QCursor(Qt::SizeVerCursor));
}
else
{
// 默认
ori = NONE;
this->setCursor(QCursor(Qt::ArrowCursor));
}
}
void sui::mousePressEvent(QMouseEvent *event) void sui::mousePressEvent(QMouseEvent *event)
{ {
if ((event->button() == Qt::LeftButton)) switch (event->button())
{ {
case Qt::LeftButton:
m_press = true; m_press = true;
m_point = (event->globalPosition() - this->pos()).toPoint();
event->accept(); if (ori != NONE)
{
// 返回当前抓取鼠标输入的窗口
this->mouseGrabber();
}
else
{
m_point = event->globalPosition().toPoint() - this->frameGeometry().topLeft();
// globalPos()鼠标位置topLeft()窗口左上角的位置
}
break;
case Qt::RightButton:
this->setWindowState(Qt::WindowMinimized);
break;
default:
QWidget::mousePressEvent(event);
} }
} }
void sui::mouseMoveEvent(QMouseEvent *event) void sui::mouseMoveEvent(QMouseEvent *event)
{ {
if (m_press)
QPoint globalPoint = event->globalPosition().toPoint();
QRect rect = this->rect();
QPoint topLeft = mapToGlobal(rect.topLeft());
QPoint bottomRight = mapToGlobal(rect.bottomRight());
if (this->windowState() != Qt::WindowMaximized)
{ {
move(event->globalPosition().toPoint() - m_point); // 没有按下左键时
event->accept(); if (!m_press)
{
// 窗口大小的改变——判断鼠标位置,改变光标形状
this->region(globalPoint);
}
else
{
if (ori != NONE)
{
QRect newRect(topLeft, bottomRight);
switch (ori)
{
case LEFT:
if (bottomRight.x() - globalPoint.x() <= this->minimumWidth())
{
// 小于界面的最小宽度时设置为左上角横坐标为窗口x
newRect.setLeft(topLeft.x());
// 只改变左边界
}
else
{
newRect.setLeft(globalPoint.x());
}
break;
case RIGHT:
// 只能改变右边界
newRect.setWidth(globalPoint.x() - topLeft.x());
break;
case UP:
if (bottomRight.y() - globalPoint.y() <= this->minimumHeight())
{
newRect.setY(topLeft.y());
}
else
{
newRect.setY(globalPoint.y());
}
break;
case DOWN:
newRect.setHeight(globalPoint.y() - topLeft.y());
break;
case LEFTTOP:
if (bottomRight.x() - globalPoint.x() <= this->minimumWidth())
{
newRect.setX(topLeft.x());
}
else
{
newRect.setX(globalPoint.x());
}
if (bottomRight.y() - globalPoint.y() <= this->minimumHeight())
{
newRect.setY(topLeft.y());
}
else
{
newRect.setY(globalPoint.y());
}
break;
case RIGHTTOP:
if (globalPoint.x() - topLeft.x() >= this->minimumWidth())
{
newRect.setWidth(globalPoint.x() - topLeft.x());
}
else
{
newRect.setWidth(bottomRight.x() - topLeft.x());
}
if (bottomRight.y() - globalPoint.y() >= this->minimumHeight())
{
newRect.setY(globalPoint.y());
}
else
{
newRect.setY(topLeft.y());
}
break;
case LEFTBOTTOM:
if (bottomRight.x() - globalPoint.x() >= this->minimumWidth())
{
newRect.setX(globalPoint.x());
}
else
{
newRect.setX(topLeft.x());
}
if (globalPoint.y() - topLeft.y() >= this->minimumHeight())
{
newRect.setHeight(globalPoint.y() - topLeft.y());
}
else
{
newRect.setHeight(bottomRight.y() - topLeft.y());
}
break;
case RIGHTBOTTOM:
newRect.setWidth(globalPoint.x() - topLeft.x());
newRect.setHeight(globalPoint.y() - topLeft.y());
break;
default:
break;
}
this->setGeometry(newRect);
}
else
{
// 移动窗口
move(event->globalPosition().toPoint() - m_point);
event->accept();
}
}
} }
} }
// 鼠标释放事件
void sui::mouseReleaseEvent(QMouseEvent *event) void sui::mouseReleaseEvent(QMouseEvent *event)
{ {
Q_UNUSED(event) if (event->button() == Qt::LeftButton)
m_press = false;
}
bool sui::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
{
//Q_UNUSED(eventType)
MSG *param = static_cast<MSG *>(message);
switch (param->message)
{ {
case WM_NCHITTEST: m_press = false;
{ if (ori != NONE)
int nX = GET_X_LPARAM(param->lParam) - this->geometry().x(); {
int nY = GET_Y_LPARAM(param->lParam) - this->geometry().y(); // 释放鼠标抓取
this->releaseMouse();
// 如果鼠标位于子控件上,则不进行处理 this->setCursor(QCursor(Qt::ArrowCursor));
if (childAt(nX, nY) != nullptr) ori = NONE;
return QWidget::nativeEvent(eventType, message, result); }
*result = HTCAPTION;
// 鼠标区域位于窗体边框,进行缩放
if ((nX > 0) && (nX < m_border_width))
*result = HTLEFT;
if ((nX > this->width() - m_border_width) && (nX < this->width()))
*result = HTRIGHT;
if ((nY > 0) && (nY < m_border_width))
*result = HTTOP;
if ((nY > this->height() - m_border_width) && (nY < this->height()))
*result = HTBOTTOM;
if ((nX > 0) && (nX < m_border_width) && (nY > 0) && (nY < m_border_width))
*result = HTTOPLEFT;
if ((nX > this->width() - m_border_width) && (nX < this->width()) && (nY > 0) && (nY < m_border_width))
*result = HTTOPRIGHT;
if ((nX > 0) && (nX < m_border_width) && (nY > this->height() - m_border_width) && (nY < this->height()))
*result = HTBOTTOMLEFT;
if ((nX > this->width() - m_border_width) && (nX < this->width()) && (nY > this->height() - m_border_width) && (nY < this->height()))
*result = HTBOTTOMRIGHT;
return true;
} }
}
return QWidget::nativeEvent(eventType, message, result);
} }

View File

@ -2,13 +2,20 @@
#define SUI_H #define SUI_H
#include "common.h" #include "common.h"
#include <QMainWindow>
#ifdef Q_OS_WIN
#include <QWindow>
#include <windowsx.h>
#pragma execution_character_set("utf-8")
#endif
#include "sui_title.h" #include "sui_title.h"
typedef enum {
UP=0,
DOWN=1,
LEFT,
RIGHT,
LEFTTOP,
LEFTBOTTOM,
RIGHTBOTTOM,
RIGHTTOP,
NONE
}Orient;
class sui : public QWidget class sui : public QWidget
{ {
Q_OBJECT Q_OBJECT
@ -16,12 +23,15 @@ public:
explicit sui(QWidget *parent = 0); explicit sui(QWidget *parent = 0);
~sui(); ~sui();
sui_title* title() { return m_title; } sui_title* title() { return m_title; }
void region(const QPoint &currentGlobalPoint); //鼠标的位置,改变光标
private: private:
QVBoxLayout *m_layout; QVBoxLayout *m_layout;
QWidget *m_widget; QWidget *m_widget;
QPoint m_point; QPoint m_point;
bool m_press; bool m_press;
int m_border_width; int m_border_width;
Orient ori;
sui_title *m_title; sui_title *m_title;
protected: protected:
void paintEvent(QPaintEvent *event); void paintEvent(QPaintEvent *event);
@ -29,6 +39,5 @@ protected:
void mouseMoveEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event);
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result);
}; };
#endif // SUI_H #endif // SUI_H