Qt無邊框窗口拖拽和陰影的實現(xiàn)
先看下效果:
說明
自定義窗口控件的無邊框,窗口事件由于沒有系統(tǒng)自帶邊框,無法實現(xiàn)拖拽拉伸等事件的處理,一種方法就是重新重寫主窗口的鼠標事件,一種時通過nativeEvent事件處理。重寫事件相對繁瑣,我們這里推薦nativeEvent處理。注意后續(xù)我們在做win平臺的進程通信,也會用到它!
我們這里使用的是:nativeEvent
軟件用到的樣式表,這里就不展示了,大家可以自行調(diào)整!
關鍵點說明
QPainterPath
QPainterPath類提供一個容器,可以用來創(chuàng)建圖形并且重復使用。繪制器路徑是由許多圖形構(gòu)建基塊(如矩形、橢圓形、直線和曲線)組成的對象。構(gòu)建基塊可以連接在封閉的子路徑中,例如作為矩形或橢圓。封閉路徑具有重合的起點和終點?;蛘咚鼈兛梢宰鳛槲撮]合的子路徑獨立存在,例如直線和曲線。
抗鋸齒
抗鋸齒是一種常見的圖形處理技術,用于減少在顯示器上呈現(xiàn)的圖像中出現(xiàn)的鋸齒狀邊緣。
抗鋸齒技術通過在邊緣周圍添加額外的像素來平滑邊緣,從而減少鋸齒狀邊緣。這種技術基于亞像素級別的渲染,它將顏色逐漸混合到邊緣像素的周圍像素中,使得邊緣更加平滑。
打開抗鋸齒可以使圖像更加平滑,尤其是在呈現(xiàn)銳利直線或曲線時。這種技術可以減少鋸齒狀邊緣,使得圖像更加清晰,更加真實。特別是在高分辨率屏幕上,抗鋸齒可以使得字體更加易讀,圖像更加細膩。
雖然抗鋸齒可以使圖像更加平滑,但在某些情況下,關閉抗鋸齒可能更加合適。關閉抗鋸齒可以提高圖像處理速度。
這里我們基于Qt繪圖框架用的是:
- setRenderHint(QPainter::Antialiasing, true); //打開抗鋸齒
- setRenderHint(QPainter::Antialiasing, false); //關閉抗鋸齒
具體實現(xiàn)
CDlgComBase,無邊框窗口,帶陰影,支持拖拽,注意:
- 該實現(xiàn)方案不支持存在多個顯示屏的情況!
- 該實現(xiàn)方案僅支持win平臺!
實現(xiàn)無邊框帶陰影的窗口代碼,下面的代碼供大家參考:
DlgComBase.h
#pragma once #include "DlgShadow.h" #include "FrameComTitleBar.h" #include <QVBoxLayout> 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 <QTimer> 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 <QDialog> #include <QMouseEvent> 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; // 邊框?qū)挾龋瑔挝唬合袼? int m_nShadowLen; // 陰影寬度,單位:像素 int m_nHeadBarHeight; // 標題欄高度 bool m_bHasMaxFun; bool m_bMaximized; bool m_bNcLBtnClk; bool m_bHideDlg; QString m_strTitle; // 調(diào)試時使用 bool m_bHotKey; // 處理快捷鍵功能 private: QRect m_rectDlg; QColor m_clrDlgBk; bool m_bResizeable; }; #endif // SHADOWDLG_H
DlgShadow.cpp
#include "DlgShadow.h" #include <QPainter> #include <qmath.h> #include <QApplication> #include <QDesktopWidget> #include <Windows.h> 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<MSG*>(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); }
到此這篇關于Qt無邊框窗口拖拽和陰影的實現(xiàn)的文章就介紹到這了,更多相關Qt無邊框窗口拖拽和陰影內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++?MiniZip實現(xiàn)目錄壓縮與解壓的示例詳解
Zlib是一個開源的數(shù)據(jù)壓縮庫,提供了一種通用的數(shù)據(jù)壓縮和解壓縮算法,本文主要為大家詳細介紹了如何利用Zlib實現(xiàn)目錄壓縮與解壓,需要的小伙伴可以參考下2023-11-11