Qt之通用无边框基类

1 篇文章 0 订阅

通用无边框基类

通用无边框基类指的是不管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>
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值