<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Qt實戰6.萬能的無邊框窗口(FramelessWindow)

      1 需求描述

      1. 實現一個Qt無邊框窗口,自定義最大化、最小化、關閉按鈕;
      2. 窗口支持任意拉伸、移動,支持邊框陰影;
      3. 窗口能夠集成任意其它窗口到內部形成一個整體。

      2 設計思路

      最初實現無邊框的目標只有一個,即簡單好用。所有實現基于Qt本身,現將窗口分為三層,如圖:

      外層和內容層均使用垂直布局,使窗口拉伸時能夠自動適應大小。下面對每一層做個簡單說明。

      2.1 XWidget

      作為窗口的最外層,設置為透明,為內層ContentWidget邊框設置、陰影顯示提供支持。同時根據位置設置光標形狀(CursorShape),實現窗口的任意拉伸。

      2.2 ContentWidget

      作為內容包含層,可設置邊框顏色、寬度、圓角、陰影等效果,同時增加最大化、最小化、關閉按鈕,以及logo、軟件名稱顯示部件。

      2.3 CentralWidget

      作為外部嵌入層,XWidget提供一個接口void setCentralWidget(QWidget *widget),將其它窗口集成到ContentWidget內部形成一個整體,這個與QMainWindow類似。

      3 代碼實現

      1. 首先,隱藏標題欄、啟用樣式表,XWidget背景透明,代碼如下:
      setWindowFlags(Qt::FramelessWindowHint);    //隱藏標題欄(無邊框)
      setAttribute(Qt::WA_StyledBackground);      //啟用樣式背景繪制
      setAttribute(Qt::WA_TranslucentBackground); //背景透明
      
      1. 為了實現鼠標的位置信息獲取不受子控件的影響,啟動鼠標懸浮追蹤,代碼如下:
      setAttribute(Qt::WA_Hover);
      
      1. 隨后便可以在event事件處理函數中獲取到懸浮事件,將其轉換為鼠標移動事件進行統一處理,代碼如下:
      bool XWidget::event(QEvent *event)
      {
          if (event->type() == QEvent::HoverMove) {
              QHoverEvent *hoverEvent = static_cast<QHoverEvent *>(event);
              QMouseEvent mouseEvent(QEvent::MouseMove, hoverEvent->pos(),
                                     Qt::NoButton, Qt::NoButton, Qt::NoModifier);
              mouseMoveEvent(&mouseEvent);
          }
      
          return QWidget::event(event);
      }
      
      1. 進入鼠標移動事件,根據坐標設置鼠標對應的形狀,如果鼠標為按下狀態且到達XWidget邊界則拉伸窗口,否則只移動窗口,代碼如下:

      m_bIsPressed 是否按下鼠標
      m_bIsResizing 是否正在調整窗口,調整窗口大小時不移動窗口

      void XWidget::mousePressEvent(QMouseEvent *event)
      {
          if (event->button() == Qt::LeftButton) {
              m_bIsPressed = true;
              m_pressPoint = event->globalPos();
          }
      
          return QWidget::mousePressEvent(event);
      }
      
      void XWidget::mouseMoveEvent(QMouseEvent *event)
      {
          if (m_bIsPressed) {
              if (m_bIsResizing) {
                  m_movePoint = event->globalPos() - m_pressPoint;
                  m_pressPoint += m_movePoint;
              } else {
                  if (!m_bIsDoublePressed && windowState() == Qt::WindowMaximized) {
                      restoreWidget();
                      QPointF point(width() * ((double)(event->globalPos().x())/QApplication::desktop()->width()),
                                    height() * ((double)(event->globalPos().y())/QApplication::desktop()->height()));
      
                      move(event->globalPos() - point.toPoint());
      
                      m_pressPoint = event->globalPos();
                  }
      
                  QPoint point = event->globalPos() - m_pressPoint;
                  move(pos() + point);
      
                  m_pressPoint = event->globalPos();
              }
          }
      
          if (windowState() != Qt::WindowMaximized) {
              updateRegion(event);
          }
      
          QWidget::mouseMoveEvent(event);
      }
      
      void XWidget::updateRegion(QMouseEvent *event)
      {
          QRect mainRect = geometry();
      
          int marginTop = event->globalY() - mainRect.y();
          int marginBottom = mainRect.y() + mainRect.height() - event->globalY();
          int marginLeft = event->globalX() - mainRect.x();
          int marginRight = mainRect.x() + mainRect.width() - event->globalX();
      
          if (!m_bIsResizing) {
              if ( (marginRight >= MARGIN_MIN_SIZE && marginRight <= MARGIN_MAX_SIZE)
                   && ((marginBottom <= MARGIN_MAX_SIZE) && marginBottom >= MARGIN_MIN_SIZE) ) {
                  m_direction = BOTTOMRIGHT;
                  setCursor(Qt::SizeFDiagCursor);
              } else if ( (marginTop >= MARGIN_MIN_SIZE && marginTop <= MARGIN_MAX_SIZE)
                          && (marginRight >= MARGIN_MIN_SIZE && marginRight <= MARGIN_MAX_SIZE)) {
                  m_direction = TOPRIGHT;
                  setCursor(Qt::SizeBDiagCursor);
              } else if ( (marginLeft >= MARGIN_MIN_SIZE && marginLeft <= MARGIN_MAX_SIZE)
                          && (marginTop >= MARGIN_MIN_SIZE && marginTop <= MARGIN_MAX_SIZE) ) {
                  m_direction = TOPLEFT;
                  setCursor(Qt::SizeFDiagCursor);
              } else if ( (marginLeft >= MARGIN_MIN_SIZE && marginLeft <= MARGIN_MAX_SIZE)
                          && (marginBottom >= MARGIN_MIN_SIZE && marginBottom <= MARGIN_MAX_SIZE)) {
                  m_direction = BOTTOMLEFT;
                  setCursor(Qt::SizeBDiagCursor);
              } else if (marginBottom <= MARGIN_MAX_SIZE && marginBottom >= MARGIN_MIN_SIZE) {
                  m_direction = DOWN;
                  setCursor(Qt::SizeVerCursor);
              } else if (marginLeft <= MARGIN_MAX_SIZE - 1 && marginLeft >= MARGIN_MIN_SIZE - 1) {
                  m_direction = LEFT;
                  setCursor(Qt::SizeHorCursor);
              } else if (marginRight <= MARGIN_MAX_SIZE && marginRight >= MARGIN_MIN_SIZE) {
                  m_direction = RIGHT;
                  setCursor(Qt::SizeHorCursor);
              } else if (marginTop <= MARGIN_MAX_SIZE && marginTop >= MARGIN_MIN_SIZE) {
                  m_direction = UP;
                  setCursor(Qt::SizeVerCursor);
              } else {
                  if (!m_bIsPressed) {
                      setCursor(Qt::ArrowCursor);
                  }
              }
          }
      
          if (NONE != m_direction) {
              m_bIsResizing = true;
              resizeRegion(marginTop, marginBottom, marginLeft, marginRight);
          }
      }
      

      不要看著代碼多就感覺復雜,上面其實就干了一件事,判斷鼠標是否達到邊框限定位置,達到了就把方向記錄下來。

      void XWidget::resizeRegion(int marginTop, int marginBottom,
                                     int marginLeft, int marginRight)
      {
          if (m_bIsPressed) {
              switch (m_direction) {
              case BOTTOMRIGHT:
              {
                  QRect rect = geometry();
                  rect.setBottomRight(rect.bottomRight() + m_movePoint);
                  setGeometry(rect);
              }
                  break;
              case TOPRIGHT:
              {
                  if (marginLeft > minimumWidth() && marginBottom > minimumHeight()) {
                      QRect rect = geometry();
                      rect.setTopRight(rect.topRight() + m_movePoint);
                      setGeometry(rect);
                  }
              }
                  break;
              case TOPLEFT:
              {
                  if (marginRight > minimumWidth() && marginBottom > minimumHeight()) {
                      QRect rect = geometry();
                      rect.setTopLeft(rect.topLeft() + m_movePoint);
                      setGeometry(rect);
                  }
              }
                  break;
              case BOTTOMLEFT:
              {
                  if (marginRight > minimumWidth() && marginTop> minimumHeight()) {
                      QRect rect = geometry();
                      rect.setBottomLeft(rect.bottomLeft() + m_movePoint);
                      setGeometry(rect);
                  }
              }
                  break;
              case RIGHT:
              {
                  QRect rect = geometry();
                  rect.setWidth(rect.width() + m_movePoint.x());
                  setGeometry(rect);
              }
                  break;
              case DOWN:
              {
                  QRect rect = geometry();
                  rect.setHeight(rect.height() + m_movePoint.y());
                  setGeometry(rect);
              }
                  break;
              case LEFT:
              {
                  if (marginRight > minimumWidth()) {
                      QRect rect = geometry();
                      rect.setLeft(rect.x() + m_movePoint.x());
                      setGeometry(rect);
                  }
              }
                  break;
              case UP:
              {
                  if (marginBottom > minimumHeight()) {
                      QRect rect = geometry();
                      rect.setTop(rect.y() + m_movePoint.y());
                      setGeometry(rect);
                  }
              }
                  break;
              default:
              {
              }
                  break;
              }
          } else {
              m_bIsResizing = false;
              m_direction = NONE;
          }
      }
      

      同樣的,上面這段代碼也只干了一件事,如果鼠標達到了邊框限定位置,并且按下了鼠標按鍵,就跟著改變窗口大小。

      1. 對標記成員進行重置,代碼如下:
      void XWidget::mouseReleaseEvent(QMouseEvent *event)
      {
          if (event->button() == Qt::LeftButton) {
              m_bIsPressed = false;
              m_bIsResizing = false;
              m_bIsDoublePressed = false;
          }
      
          QWidget::mouseReleaseEvent(event);
      }
      
      void XWidget::leaveEvent(QEvent *event)
      {
          m_bIsPressed = false;
          m_bIsDoublePressed = false;
          m_bIsResizing = false;
      
          QWidget::leaveEvent(event);
      }
      
      1. 最后實現ContentWidget邊框陰影效果,代碼如下:
      void XWidget::createShadow()
      {
          QGraphicsDropShadowEffect *shadowEffect = new QGraphicsDropShadowEffect(this);
          shadowEffect->setColor(Qt::black);
          shadowEffect->setOffset(0, 0);
          shadowEffect->setBlurRadius(13);
          ui->widgetContent->setGraphicsEffect(shadowEffect);
      }
      

      此方法雖有效,會損耗性能,復雜界面不建議使用。

      1. 由于ContentWidget和XWidget之間有間距,最大化時可能不能占滿全屏,手動處理下,最大化時邊距設為0,還原時恢復即可,代碼如下:
      void XWidget::maximizeWidget()
      {
          ui->pushButtonRestore->show();
          ui->pushButtonMax->hide();
      
          ui->verticalLayoutShadow->setContentsMargins(0, 0, 0, 0);
      
          showMaximized();
      }
      
      void XWidget::restoreWidget()
      {
          ui->pushButtonRestore->hide();
          ui->pushButtonMax->show();
      
          ui->verticalLayoutShadow->setContentsMargins(9, 9, 9, 9);
      
          showNormal();
      }
      

      4 QSS一下

      #widgetContent {
          background-color: white;
          border: 1px solid lightgray;
          border-radius: 3px;
      }
      
      
      #widgetContent QTreeWidget {
          border: 1px solid lightgray;
      }
      
      
      #titleBarWidget QPushButton {
          min-width: 25px;
          max-width: 25px;
          min-height: 25px;
          max-height: 25px;
          qproperty-flat: true;
          border: none;
      }
      #titleBarWidget QPushButton:hover {
          background-color: #D5E1F2;
      }
      #titleBarWidget QPushButton:pressed {
          background-color: #A3BDE3;
      }
      #titleBarWidget QPushButton#pushButtonClose {
          border-image: url(:/img/titleBar/close.png) 0 0 0 0 stretch stretch;
      }
      #titleBarWidget QPushButton#pushButtonRestore {
          border-image: url(:/img/titleBar/restore.png) 0 0 0 0 stretch stretch;
      }
      #titleBarWidget QPushButton#pushButtonMax {
          border-image: url(:/img/titleBar/max.png) 0 0 0 0 stretch stretch;
      }
      #titleBarWidget QPushButton#pushButtonMin {
          border-image: url(:/img/titleBar/min.png) 0 0 0 0 stretch stretch;
      }
      #titleBarWidget QPushButton#pushButtonMenu {
          border-image: url(:/img/titleBar/menu.png) 0 0 0 0 stretch stretch;
      }
      
      
      #menuBarTabWidget::tab-bar {
          left: 65px;
      }
      #menuBarTabWidget {
          border: 1px;
      }
      #menuBarTabWidget {
          background-color: #2B579A;
      }
      #menuBarTabWidget::pane {
          border: 1px solid lightgray;
          border-left: 0px;
          border-right: 0px;
      }
      #menuBarTabWidget QTabBar::tab{
          min-width: 55px;
          max-width: 55px;
          min-height: 23px;
          max-height: 23px;
      }
      #menuBarTabWidget QTabBar::tab {
          background: transparent;
          margin-left: 4px;
          margin-right: 4px;
      }
      #menuBarTabWidget QTabBar::tab:hover {
          color: #2B579A;
      }
      #menuBarTabWidget QTabBar::tab:selected {
          border: 1px solid #BAC9DB;
          background: white;
          border-bottom-color: #FFFFFF;
      }
      #menuBarTabWidget QTabBar::tab:!selected {
          margin-top: 1px;
      }
      
      
      QMenu {
          background-color: #FCFCFC;
          border: 1px solid #8492A6;
      }
      QMenu::item {
          background-color: transparent;
      }
      QMenu::item:selected {
          color: black;
          background-color: #D5E1F2;
      }
      
      
      #pushBtnFileMenu {
          min-width: 58px;
          max-width: 58px;
          min-height: 23px;
          max-height: 23px;
          color: white;
          border: 1px solid #2B579A;
          background-color: #2B579A;
      }
      #pushBtnFileMenu::menu-indicator {
          image: none;
      }
      
      

      5 總結

      之前也看了不少Qt實現FramelessWindow的例子,不是很復雜就是不通用。通過上面的實現,現在已完成了一個通用的版本,只要將自己的窗口設置到ContentWidget即可。本次實踐關鍵地方有以下三點:

      1. 界面的分層,感興趣的朋友可以嘗試下,如果沒有XWidget這一層會有什么效果,ContentWidget邊框效果會失效,這樣當然就達不到預期結果了;
      2. 啟用了WA_Hover鼠標懸浮追蹤,如果不啟用,鼠標的移動事件可能會被子控件覆蓋,這樣就不會知道鼠標是否到達邊框位置,從而無法正確設置鼠標的形狀;
      3. 窗口拉伸時有個偏移量m_movePoint,鼠標其實到達ContentWidget邊界就改變形狀了,拉伸是對XWidget進行的,所以這里有一定的偏移。

      可能算不上最佳實踐,但是已經能夠滿足絕大多數使用場景了,往里面套就行,使用起來非常之簡單,還是很nice的。

      posted @ 2020-08-19 13:08  Qt小羅  閱讀(22444)  評論(9)    收藏  舉報
      主站蜘蛛池模板: 国产精品不卡一区二区久久| 尹人香蕉久久99天天拍| 亚洲va成无码人在线观看天堂| 日韩在线成年视频人网站观看| 久久精品亚洲成在人线av麻豆| 久久国产精品免费一区| 亚洲日韩欧美一区二区三区在线| 成人免费亚洲av在线| 国产精品无码成人午夜电影| 国产精品人成视频免| 国产日本一区二区三区久久| 18av千部影片| 久久亚洲精品中文字幕波多野结衣| 精品视频一区二区三区不卡| 综合色天天久久| 日韩乱码人妻无码系列中文字幕| 日韩av综合免费在线| 阿尔山市| 欧美做受视频播放| 女女互揉吃奶揉到高潮视频| 国产成人毛片无码视频软件| 在线精品自拍亚洲第一区| 奇米四色7777中文字幕| 亚洲成人av综合一区| 天天躁夜夜躁av天天爽| AV教师一区高清| 欧美色丁香| 一本一本久久a久久精品综合| 东京热一精品无码av| 日韩精品一区二区亚洲专区| 亚洲欧美综合在线天堂| 突泉县| 国内自拍av在线免费| 97无码人妻福利免费公开在线视频 | 91亚洲人成手机在线观看| 国内极度色诱视频网站| 无码av中文字幕久久专区| 国产+亚洲+制服| 国产精品亚洲二区在线播放 | 国产专区一线二线三线码| 国产稚嫩高中生呻吟激情在线视频|