上海古都建筑设计集团,上海办公室装修设计公司,上海装修公司高质量的内容分享社区,上海装修公司我们不是内容生产者,我们只是上海办公室装修设计公司内容的搬运工平台

Qt无边框窗口拖拽和阴影

guduadmin191月前

先看下效果:

Qt无边框窗口拖拽和阴影,在这里插入图片描述,第1张

说明

自定义窗口控件的无边框,窗口事件由于没有系统自带边框,无法实现拖拽拉伸等事件的处理,一种方法就是重新重写主窗口的鼠标事件,一种时通过nativeEvent事件处理。重写事件相对繁琐,我们这里推荐nativeEvent处理。注意后续我们在做win平台的进程通信,也会用到它!

  • 我们这里使用的是:nativeEvent

    软件用到的样式表,这里就不展示了,大家可以自行调整!

    关键点说明

    QPainterPath

    QPainterPath类提供一个容器,可以用来创建图形并且重复使用。绘制器路径是由许多图形构建基块(如矩形、椭圆形、直线和曲线)组成的对象。构建基块可以连接在封闭的子路径中,例如作为矩形或椭圆。封闭路径具有重合的起点和终点。或者它们可以作为未闭合的子路径独立存在,例如直线和曲线。

    抗锯齿

    1. 抗锯齿是一种常见的图形处理技术,用于减少在显示器上呈现的图像中出现的锯齿状边缘。

      抗锯齿技术通过在边缘周围添加额外的像素来平滑边缘,从而减少锯齿状边缘。这种技术基于亚像素级别的渲染,它将颜色逐渐混合到边缘像素的周围像素中,使得边缘更加平滑。

    2. 打开抗锯齿可以使图像更加平滑,尤其是在呈现锐利直线或曲线时。这种技术可以减少锯齿状边缘,使得图像更加清晰,更加真实。特别是在高分辨率屏幕上,抗锯齿可以使得字体更加易读,图像更加细腻。
    3. 虽然抗锯齿可以使图像更加平滑,但在某些情况下,关闭抗锯齿可能更加合适。关闭抗锯齿可以提高图像处理速度。
    4. 这里我们基于Qt绘图框架用的是:
    • setRenderHint(QPainter::Antialiasing, true); //打开抗锯齿
    • setRenderHint(QPainter::Antialiasing, false); //关闭抗锯齿

      具体实现

      CDlgComBase,无边框窗口,带阴影,支持拖拽,注意:

      • 该实现方案不支持存在多个显示屏的情况!
      • 该实现方案仅支持win平台!

        实现无边框带阴影的窗口代码,下面的代码供大家参考:

        DlgComBase.h

        #pragma once
        #include "DlgShadow.h"
        #include "FrameComTitleBar.h"
        #include 
        class CDlgComBase : public CDlgShadow
        {
        	Q_OBJECT
        public:
        	CDlgComBase(QWidget *parent = 0, bool bCenterDlg = true, bool bHasTitleBar = true);
        	~CDlgComBase();
        	void SetWindowsTitle(const QString& strTitle, bool bCheckPos = false);
        	// 显示隐藏按钮
        	void ShowMinBtn(bool bShow);
        	void ShowMaxBtn(bool bShow);
        	void ShowCloseBtn(bool bShow);
        	void ShowSettingBtn(bool bShow);
        	
        	void ShowMaximized();
        	
        	void SetTitleBarObjectName(QString strObjectName);
        	void SetHeadBarHeight(int nHeight);
        protected:
        	virtual bool IsCaption(int nXPos, int nYPos);
        	QWidget* GetCenterWidget() { return &m_frameCenter; }
        	virtual void OnNcLBtnDbClick(int nXPos, int nYPos);
        protected slots:
        	void OnTimerCenter();
        private:
        	CFrameComTitleBar		m_frameComTitleBar;
        	QVBoxLayout				m_vBoxLayout;
        	QFrame					m_frameCenter;
        	bool					m_bHasTitleBar;
        };
        

        DlgComBase.cpp

        #include "DlgComBase.h"
        #include 
        CDlgComBase::CDlgComBase(QWidget *parent, bool bCenterDlg, bool bHasTitleBar)
        : CDlgShadow(parent), m_frameComTitleBar(this), m_frameCenter(this), m_bHasTitleBar(bHasTitleBar)
        {
        	m_frameComTitleBar.setObjectName("framComTitleBar");
        	m_frameComTitleBar.setFixedHeight(GetHeadBarHeight());
        	int nShadowLen = GetShadowLen();
        	m_vBoxLayout.setContentsMargins(nShadowLen, nShadowLen, nShadowLen, nShadowLen);
        	m_vBoxLayout.setSpacing(0);
        	if (m_bHasTitleBar)
        	{
        		m_vBoxLayout.addWidget(&m_frameComTitleBar);
        	}
        	
        	m_vBoxLayout.addWidget(&m_frameCenter);
        	m_frameCenter.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        	setLayout(&m_vBoxLayout);
        	if (bCenterDlg)
        		QTimer::singleShot(10, this, SLOT(OnTimerCenter()));
        }
        CDlgComBase::~CDlgComBase()
        {
        }
        void CDlgComBase::SetWindowsTitle(const QString& strTitle, bool bCheckPos)
        {
        	m_strTitle = strTitle;
        	m_frameComTitleBar.SetWindowsTitle(strTitle, bCheckPos);
        	setWindowTitle(strTitle);
        }
        void CDlgComBase::ShowMinBtn(bool bShow)
        {
        	m_frameComTitleBar.ShowMinBtn(bShow);
        }
        void CDlgComBase::ShowMaxBtn(bool bShow)
        {
        	SetHasMaxFun(bShow);
        	m_frameComTitleBar.ShowMaxBtn(bShow);
        }
        void CDlgComBase::ShowCloseBtn(bool bShow)
        {
        	m_frameComTitleBar.ShowCloseBtn(bShow);
        }
        void CDlgComBase::ShowSettingBtn(bool bShow)
        {
        	m_frameComTitleBar.ShowSettingBtn(bShow);
        }
        bool CDlgComBase::IsCaption(int nXPos, int nYPos)
        {
        	QWidget* pChild = childAt(nXPos, nYPos);
        	if (pChild == NULL)
        	{
        		ADD_LOGD("CDlgComBase::IsCaption() return true");
        		return true;
        	}
        	if (pChild == &m_frameComTitleBar || pChild == m_frameComTitleBar.GetTitleLabel())
        	{
        		ADD_LOGD("CDlgComBase::IsCaption() return true");
        		return true;
        	}
        	ADD_LOGD("CDlgComBase::IsCaption() return false");
        	return false;
        }
        void CDlgComBase::SetTitleBarObjectName(QString strObjectName)
        {
        	m_frameComTitleBar.setObjectName(strObjectName);
        }
        void CDlgComBase::OnTimerCenter()
        {
        	CenterInParent((QWidget*)parent());
        }
        void CDlgComBase::SetHeadBarHeight(int nHeight)
        {
        	m_frameComTitleBar.setFixedHeight(nHeight);
        	CDlgShadow::SetHeadBarHeight(nHeight);
        }
        void CDlgComBase::ShowMaximized()
        {
        	m_frameComTitleBar.ShowMaximized();
        	CDlgShadow::ShowMaximized();
        }
        void CDlgComBase::OnNcLBtnDbClick(int nXPos, int nYPos)
        {
        	if (m_bHasMaxFun)
        		m_frameComTitleBar.ShowMaxRestoreBtn(m_bMaximized);
        	CDlgShadow::OnNcLBtnDbClick(nXPos, nYPos);
        }
        

        DlgShadow.h

        #ifndef SHADOWDLG_H
        #define SHADOWDLG_H
        #include 
        #include 
        class CDlgShadow : public QDialog
        {
        	Q_OBJECT
        public:
        	CDlgShadow(QWidget *parent = 0);
        	~CDlgShadow();
        	void HideDlg();
        	void ShowDlg();
        	void SetDlgBkColor(QColor& clrDlgBk);
        	void CenterInParent(QWidget* pWidget);
        	void SetResizeable(bool bOn) { m_bResizeable = bOn; }
        	virtual void OnBtnSettingClicked(QPoint& ptBtnBottom);
        	virtual void OnBtnMinClicked();
        	virtual void OnBtnMaxClicked();
        	virtual void OnBtnRestoreClicked();
        	virtual void OnBtnCloseClicked();
        	virtual bool OnProHotKey(int nFsModifiers, int nVk);
        	virtual void OnMsgEndSession();
        	void ShowMaximized();
        protected:
        	void paintEvent(QPaintEvent* event);
        	void keyPressEvent(QKeyEvent* event);
        	int GetShadowLen() { return m_nShadowLen; }
        	int GetHeadBarHeight() { return m_nHeadBarHeight; }
        	void SetHeadBarHeight(int nHeight);
        	void SetHasMaxFun(bool bHasMaxFun) { m_bHasMaxFun = bHasMaxFun; }
        	bool nativeEvent(const QByteArray& eventType, void* pMessage, long* pResult);
        	virtual bool IsCaption(int nXPos, int nYPos);
        	virtual void OnNcLBtnDbClick(int nXPos, int nYPos);
        	virtual void OnKeyReturnPress();
        	virtual void OnKeyEscapePress();
        	virtual void OnNcLBtnClick();
        	void closeEvent(QCloseEvent *event);
        protected:
        	int					m_nFrameLen;		// 边框宽度,单位:像素
        	int					m_nShadowLen;		// 阴影宽度,单位:像素
        	int					m_nHeadBarHeight;	// 标题栏高度
        	bool				m_bHasMaxFun;
        	bool				m_bMaximized;
        	bool				m_bNcLBtnClk;
        	bool				m_bHideDlg;
        	QString				m_strTitle;			// 调试时使用
        	bool				m_bHotKey;			// 处理快捷键功能
        private:
        	QRect				m_rectDlg;
        	QColor				m_clrDlgBk;
        	bool				m_bResizeable;
        };
        #endif // SHADOWDLG_H
        

        DlgShadow.cpp

        #include "DlgShadow.h"
        #include 
        #include 
        #include 
        #include 
        #include 
        CDlgShadow::CDlgShadow(QWidget *parent)
        	: QDialog(parent)
        {
        	setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog | Qt::WindowMinimizeButtonHint);
        	setAttribute(Qt::WA_TranslucentBackground);
        	
        	m_nFrameLen = 10;
        	m_nShadowLen = 6;
        	m_nHeadBarHeight = 36;
        	m_bMaximized = false;
        	m_bHasMaxFun = true;
        	m_clrDlgBk = QColor(255, 255, 255);
        	m_bResizeable = true;
        	m_bNcLBtnClk = false;
        	m_bHideDlg = false;
        	m_bHotKey = false;
        }
        CDlgShadow::~CDlgShadow()
        {
        }
        void CDlgShadow::paintEvent(QPaintEvent* event)
        {
        	QPainterPath path;
        	path.setFillRule(Qt::WindingFill);
        	path.addRoundedRect(m_nShadowLen, m_nShadowLen, width() - 2 * m_nShadowLen, height() - 2 * m_nShadowLen, 2, 2);
        	QPainter painter(this);
        	painter.setRenderHint(QPainter::Antialiasing, true);
        	painter.fillPath(path, QBrush(m_clrDlgBk));
        	QColor color(0, 0, 0, 50);
        	for (int i = 0; i < m_nShadowLen; i++)
        	{
        		QPainterPath pathShadow;
        		pathShadow.setFillRule(Qt::WindingFill);
        		pathShadow.addRoundedRect(m_nShadowLen - i, m_nShadowLen - i, width() - (m_nShadowLen - i) * 2, height() - (m_nShadowLen - i) * 2, 2 + i, 2 + i);
        		int nAlpha = 50 - qSqrt(i) * 25;
        		if (nAlpha < 0)
        			nAlpha = 0;
        		color.setAlpha(nAlpha);
        		painter.setPen(color);
        		painter.drawPath(pathShadow);
        	}
        	painter.setRenderHint(QPainter::Antialiasing, false);
        	painter.fillPath(path, QBrush(m_clrDlgBk));
        	QDialog::paintEvent(event);
        }
        void CDlgShadow::OnBtnMinClicked()
        {
        	showMinimized();
        }
        void CDlgShadow::OnBtnMaxClicked()
        {
        	m_bMaximized = true;
        	m_rectDlg = geometry();
        	setGeometry(-m_nShadowLen, -m_nShadowLen, QApplication::desktop()->availableGeometry().width() + m_nShadowLen * 2,
        		QApplication::desktop()->availableGeometry().height() + m_nShadowLen * 2);
        }
        void CDlgShadow::OnBtnRestoreClicked()
        {
        	m_bMaximized = false;
        	setFixedHeight(QWIDGETSIZE_MAX);
        	setGeometry(m_rectDlg);
        }
        void CDlgShadow::SetDlgBkColor(QColor& clrDlgBk)
        {
        	m_clrDlgBk = clrDlgBk;
        }
        void CDlgShadow::SetHeadBarHeight(int nHeight)
        {
        	m_nHeadBarHeight = nHeight; 
        }
        bool CDlgShadow::IsCaption(int nXPos, int nYPos)
        {
        	if (childAt(nXPos, nYPos) == 0)
        	{
        		ADD_LOGD("CDlgShadow::IsCaption() return true");
        		return true;
        	}
        	else
        	{
        		ADD_LOGD("CDlgShadow::IsCaption() return false");
        		return false;
        	}
        }
        bool CDlgShadow::nativeEvent(const QByteArray& eventType, void* pMessage, long* pResult)
        {
        	ADD_LOGD(QString("CDlgShadow::nativeEvent in"));
        	if (m_bHideDlg)
        	{
        		ADD_LOGD(QString("CDlgShadow::nativeEvent out"));
        		return QDialog::nativeEvent(eventType, pMessage, pResult);
        	}
        	const MSG* pMsg = static_cast(pMessage);
        	if (pMsg->message == WM_NCHITTEST)
        	{
        		RECT rect;
        		SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
        		int nWin32Width = rect.right - rect.left;
        		int nWin32Height = rect.bottom - rect.top;
        		int nQtWidth = QApplication::desktop()->availableGeometry().width();
        		int nQtHeight = QApplication::desktop()->availableGeometry().height();
        		int nMsgX = ((int)(short)LOWORD(pMsg->lParam)) * nQtWidth / nWin32Width;
        		int nMsgY = ((int)(short)HIWORD(pMsg->lParam)) * nQtHeight / nWin32Height;
        		int xPos = nMsgX - frameGeometry().x();
        		int yPos = nMsgY - frameGeometry().y();
        		if (IsCaption(xPos, yPos))
        		{
        			*pResult = HTCAPTION;
        		}
        		else
        		{
        			ADD_LOGD(QString("CDlgShadow::nativeEvent out, WM_NCHITTEST pResult:%1").arg(*pResult));
        			return false;
        		}
        		if (!m_bResizeable)
        		{
        			if (*pResult == HTCAPTION)
        			{
        				ADD_LOGD(QString("CDlgShadow::nativeEvent out, WM_NCHITTEST pResult:%1").arg(*pResult));
        				return true;
        			}
        			ADD_LOGD(QString("CDlgShadow::nativeEvent out, WM_NCHITTEST pResult:%1").arg(*pResult));
        			return QDialog::nativeEvent(eventType, pMessage, pResult);
        		}
        		if (xPos > 0 && xPos < m_nFrameLen)
        			*pResult = HTLEFT;
        		if (xPos >(width() - m_nFrameLen) && xPos < (width() - 0))
        			*pResult = HTRIGHT;
        		if (yPos > 0 && yPos < m_nFrameLen)
        			*pResult = HTTOP;
        		if (yPos >(height() - m_nFrameLen) && yPos < (height() - 0))
        			*pResult = HTBOTTOM;
        		if (xPos > 0 && xPos < m_nFrameLen && yPos > 0 && yPos < m_nFrameLen)
        			*pResult = HTTOPLEFT;
        		if (xPos >(width() - m_nFrameLen) && xPos < (width() - 0) && yPos > 0 && yPos < m_nFrameLen)
        			*pResult = HTTOPRIGHT;
        		if (xPos > 0 && xPos < m_nFrameLen && yPos >(height() - m_nFrameLen) && yPos < (height() - 0))
        			*pResult = HTBOTTOMLEFT;
        		if (xPos >(width() - m_nFrameLen) && xPos < (width() - 0) && yPos >(height() - m_nFrameLen) && yPos < (height() - 0))
        			*pResult = HTBOTTOMRIGHT;
        		ADD_LOGD(QString("CDlgShadow::nativeEvent out, WM_NCHITTEST pResult:%1").arg(*pResult));
        		return true;
        	}
        	else if (pMsg->message == WM_NCLBUTTONDBLCLK)
        	{
        		int xPos = ((int)(short)LOWORD(pMsg->lParam)) - frameGeometry().x();
        		int yPos = ((int)(short)HIWORD(pMsg->lParam)) - frameGeometry().y();
        		OnNcLBtnDbClick(xPos, yPos);
        		ADD_LOGD(QString("CDlgShadow::nativeEvent out, WM_NCLBUTTONDBLCLK"));
        		return true;
        	}
        	else if (pMsg->message == WM_NCLBUTTONDOWN)
        	{
        		if (m_bNcLBtnClk)
        		{
        			OnNcLBtnClick();
        		}
        	}
        	else if (pMsg->message == WM_HOTKEY)
        	{
        		if (m_bHotKey)
        		{
        			UINT nFuModifiers = (UINT)LOWORD(pMsg->lParam);  // 模式
        			UINT nVirtKey = (UINT)HIWORD(pMsg->lParam);     // 键值
        			if (OnProHotKey(nFuModifiers, nVirtKey))
        			{
        				ADD_LOGD(QString("CDlgShadow::nativeEvent out, WM_HOTKEY"));
        				return true;
        			}
        		}
        	}
        	else if (pMsg->message == WM_ENDSESSION)
        	{
        		ADD_LOGD(QStringLiteral("截获关机指令1"));
        		OnMsgEndSession();
        	}
        	ADD_LOGD(QString("CDlgShadow::nativeEvent out"));
        	return QDialog::nativeEvent(eventType, pMessage, pResult);
        }
        void CDlgShadow::OnNcLBtnDbClick(int nXPos, int nYPos)
        {
        	if (!m_bHasMaxFun)
        		return;
        	if (nYPos > m_nFrameLen + m_nHeadBarHeight)
        		return;
        	if (m_bMaximized)
        	{
        		OnBtnRestoreClicked();
        	}
        	else
        	{
        		OnBtnMaxClicked();
        	}
        }
        void CDlgShadow::CenterInParent(QWidget* pWidget)
        {
        	int nXPos = 0;
        	int nYPos = 0;
        	if (pWidget == NULL)
        	{
        		nXPos = (QApplication::desktop()->width() - width()) / 2;
        		nYPos = (QApplication::desktop()->height() - height()) / 2;
        	}
        	else
        	{
        		QWidget* pParent = (QWidget*)pWidget->parent();
        // 		if (pParent != NULL)
        // 		{
        // 			//QPoint ptGloba = pWidget->mapToGlobal(QPoint(0, 0));
        // 			nXPos = /*ptGloba.x() + */(pWidget->width() - width()) / 2;
        // 			nYPos = /*ptGloba.y() + */(pWidget->height() - height()) / 2;
        // 		}
        // 		else
        		{
        			QPoint ptGloba = pWidget->mapToGlobal(QPoint(0, 0));
        			nXPos = ptGloba.x() + (pWidget->width() - width()) / 2;
        			nYPos = ptGloba.y() + (pWidget->height() - height()) / 2;
        		}
        	}
        	move(nXPos, nYPos);
        }
        void CDlgShadow::keyPressEvent(QKeyEvent* event)
        {
        	if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return/* || event->key() == Qt::Key_Space*/)
        	{
        		OnKeyReturnPress();
        		event->accept();
        	}
        	else if (event->key() == Qt::Key_Escape)
        	{
        		OnKeyEscapePress();
        		event->ignore();
        	}
        }
        void CDlgShadow::OnKeyReturnPress()
        {
        	//accept();
        }
        void CDlgShadow::OnKeyEscapePress()
        {
        	//reject();
        }
        void CDlgShadow::OnBtnCloseClicked()
        {
        	reject();
        }
        void CDlgShadow::OnBtnSettingClicked(QPoint& ptBtnBottom)
        {
        }
        void CDlgShadow::OnNcLBtnClick()
        {
        }
        void CDlgShadow::HideDlg()
        {
        	m_bHideDlg = true;
        	setWindowOpacity(0);
        }
        void CDlgShadow::ShowDlg()
        {
        	setWindowOpacity(1);
        	m_bHideDlg = false;
        }
        void CDlgShadow::closeEvent(QCloseEvent *event)
        {
        	event->ignore();
        	OnBtnCloseClicked();
        }
        bool CDlgShadow::OnProHotKey(int nFsModifiers, int nVk)
        {
        	return false;
        }
        void CDlgShadow::OnMsgEndSession()
        {
        }
        void CDlgShadow::ShowMaximized()
        {
        	m_bMaximized = true;
        	int nXPos = (QApplication::desktop()->availableGeometry().width() - (1273 + 11)) / 2;
        	int nYPos = (QApplication::desktop()->availableGeometry().height() - (878 + 11)) / 2;
        	int nMaxHeight = QApplication::desktop()->availableGeometry().height() + m_nShadowLen * 2;
        	//setFixedHeight(nMaxHeight);
        	setFixedHeight(QWIDGETSIZE_MAX);
        	m_rectDlg = QRect(nXPos, nYPos, (1273 + 11), (878 + 11));
        	setGeometry(-m_nShadowLen, -m_nShadowLen, QApplication::desktop()->availableGeometry().width() + m_nShadowLen * 2,
        		QApplication::desktop()->availableGeometry().height() + m_nShadowLen * 2);
        }
        

网友评论

搜索
最新文章
热门文章
热门标签
 
 周公解梦大全梦见房屋倒塌  梦见上坟烧纸着火了是什么意思  梦见大难不死是什么意思