通用无边框基类指的是不管QWidget或者QDialog都能直接继承使用,实现这个要去需要引入模板类
代码
#ifndef FRAMELESSWINDOW_H
#define FRAMELESSWINDOW_H
#include <QWidget>
#include <QMouseEvent>
#include <QPoint>
template<typename T>
class FramelessWindow : public T
{
enum MouseRegion
{
Top = 0,
RightTop,
Right,
RightBottom,
Bottom,
LeftBottom,
Left,
LeftTop,
Inner,
Unknown
};
public:
explicit FramelessWindow(QWidget* parent = 0);
~FramelessWindow();
public:
// 设置四周边框宽度
void setBorderWidth(int top, int right, int bottom, int left);
void setMoveEnable(bool enable);
void setResizeEnable(bool enable);
protected:
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void resizeEvent(QResizeEvent *);
void leaveEvent(QEvent *);
void closeEvent(QCloseEvent *event);
private:
void updateGeometry(int x, int y, int w, int h);
void updateCursor(MouseRegion regionType);
void makeRegions();
int hitTest(const QPoint& pos);
void startCursorTimer();
void stopCursorTimer();
protected:
bool isSupportResize;
bool isLeftMousePressed;
QPoint pressPosGlobal;
QPoint pressPosLocal;
MouseRegion mRegionPressed;
QRect mGeoOld;
int mLeftPadding;
int mRightPadding;
int mTopPadding;
int mBottomPadding;
QRect mAllRigions[9];
int basePadding;
int mCursorTimerId;
bool mMoveEnable; //是否可移动
bool mResizeEnable; //是否可缩放
};
template<typename T>
void FramelessWindow<T>::setResizeEnable(bool enable)
{
mResizeEnable = enable;
}
template<typename T>
void FramelessWindow<T>::setMoveEnable(bool enable)
{
mMoveEnable = enable;
}
template<typename T>
FramelessWindow<T>::FramelessWindow(QWidget *parent)
: T(parent)
, basePadding(8)
, mCursorTimerId(0)
, isSupportResize(false)
, mMoveEnable(true)
, mResizeEnable(false)
{
mRegionPressed = Unknown;
isLeftMousePressed = false;
T::setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowStaysOnTopHint);
T::setMouseTracking(true);
setBorderWidth(basePadding, basePadding, basePadding, basePadding);
}
template<typename T>
FramelessWindow<T>::~FramelessWindow()
{
}
template<typename T>
void FramelessWindow<T>::setBorderWidth(int top, int right, int bottom, int left)
{
mTopPadding = top;
mRightPadding = right;
mBottomPadding = bottom;
mLeftPadding = left;
makeRegions();
}
template<typename T>
void FramelessWindow<T>::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
isLeftMousePressed = true;
pressPosGlobal = event->globalPos();
pressPosLocal = event->globalPos() - this->frameGeometry().topLeft();
mRegionPressed = (MouseRegion)hitTest(event->pos());
mGeoOld = QWidget::geometry();
event->accept();
}
}
template<typename T>
void FramelessWindow<T>::closeEvent(QCloseEvent * event)
{
}
template<typename T>
void FramelessWindow<T>::mouseMoveEvent(QMouseEvent *event)
{
if (mResizeEnable)
{
MouseRegion regionType = (MouseRegion)hitTest(event->pos());
updateCursor(regionType);
}
QPoint gloPoint = event->globalPos();
if (isLeftMousePressed && mMoveEnable)
{
if (mRegionPressed == Inner)
{
//move是将窗口的左上点移动到一个全局坐标位置,所以必须算上左上点坐标,但是此时的左上点和鼠标按下时已经不一样。必须在鼠标
//按下时就已经将左上点的全局坐标考虑在内
//使用setGeometry效率太差
T::move(gloPoint - pressPosLocal);
}
}
if (isLeftMousePressed && mResizeEnable)
{
if (mRegionPressed == Top)
{
int dY = gloPoint.y() - pressPosGlobal.y();
updateGeometry(mGeoOld.x(), mGeoOld.y() + dY, mGeoOld.width(), mGeoOld.height() - dY);
}
else if (mRegionPressed == RightTop)
{
QPoint dP = gloPoint - pressPosGlobal;
updateGeometry(mGeoOld.x(), mGeoOld.y() + dP.y(), mGeoOld.width() + dP.x(), mGeoOld.height() - dP.y());
}
else if (mRegionPressed == Right)
{
int dX = gloPoint.x() - pressPosGlobal.x();
updateGeometry(mGeoOld.x(), mGeoOld.y(), mGeoOld.width() + dX, mGeoOld.height());
}
else if (mRegionPressed == RightBottom)
{
QPoint dP = gloPoint - pressPosGlobal;
updateGeometry(mGeoOld.x(), mGeoOld.y(), mGeoOld.width() + dP.x(), mGeoOld.height() + dP.y());
}
else if (mRegionPressed == Bottom)
{
int dY = gloPoint.y() - pressPosGlobal.y();
updateGeometry(mGeoOld.x(), mGeoOld.y(), mGeoOld.width(), mGeoOld.height() + dY);
}
else if (mRegionPressed == LeftBottom)
{
QPoint dP = gloPoint - pressPosGlobal;
updateGeometry(mGeoOld.x() + dP.x(), mGeoOld.y(), mGeoOld.width() - dP.x(), mGeoOld.height() + dP.y());
}
else if (mRegionPressed == Left)
{
int dX = gloPoint.x() - pressPosGlobal.x();
updateGeometry(mGeoOld.x() + dX, mGeoOld.y(), mGeoOld.width() - dX, mGeoOld.height());
}
else if (mRegionPressed == LeftTop)
{
QPoint dP = gloPoint - pressPosGlobal;
updateGeometry(mGeoOld.x() + dP.x(), mGeoOld.y() + dP.y(), mGeoOld.width() - dP.x(), mGeoOld.height() - dP.y());
}
}
}
template<typename T>
void FramelessWindow<T>::resizeEvent(QResizeEvent *)
{
makeRegions();
}
template<typename T>
void FramelessWindow<T>::leaveEvent(QEvent *)
{
this->setCursor(QCursor(Qt::ArrowCursor));
}
template<typename T>
void FramelessWindow<T>::makeRegions()
{
int width = this->width();
int height = this->height();
mAllRigions[Top] = QRect(mLeftPadding, 0, width - mLeftPadding - mRightPadding, mTopPadding);
mAllRigions[RightTop] = QRect(width - mRightPadding, 0, mRightPadding, mTopPadding);
mAllRigions[Right] = QRect(width - mRightPadding, mTopPadding, mRightPadding, height - mTopPadding - mBottomPadding);
mAllRigions[RightBottom] = QRect(width - mRightPadding, height - mBottomPadding, mRightPadding, mBottomPadding);
mAllRigions[Bottom] = QRect(mLeftPadding, height - mBottomPadding, width - mLeftPadding - mRightPadding, mBottomPadding);
mAllRigions[LeftBottom] = QRect(0, height - mBottomPadding, mLeftPadding, mBottomPadding);
mAllRigions[Left] = QRect(0, mTopPadding, mLeftPadding, height - mTopPadding - mBottomPadding);
mAllRigions[LeftTop] = QRect(0, 0, mLeftPadding, mTopPadding);
mAllRigions[Inner] = QRect(mLeftPadding, mTopPadding, width - mLeftPadding - mRightPadding, height - mTopPadding - mBottomPadding);
}
template<typename T>
int FramelessWindow<T>::hitTest(const QPoint &pos)
{
for (int i = 0; i < 9; i++)
{
const QRect rect = mAllRigions[i];
if (rect.contains(pos))
{
return FramelessWindow::MouseRegion(i);
}
}
return Unknown;
}
template<typename T>
void FramelessWindow<T>::startCursorTimer()
{
stopCursorTimer();
mCursorTimerId = this->startTimer(50);
}
template<typename T>
void FramelessWindow<T>::stopCursorTimer()
{
if (mCursorTimerId != 0)
{
this->killTimer(mCursorTimerId);
mCursorTimerId = 0;
}
}
template<typename T>
void FramelessWindow<T>::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
isLeftMousePressed = false;
if (mRegionPressed != Unknown)
{
this->releaseMouse();
this->setCursor(QCursor(Qt::ArrowCursor));
}
}
}
template<typename T>
void FramelessWindow<T>::updateGeometry(int x, int y, int w, int h)
{
int minWidth = this->minimumWidth();
int minHeight = this->minimumHeight();
int maxWidth = this->maximumWidth();
int maxHeight = this->maximumHeight();
if (w < minWidth || w > maxWidth || h < minHeight || h > maxHeight)
{
return;
}
this->setGeometry(x, y, w, h);
}
template<typename T>
void FramelessWindow<T>::updateCursor(MouseRegion regionType)
{
switch (regionType)
{
case Top:
case Bottom:
this->setCursor(Qt::SizeVerCursor);
break;
case RightTop:
case LeftBottom:
this->setCursor(Qt::SizeBDiagCursor);
break;
case Right:
case Left:
this->setCursor(Qt::SizeHorCursor);
break;
case RightBottom:
case LeftTop:
this->setCursor(Qt::SizeFDiagCursor);
break;
default:
this->setCursor(Qt::ArrowCursor);
break;
}
}
#endif // FRAMELESSWINDOW_H
调用
#include "framelesswindow.h"
//QWidget
class widget : public FramelessWindow<QWidget>
//QDialog
class dialog: public FramelessWindow<QDialog>