插件类,可使得Qt QWidget去除边框,可自由拉伸
/.h
#ifndef COMRESIZER_H
#define COMRESIZER_H
#include
#include
#include
class COMResizer : public QObject
{
Q_OBJECT
public:
explicit COMResizer(QWidget *parent = nullptr);
~COMResizer();
void attach();
void detach();
/**
* @brief 设置移动触发热区
* @param 0值或未设置表示包括全部区域
*/
void setHotspot(const QSize & size);
/*
* 使能缩放窗口宽/高。
* 默认只能移动,不能缩放。
*/
void setResizable(bool width, bool height);
protected:
bool eventFilter(QObject *obj, QEvent *event);
void mouseEnterEvent(QEnterEvent *event);
void mouseMoveEvent(QMouseEvent * event);
void mousePressEvent(QMouseEvent * event);
void mouseReleaseEvent(QMouseEvent * event);
bool keyPressEvent(QKeyEvent *);
void detectResizeMode(const QPoint & pos);
void modifyResizeMode(uint mode);
void moveParentWidget(const QPoint & global);
void resizeParentWidget(const QPoint & global);
QWidget *parentWidget() const;
enum Mode {
None = 0,
Left = 1,
Right = 2,
Up = 3,
LeftUp = Left + Up,
RightUp = Right + Up,
Down,
LeftDown = Left + Down,
RightDown = Right + Down
};
enum State {
Idle, NormalMove, ResizeMove
};
signals:
void sigNormalWidget(bool bNormal);//拖动标题栏,窗体放缩
public slots:
private:
private:
uint mMode;
State mState;
QSize mHotspot;
QRect mBorder;
bool mResizable;
QPoint mSavedPos;
QRect mSavedRect;
bool mbNeedRelocate;//true:窗口需要重定位
};
#endif // COMRESIZER_H
实现cpp
#include "COMResizer.h"
#include
#include
#define BORDER_WIDTH 10
COMResizer::COMResizer(QWidget *parent) :
QObject(parent),
mMode(None),
mState(Idle),
mResizable(false),
mbNeedRelocate(false)
{
parent->setWindowFlags(parent->windowFlags()
|Qt::WindowSystemMenuHint
|Qt::FramelessWindowHint
|Qt::WindowMinMaxButtonsHint);
attach();
// connect(Mask4WinMax::getInstance(),&Mask4WinMax::sigNormalWidget, this, &COMResizer::sigNormalWidget);
mHotspot = QSize(0, 30);//使窗体只有标题栏可以选中拖动
}
COMResizer::~COMResizer()
{
}
void COMResizer::attach()
{
QWidget *parent = parentWidget();
if (!parent->hasMouseTracking())
{
parent->setMouseTracking(true);
parent->installEventFilter(this);
// 状态复位
mState = Idle;
modifyResizeMode(None);
}
}
void COMResizer::detach()
{
QWidget *parent = parentWidget();
if (parent->hasMouseTracking())
{
parent->setMouseTracking(false);
parent->removeEventFilter(this);
}
}
void COMResizer::setHotspot(const QSize &size)
{
mHotspot = size;
}
void COMResizer::setResizable(bool width, bool height)
{
int x = width ? BORDER_WIDTH : 0;
int y = height ? BORDER_WIDTH : 0;
mBorder.setLeft(x);
mBorder.setRight(x);
mBorder.setTop(y);
mBorder.setBottom(y);
mResizable = (width || height);
}
bool COMResizer::eventFilter(QObject *obj, QEvent *event)
{
if (obj == parent())
{
switch(event->type())
{
case QEvent::Enter:
mouseEnterEvent((QEnterEvent*)event);
break;
case QEvent::MouseButtonPress:
mousePressEvent((QMouseEvent*)event);
break;
case QEvent::MouseButtonRelease:
mouseReleaseEvent((QMouseEvent*)event);
break;
case QEvent::MouseMove:
mouseMoveEvent((QMouseEvent*)event);
break;
case QEvent::KeyPress:
return keyPressEvent(dynamic_cast<QKeyEvent*>(event));
}
}
return false;
}
bool COMResizer::keyPressEvent(QKeyEvent *event)
{
if(Qt::Key_Enter == event->key() || Qt::Key_Return == event->key())
{
event->ignore();
return true;
}
return false;
}
void COMResizer::mouseEnterEvent(QEnterEvent *event)
{
detectResizeMode(event->pos());
}
void COMResizer::mouseMoveEvent(QMouseEvent *event)
{
if (mState == Idle)
{
detectResizeMode(event->pos());
}
else if (mState == NormalMove)
{
if(parentWidget()->isMaximized())
{
parentWidget()->showNormal();
emit sigNormalWidget(true);
mbNeedRelocate = true;
}
else
{
if(mbNeedRelocate)
{
//计算对话框重定位后的位置
int newWidth = parentWidget()->geometry().width();
int newHeight = parentWidget()->geometry().height();
int newX = event->globalPos().x() -
(int)(((float)mSavedPos.x()-mSavedRect.left())/mSavedRect.width() * newWidth);
int newY = event->globalPos().y() -
(int)(((float)mSavedPos.y()-mSavedRect.top())/mSavedRect.height() * newHeight);
QRect rcNew = QRect(newX,newY,newWidth, newHeight);
parentWidget()->setGeometry(rcNew);
mSavedPos = event->globalPos();
mSavedRect = rcNew;
mbNeedRelocate = false;
}
else
{
moveParentWidget(event->globalPos());
// Mask4WinMax::getInstance()->SetBuddyWidget(parentWidget());//设置放缩时的遮罩
}
}
}
else if (mState == ResizeMove)
{
resizeParentWidget(event->globalPos());
}
}
void COMResizer::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && mState == Idle)
{
if (mMode != None)
{
mState = ResizeMove;
}
else
{
// 不在热区,不能移动
QPoint pos = event->pos();
if (mHotspot.width() > 0 && pos.x() > mHotspot.width())
{
return;
}
if (mHotspot.height() > 0 && pos.y() > mHotspot.height())
{
return;
}
mState = NormalMove;
}
mSavedPos = event->globalPos();
mSavedRect = parentWidget()->geometry();
}
}
void COMResizer::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
mState = Idle;
modifyResizeMode(None);
}
}
void COMResizer::detectResizeMode(const QPoint &pos)
{
if (!mResizable)
{
return;
}
uint mode = None;
QRect rect = parentWidget()->rect();
if (rect.contains(pos))
{
if (pos.x() < mBorder.left())
{
mode = Left;
}
else if (pos.x() + mBorder.right() > rect.right())
{
mode = Right;
}
if (pos.y() < mBorder.top())
{
mode += Up;
}
else if (pos.y() + mBorder.bottom() > rect.bottom())
{
mode += Down;
}
}
modifyResizeMode(mode);
}
void COMResizer::modifyResizeMode(uint mode)
{
if (mode == mMode)
{
// 拉伸区未变化
return;
}
if (mMode == None)
{
// 首次进入拉伸区,持续接收鼠标消息
parentWidget()->grabMouse();
}
Qt::CursorShape shape = Qt::ArrowCursor;
if (mode == None)
{
// 离开拉伸区
parentWidget()->releaseMouse();
}
else
{
switch(mode)
{
case Left:
case Right:
shape = Qt::SizeHorCursor;
break;
case Up:
case Down:
shape = Qt::SizeVerCursor;
break;
case LeftUp:
case RightDown:
shape = Qt::SizeFDiagCursor;
break;
case RightUp:
case LeftDown:
shape = Qt::SizeBDiagCursor;
break;
default:
break;
}
}
mMode = mode;
parentWidget()->setCursor(QCursor(shape));
}
inline void COMResizer::moveParentWidget(const QPoint &global)
{
QPoint pos = mSavedRect.topLeft()
+ global - mSavedPos;
parentWidget()->move(pos);
}
void COMResizer::resizeParentWidget(const QPoint &global)
{
// 拉伸移动
QRect rect = mSavedRect;
QPoint offset = global - mSavedPos;
switch (mMode)
{
case Left:
rect.setLeft(rect.left() + offset.x());
break;
case Right:
rect.setRight(rect.right() + offset.x());
break;
case Up:
rect.setTop(rect.top() + offset.y());
break;
case Down:
rect.setBottom(rect.bottom() + offset.y());
break;
case LeftUp:
rect.setTop(rect.top() + offset.y());
rect.setLeft(rect.left() + offset.x());
break;
case RightUp:
rect.setTop(rect.top() + offset.y());
rect.setRight(rect.right() + offset.x());
break;
case LeftDown:
rect.setLeft(rect.left() + offset.x());
rect.setBottom(rect.bottom() + offset.y());
break;
case RightDown:
rect.setRight(rect.right() + offset.x());
rect.setBottom(rect.bottom() + offset.y());
break;
default:
break;
}
parentWidget()->setGeometry(rect);
}
inline QWidget *COMResizer::parentWidget() const
{
return static_cast<QWidget *>(QObject::parent());
}
使用方式
```cpp
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
m_resizer(new COMResizer(this))
{
ui->setupUi(this);
this->setStyleSheet("background: yellow");
ui->label->setStyleSheet("background: blue");
m_resizer->setResizable(true, true);
connect(ui->pushButton, &QPushButton::clicked, this, [this]{close();});
connect(ui->pushButton_2, &QPushButton::clicked, this, [this]{close();});
}