当前位置:   article > 正文

Qt跨平台无边框窗口探索记录

Qt跨平台无边框窗口探索记录

一、前言

实现的效果为:通过黑色矩形框预操作,鼠标释放时更新窗口。效果图如下:

1.功能

1.1 已实现功能

  1. 8个方向的缩放
  2. 标题栏拖动
  3. 标题栏双击最大化/正常窗口
  4. 窗口最小尺寸
  5. 预操作框颜色与背景色互补
  6. 多屏幕
  7. 默认标题栏

1.2 待开发功能

  1. 拖动到屏幕四周进行半屏全屏。

1.3 存在的问题

1.QWebEngineView

从测试效果来看,对于普通widget效果较好,但是如果是嵌入了QWebEngineView,且其位于窗口四周,就会出现问题。

其主要原因在于,当事件进入QWebEngineView后,会被其child(QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget)"吃掉",导致后续事件不再进入主窗口,从而无法触发我们的代码。这时我们还可以遍历QWebEngineView的children,将事件安装到主窗口

  1. auto childs = view->children();
  2. for(auto child:childs){
  3. child->installEventFilter(this);
  4. }

但是这样显得太笨重了。而且,即使如此,鼠标样式的修改,也会被QWebEngineView刷掉。因此对于QWebEngineView下是存在一些问题的。

2.多屏幕拖动时,从低缩放比拖到高缩放比释放时,会闪烁一次,目前没有进一步分析原因。

2.探索的过程

2.1 关于无边框缩放的实现方式

目前网上无非两种方式:

a)通过nativeEvent()实现。c++ - Qt/Windows, resizable frameless window - Stack Overflow

b)通过窗口的eventFilter()直接实现。

但是问题是前者基于windows接口不跨平台,而后者则会出现抖动。

本文则是基于第二种方式,并参考windows窗口的拖动方式,通过预操作框避免抖动的问题。

2.2 实现思路

  1. 首先关于无边框窗口,通过Qt标志处理:
setWindowFlags(Qt::FramelessWindowHint);
  1. 然后关于缩放和拖动,与网上大多数实现一致,通过九宫格法实现:

当鼠标位于不同区域时,触发不同的操作。

  1. 而对于预处理框,则是通过一个覆盖整个屏幕的透明窗口,并重写paintEvent在其中绘制一个rect。

2.3 实现难点

1.首先是九宫格的思路,了解了思路之后,实现就比较简单了

2.对于预处理框,首先是需要以全屏幕作为geometry,否则会导致拖不到非主屏幕,或者位置错误灯问题

3.其次是预处理框要实现window类似的与背景色互补(而非纯色),需要获取全屏幕图片作为背景绘制到预操作框,然后再通过QPainter::RasterOp_SourceAndNotDestination模式取反。

4.最后就是对于多屏幕的位置,缩放比灯。

二、代码

目录结构如下:

其中:

  • cursorTransform是用于鼠标位置和方向的计算
  • framelessData则是一些全局变量
  • framelessHelper则是对外的接口,
  • titleBar表示默认标题栏
  • transparentRect则是实现预操作框

详细代码如下:

  1. #include "cursorTransform.h"
  2. #include <QDebug>
  3. AreaType CursorTransform::calculateCursorType(const QSize &size, const QPoint &pos)
  4. {
  5. //TODO:minsize
  6. auto w = size.width();
  7. auto h = size.height();
  8. auto x = pos.x();
  9. auto y = pos.y();
  10. //left
  11. if(x<=FrameLessData::borderThickness){
  12. if(y<=FrameLessData::borderThickness)
  13. return AreaType::LeftTopArea;
  14. else if(y>=h-FrameLessData::borderThickness)
  15. return AreaType::LeftBottomArea;
  16. else
  17. return AreaType::LeftArea;
  18. }//right
  19. else if(x>=w-FrameLessData::borderThickness){
  20. if(y<=FrameLessData::borderThickness)
  21. return AreaType::RightTopArea;
  22. else if(y>=h-FrameLessData::borderThickness)
  23. return AreaType::RightBottomArea;
  24. else
  25. return AreaType::RightArea;
  26. }
  27. else{//center
  28. if(y<=FrameLessData::borderThickness)
  29. return AreaType::TopArea;
  30. else if(y<=FrameLessData::titleHeight)
  31. return AreaType::TitleArea;
  32. else if(y>=h-FrameLessData::borderThickness)
  33. return AreaType::BottomArea;
  34. else
  35. return AreaType::CenterArea;
  36. }
  37. }
  38. Qt::CursorShape CursorTransform::AreaType2CursorShape(AreaType type)
  39. {
  40. Qt::CursorShape cursorType(Qt::ArrowCursor);
  41. switch (type) {
  42. case AreaType::LeftTopArea:
  43. case AreaType::RightBottomArea:
  44. cursorType=Qt::SizeFDiagCursor;
  45. break;
  46. case AreaType::RightTopArea:
  47. case AreaType::LeftBottomArea:
  48. cursorType=Qt::SizeBDiagCursor;
  49. break;
  50. case AreaType::TopArea:
  51. case AreaType::BottomArea:
  52. cursorType=Qt::SizeVerCursor;
  53. break;
  54. case AreaType::LeftArea:
  55. case AreaType::RightArea:
  56. cursorType=Qt::SizeHorCursor;
  57. break;
  58. default:
  59. break;
  60. }
  61. return cursorType;
  62. }
  63. void CursorTransform::calculateRect(AreaType type,QRect &rect, const QPoint &lastPos,const QPoint &newPos)
  64. {
  65. int xOff=0,yOff=0,wOff=0,hOff=0;
  66. int posXOff=newPos.x()-lastPos.x();
  67. int posYOff = newPos.y()-lastPos.y();
  68. switch (type) {
  69. case AreaType::LeftTopArea:
  70. xOff = posXOff;
  71. yOff = posYOff;
  72. break;
  73. case AreaType::TopArea:
  74. yOff = posYOff;
  75. break;
  76. case AreaType::RightTopArea:
  77. yOff = posYOff;
  78. wOff = posXOff;
  79. break;
  80. case AreaType::LeftArea:
  81. xOff = posXOff;
  82. break;
  83. case AreaType::RightArea:
  84. wOff = posXOff;
  85. break;
  86. case AreaType::LeftBottomArea:
  87. xOff = posXOff;
  88. hOff = posYOff;
  89. break;
  90. case AreaType::BottomArea:
  91. hOff = posYOff;
  92. break;
  93. case AreaType::RightBottomArea:
  94. wOff = posXOff;
  95. hOff = posYOff;
  96. break;
  97. case AreaType::TitleArea: //move
  98. rect.moveTopLeft(rect.topLeft()+QPoint(posXOff,posYOff));
  99. break;
  100. default:
  101. break;
  102. }
  103. //min judget:
  104. if(rect.width()-xOff<=FrameLessData::minWidth)
  105. xOff=0;
  106. else if(rect.left()<newPos.x() && xOff<0)
  107. xOff=0;
  108. if(rect.width()+wOff<=FrameLessData::minWidth)
  109. wOff=0;
  110. else if(rect.right()>newPos.x() && wOff>0)
  111. wOff=0;
  112. if(rect.height()-yOff<=FrameLessData::minHeight)
  113. yOff=0;
  114. else if(rect.top()<newPos.y() && yOff<0)
  115. yOff=0;
  116. if(rect.height()+hOff<=FrameLessData::minHeight)
  117. hOff=0;
  118. else if(rect.bottom()>newPos.y() && hOff>0)
  119. hOff=0;
  120. //resize:
  121. rect.setTop(rect.top()+yOff);
  122. rect.setLeft(rect.left()+xOff);
  123. rect.setWidth(rect.width()+wOff);
  124. rect.setHeight(rect.height()+hOff);
  125. }
  1. #ifndef CURSORTRANSFORM_H
  2. #define CURSORTRANSFORM_H
  3. #include "framelessData.h"
  4. #include <QRect>
  5. class CursorTransform
  6. {
  7. public:
  8. static AreaType calculateCursorType(const QSize &size, const QPoint &pos);
  9. static enum Qt::CursorShape AreaType2CursorShape(AreaType type);
  10. static void calculateRect(AreaType type,QRect &rect,const QPoint &lastPos,const QPoint &newPos);
  11. private:
  12. };
  13. #endif // CURSORTRANSFORM_H
  1. #include "framelessData.h"
  2. int FrameLessData::borderThickness=4;
  3. int FrameLessData::titleHeight=30;
  4. int FrameLessData::minHeight=355;
  5. int FrameLessData::minWidth=220;
  6. QColor FrameLessData::borderColor=(Qt::white);
  7. QColor FrameLessData::transparentRectBkground=(Qt::transparent);
  8. enum Qt::PenStyle FrameLessData::borderStyle=(Qt::SolidLine);
  1. #ifndef FRAMELESSDATA_H
  2. #define FRAMELESSDATA_H
  3. #include <QColor>
  4. #include <QPoint>
  5. #include <QSize>
  6. //透明矩形的属性
  7. class FrameLessData{
  8. public:
  9. static int borderThickness;
  10. static int titleHeight;
  11. static int minHeight;
  12. static int minWidth;
  13. static QColor borderColor;
  14. static QColor transparentRectBkground;
  15. static enum Qt::PenStyle borderStyle;
  16. };
  17. enum class AreaType
  18. {
  19. LeftTopArea,
  20. TopArea,
  21. RightTopArea,
  22. LeftArea,
  23. RightArea,
  24. LeftBottomArea,
  25. BottomArea,
  26. RightBottomArea,
  27. CenterArea,
  28. TitleArea,
  29. None
  30. };
  31. enum class WidgetOperator
  32. {
  33. None,
  34. Resize,
  35. Move
  36. };
  37. #endif // FRAMELESSDATA_H
  1. #include "framelessHelper.h"
  2. #include "cursorTransform.h"
  3. #include <QEvent>
  4. #include <QSize>
  5. #include <QPoint>
  6. #include <QCursor>
  7. #include <QWidget>
  8. #include <QPainter>
  9. #include <QDebug>
  10. FrameLessHelper::FrameLessHelper(QWidget *widget)
  11. : m_widget(widget)
  12. , m_transparentRect(new TransparentRect())
  13. , m_widgetOperator(WidgetOperator::None)
  14. , m_isMove(false)
  15. #ifdef TITLEBAR
  16. , m_titleBar(nullptr)
  17. #endif
  18. {
  19. m_transparentRect->setRect(m_widget->frameGeometry());
  20. #ifdef TITLEBAR
  21. //if use title
  22. m_titleBar = new TitleBar(m_widget);
  23. connect(m_titleBar,&TitleBar::minimumSizeClick,this,&FrameLessHelper::onMinClick);
  24. connect(m_titleBar,&TitleBar::showNormalClick,this,&FrameLessHelper::onMaxClick);
  25. connect(m_titleBar,&TitleBar::closeClick,this,&FrameLessHelper::onCloseClick);
  26. #endif
  27. }
  28. bool FrameLessHelper::eventFilter(QObject *watched, QEvent *event)
  29. {
  30. int ret=false;
  31. switch (event->type()) {
  32. case QEvent::MouseButtonDblClick: //double click
  33. ret = onDbClickEvent(static_cast<QMouseEvent *>(event));
  34. break;
  35. case QEvent::MouseButtonPress:
  36. ret = onMousePressEvent(static_cast<QMouseEvent *>(event));
  37. break;
  38. case QEvent::MouseButtonRelease:
  39. ret = onMouseReleaseEvent(static_cast<QMouseEvent *>(event));
  40. break;
  41. case QEvent::MouseMove:
  42. ret = onMoveEvent(static_cast<QMouseEvent *>(event));
  43. break;
  44. case QEvent::HoverMove:
  45. case QEvent::HoverEnter:
  46. ret = onHoverEvent(watched,static_cast<QHoverEvent *>(event));
  47. break;
  48. default:
  49. break;
  50. }
  51. //触发返回true
  52. if(ret)
  53. return ret;
  54. return QObject::eventFilter(watched,event);
  55. }
  56. void FrameLessHelper::setBorderThickness(int thickness)
  57. {
  58. FrameLessData::borderThickness = thickness;
  59. }
  60. void FrameLessHelper::setTitleHeight(int height)
  61. {
  62. FrameLessData::titleHeight = height;
  63. }
  64. void FrameLessHelper::setMinHeight(int height)
  65. {
  66. FrameLessData::minHeight = height;
  67. }
  68. void FrameLessHelper::setMinWidth(int width)
  69. {
  70. FrameLessData::minWidth = width;
  71. }
  72. #ifdef TITLEBAR
  73. QWidget *FrameLessHelper::getTitleBar()
  74. {
  75. return m_titleBar;
  76. }
  77. void FrameLessHelper::onMinClick()
  78. {
  79. m_widget->showMinimized();
  80. }
  81. void FrameLessHelper::onMaxClick()
  82. {
  83. if(m_widget->isFullScreen())
  84. m_widget->showNormal();
  85. else
  86. m_widget->showFullScreen();
  87. }
  88. void FrameLessHelper::onCloseClick()
  89. {
  90. m_widget->close();
  91. }
  92. #endif
  93. bool FrameLessHelper::onHoverEvent(QObject *watched,QHoverEvent *event)
  94. {
  95. //操作的时候不响应hover
  96. if(m_widgetOperator!=WidgetOperator::None || m_widget->isFullScreen())
  97. return false;
  98. //hover move
  99. auto areatype = CursorTransform::calculateCursorType(m_widget->size(),event->pos());
  100. auto w=static_cast<QWidget *>(watched);
  101. if(w)
  102. w->setCursor(CursorTransform::AreaType2CursorShape(areatype));
  103. else
  104. m_widget->setCursor(CursorTransform::AreaType2CursorShape(areatype));
  105. return true;
  106. //hover leave -> Qt::ArrowCursor
  107. //not need
  108. }
  109. bool FrameLessHelper::onDbClickEvent(QMouseEvent *event)
  110. {
  111. if(event->button()!=Qt::LeftButton){
  112. return false;
  113. }
  114. auto areatype = CursorTransform::calculateCursorType(m_widget->size(),event->globalPos()-m_widget->pos());
  115. if(areatype==AreaType::TitleArea){
  116. if(m_widget->isFullScreen()){
  117. m_widget->showNormal();
  118. }
  119. else
  120. {
  121. m_widget->showFullScreen();
  122. }
  123. #ifdef TITLEBAR
  124. m_titleBar->onMaxClick();
  125. #endif
  126. }
  127. return true;
  128. }
  129. bool FrameLessHelper::onMousePressEvent(QMouseEvent *event)
  130. {
  131. if(event->button()!=Qt::LeftButton){
  132. return false;
  133. }
  134. auto type = CursorTransform::calculateCursorType(m_widget->size(),event->globalPos()-m_widget->pos());
  135. if(type<AreaType::CenterArea){
  136. //resize
  137. m_widgetOperator = WidgetOperator::Resize;
  138. // not start show rect
  139. m_transparentRect->setRect(m_widget->frameGeometry());
  140. m_transparentRect->onMousePressEvent(event,type);
  141. return true;
  142. }
  143. else if(type==AreaType::TitleArea){
  144. //move
  145. m_widgetOperator = WidgetOperator::Move;
  146. if(!m_widget->isFullScreen())
  147. m_transparentRect->setRect(m_widget->geometry());
  148. else{
  149. m_transparentRect->setRect(calMaxMoveRect(event->globalPos()));
  150. }
  151. m_transparentRect->onMousePressEvent(event,type);
  152. return true;
  153. }
  154. return false;
  155. }
  156. bool FrameLessHelper::onMoveEvent(QMouseEvent *event)
  157. {
  158. if(m_widgetOperator==WidgetOperator::None ||
  159. (m_widgetOperator == WidgetOperator::Resize && m_widget->isFullScreen())){
  160. return false;
  161. }
  162. #ifdef TITLEBAR
  163. if(m_widget->isFullScreen())
  164. m_titleBar->onMaxClick();
  165. #endif
  166. m_isMove =true;
  167. m_transparentRect->show();
  168. m_transparentRect->onMoveEvent(event,event->globalPos()-m_widget->pos());
  169. return false;
  170. }
  171. bool FrameLessHelper::onMouseReleaseEvent(QMouseEvent *event)
  172. {
  173. if(event->button()!=Qt::LeftButton || m_widgetOperator==WidgetOperator::None){
  174. return false;
  175. }
  176. m_transparentRect->onMouseReleaseEvent(event);
  177. m_transparentRect->hide();
  178. if(m_isMove){
  179. if(m_widget->isFullScreen())
  180. m_widget->showNormal();
  181. auto &&rect = m_transparentRect->getRect();
  182. m_widget->move(rect.topLeft());
  183. m_widget->resize(rect.size());
  184. }
  185. m_isMove = false;
  186. m_widgetOperator = WidgetOperator::None;
  187. return false;
  188. }
  189. QRect FrameLessHelper::calMaxMoveRect(const QPoint &evPos)
  190. {
  191. //最大化时拖动标题栏的规则:宽度分为3份,鼠标位于左侧则向左上角对齐,右侧则向右上角对齐,中间部分则按中间对齐
  192. auto rect = m_widget->normalGeometry();
  193. rect.moveTop(0);
  194. double gPosX=evPos.x();
  195. double step = m_widget->geometry().width()/3.0;
  196. double left=0;
  197. if(gPosX>step*2){
  198. left=step*3-rect.width();
  199. }
  200. else if(gPosX>step && gPosX<=step*2){
  201. left=gPosX-rect.width()/2.0;
  202. }
  203. rect.moveLeft(left);
  204. return rect;
  205. }
  1. #ifndef FRAMELESSHELPER_H
  2. #define FRAMELESSHELPER_H
  3. #include "transparentRect.h"
  4. #include "titleBar.h"
  5. #include "cursorTransform.h"
  6. #include <QObject>
  7. #include <QMouseEvent>
  8. #include <QHoverEvent>
  9. #include <QRect>
  10. #include <QWidget>
  11. /*
  12. FrameLessHelper
  13. 1.管理窗口无边框功能
  14. 2.输入为QWidget(构造)和QEvent(eventFilter)
  15. */
  16. class FrameLessHelper : public QObject
  17. {
  18. Q_OBJECT
  19. public:
  20. FrameLessHelper(QWidget *widget);
  21. bool eventFilter(QObject *watched, QEvent *event) override;
  22. void setBorderThickness(int thickness);
  23. void setTitleHeight(int height);
  24. void setMinHeight(int height);
  25. void setMinWidth(int width);
  26. #ifdef TITLEBAR
  27. QWidget *getTitleBar();
  28. void onMinClick();
  29. void onMaxClick();
  30. void onCloseClick();
  31. #endif
  32. private:
  33. bool onHoverEvent(QObject *watched,QHoverEvent *event);
  34. bool onDbClickEvent(QMouseEvent *event);
  35. bool onMousePressEvent(QMouseEvent *event);
  36. bool onMoveEvent(QMouseEvent *event);
  37. bool onMouseReleaseEvent(QMouseEvent *event);
  38. QRect calMaxMoveRect(const QPoint &evPos);
  39. //代理窗口
  40. QWidget *m_widget;
  41. //预拖动窗口
  42. TransparentRect *m_transparentRect;
  43. enum WidgetOperator m_widgetOperator;
  44. bool m_isMove;
  45. #ifdef TITLEBAR
  46. TitleBar *m_titleBar;
  47. #endif
  48. };
  49. #endif // FRAMELESSHELPER_H
  1. #include "titleBar.h"
  2. #include <QIcon>
  3. #include <QPalette>
  4. int iconSize=30;
  5. TitleBar::TitleBar(QWidget *parent,bool isMax)
  6. : QWidget{parent}
  7. , m_minBtn{new QPushButton(this)}
  8. , m_maxBtn{new QPushButton(this)}
  9. , m_closeBtn{new QPushButton(this)}
  10. , m_hLayout{new QHBoxLayout(this)}
  11. , m_spacer{new QSpacerItem(500,30,QSizePolicy::Expanding)}
  12. , m_isMax{isMax}
  13. {
  14. m_minBtn->setIcon(QIcon(":/img/min.png"));
  15. QString maxPic = m_isMax?":/img/normal.png":":/img/max.png";
  16. m_maxBtn->setIcon(QIcon(maxPic));
  17. m_closeBtn->setIcon(QIcon(":/img/close.png"));
  18. connect(m_minBtn,&QPushButton::clicked,this,&TitleBar::minimumSizeClick);
  19. connect(m_maxBtn,&QPushButton::clicked,this,&TitleBar::showNormalClick);
  20. connect(m_maxBtn,&QPushButton::clicked,this,&TitleBar::onMaxClick);
  21. connect(m_closeBtn,&QPushButton::clicked,this,&TitleBar::closeClick);
  22. m_minBtn->resize(iconSize,iconSize);
  23. m_maxBtn->resize(iconSize,iconSize);
  24. m_maxBtn->resize(iconSize,iconSize);
  25. m_hLayout->addSpacerItem(m_spacer);
  26. m_hLayout->addWidget(m_minBtn);
  27. m_hLayout->addWidget(m_maxBtn);
  28. m_hLayout->addWidget(m_closeBtn);
  29. m_hLayout->setSpacing(0);
  30. m_hLayout->setContentsMargins(0,0,0,0);
  31. QPalette palette(this->palette());
  32. palette.setColor(QPalette::Background, QColor(100,100,100));
  33. this->setAutoFillBackground(true);
  34. this->setPalette(palette);
  35. }
  36. void TitleBar::onMaxClick()
  37. {
  38. if(m_isMax){
  39. m_maxBtn->setIcon(QIcon(":/img/max.png"));
  40. m_isMax=false;
  41. }
  42. else{
  43. m_maxBtn->setIcon(QIcon(":/img/normal.png"));
  44. m_isMax=true;
  45. }
  46. }
  1. #ifndef TITLEBAR_H
  2. #define TITLEBAR_H
  3. #include <QWidget>
  4. #include <QPushButton>
  5. #include <QHBoxLayout>
  6. #include <QSpacerItem>
  7. class TitleBar : public QWidget
  8. {
  9. Q_OBJECT
  10. public:
  11. explicit TitleBar(QWidget *parent = nullptr,bool isMax=false);
  12. void onMaxClick();
  13. signals:
  14. void minimumSizeClick();
  15. void showNormalClick();
  16. void closeClick();
  17. private:
  18. QPushButton *m_minBtn;
  19. QPushButton *m_maxBtn;
  20. QPushButton *m_closeBtn;
  21. QHBoxLayout *m_hLayout;
  22. QSpacerItem *m_spacer;
  23. bool m_isMax;
  24. };
  25. #endif // TITLEBAR_H
  1. #include "transparentRect.h"
  2. #include "framelessData.h"
  3. #include <QMouseEvent>
  4. #include <QDesktopWidget>
  5. #include <QDebug>
  6. #include <QPainter>
  7. #include <QPen>
  8. #include <QScreen>
  9. #include <QGuiApplication>
  10. #include <QList>
  11. TransparentRect::TransparentRect(QWidget *parent)
  12. : QWidget(parent)
  13. , m_areaType(AreaType::None)
  14. {
  15. setWindowFlag(Qt::FramelessWindowHint);
  16. setAttribute(Qt::WA_TranslucentBackground);
  17. }
  18. void TransparentRect::setRect(const QRect &rect)
  19. {
  20. m_rect=rect;
  21. }
  22. QRect TransparentRect::getRect() const
  23. {
  24. return m_rect;
  25. }
  26. void TransparentRect::onMousePressEvent(QMouseEvent *event,AreaType type)
  27. {
  28. m_lastPos = event->pos();
  29. //
  30. auto screens = QGuiApplication::screens();
  31. QRect rect;
  32. //QPainter painter(&m_pixmap);
  33. for(auto s:screens){
  34. auto geom = s->geometry();
  35. rect |= geom;
  36. //auto pixmap = s->grabWindow(0, geom.x(), geom.y(), geom.width(), geom.height());
  37. //static int i = 0;
  38. //QFile file(QString("./test%1.png").arg(i++));
  39. //file.open(QIODevice::WriteOnly);
  40. //pixmap.save(&file);
  41. //file.close();
  42. //painter.drawPixmap(s->geometry(), pixmap);
  43. }
  44. //painter.end();
  45. m_startInch = QGuiApplication::screenAt(event->globalPos())->logicalDotsPerInch();
  46. setGeometry(rect);
  47. m_pixmap= QGuiApplication::primaryScreen()->grabWindow(0, rect.x(), rect.y(), rect.width(), rect.height());
  48. m_areaType = type;
  49. #if 0
  50. //
  51. QFile file("./test.png");
  52. file.open(QIODevice::WriteOnly);
  53. m_pixmap.save(&file);
  54. file.close();
  55. #endif // 0
  56. }
  57. void TransparentRect::onMoveEvent(QMouseEvent *event,const QPoint &newPos)
  58. {
  59. m_scaled = QGuiApplication::screenAt(event->globalPos())->logicalDotsPerInch()/ m_startInch;
  60. // auto newPos = event->pos();
  61. int xOff=0,yOff=0,wOff=0,hOff=0;
  62. int posXOff=newPos.x()-m_lastPos.x();
  63. int posYOff = newPos.y()-m_lastPos.y();
  64. switch (m_areaType) {
  65. case AreaType::LeftTopArea:
  66. xOff = posXOff;
  67. yOff = posYOff;
  68. break;
  69. case AreaType::TopArea:
  70. yOff = posYOff;
  71. break;
  72. case AreaType::RightTopArea:
  73. yOff = posYOff;
  74. wOff = posXOff;
  75. break;
  76. case AreaType::LeftArea:
  77. xOff = posXOff;
  78. break;
  79. case AreaType::RightArea:
  80. wOff = posXOff;
  81. break;
  82. case AreaType::LeftBottomArea:
  83. xOff = posXOff;
  84. hOff = posYOff;
  85. break;
  86. case AreaType::BottomArea:
  87. hOff = posYOff;
  88. break;
  89. case AreaType::RightBottomArea:
  90. wOff = posXOff;
  91. hOff = posYOff;
  92. break;
  93. case AreaType::TitleArea: //move
  94. m_rect.moveTopLeft(m_rect.topLeft()+QPoint(posXOff,posYOff));
  95. break;
  96. default:
  97. break;
  98. }
  99. //min judget:
  100. if(m_rect.width()-xOff<=FrameLessData::minWidth)
  101. xOff=0;
  102. else if(m_rect.left()<event->globalPos().x() && xOff<0)
  103. xOff=0;
  104. if(m_rect.width()+wOff<=FrameLessData::minWidth)
  105. wOff=0;
  106. else if(m_rect.right()>event->globalPos().x() && wOff>0)
  107. wOff=0;
  108. if(m_rect.height()-yOff<=FrameLessData::minHeight)
  109. yOff=0;
  110. else if(m_rect.top()<event->globalPos().y() && yOff<0)
  111. yOff=0;
  112. if(m_rect.height()+hOff<=FrameLessData::minHeight)
  113. hOff=0;
  114. else if(m_rect.bottom()>event->globalPos().y() && hOff>0)
  115. hOff=0;
  116. //resize:
  117. m_rect.setTop(m_rect.top()+yOff);
  118. m_rect.setLeft(m_rect.left()+xOff);
  119. m_rect.setWidth(m_rect.width()+wOff);
  120. m_rect.setHeight(m_rect.height()+hOff);
  121. m_lastPos = newPos;
  122. update();
  123. }
  124. void TransparentRect::onMouseReleaseEvent(QMouseEvent *event)
  125. {
  126. m_areaType=AreaType::None;
  127. //释放pixmap,
  128. m_pixmap = QPixmap();
  129. //重绘,触发paintEvent,否则会有闪动,
  130. //注意要在hide之前调用。
  131. repaint();
  132. }
  133. void TransparentRect::paintEvent(QPaintEvent *event)
  134. {
  135. QPainter painter(this);
  136. painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing | QPainter::Antialiasing);
  137. painter.setBackground(FrameLessData::transparentRectBkground);
  138. painter.drawPixmap(0, 0, m_pixmap);
  139. QPen pen(FrameLessData::borderStyle);
  140. pen.setWidth(FrameLessData::borderThickness);
  141. pen.setColor(FrameLessData::borderColor);
  142. painter.setPen(pen);
  143. //背景色取反,要求color必须是white
  144. painter.setCompositionMode(QPainter::RasterOp_SourceAndNotDestination);
  145. //rect位置相对与this的geometry
  146. auto rect=m_rect;
  147. rect.moveTopLeft(rect.topLeft()-geometry().topLeft());
  148. rect.setWidth(rect.width()*m_scaled);
  149. rect.setHeight(rect.height()*m_scaled);
  150. painter.drawRect(rect);
  151. painter.end();
  152. }
  1. #ifndef TRANSPARENTRECT_H
  2. #define TRANSPARENTRECT_H
  3. #include <QWidget>
  4. #include "framelessData.h"
  5. class TransparentRect : public QWidget
  6. {
  7. Q_OBJECT
  8. public:
  9. TransparentRect(QWidget *parent=nullptr);
  10. void setRect(const QRect &rect);
  11. QRect getRect() const;
  12. void onMousePressEvent(QMouseEvent *event,AreaType type);
  13. void onMoveEvent(QMouseEvent *event,const QPoint &pos);
  14. void onMouseReleaseEvent(QMouseEvent *event);
  15. protected:
  16. virtual void paintEvent(QPaintEvent *event) override;
  17. private:
  18. QRect m_rect;
  19. QPoint m_lastPos;
  20. AreaType m_areaType;
  21. QPixmap m_pixmap;
  22. double m_scaled=1.0;
  23. double m_startInch;
  24. };
  25. #endif // TRANSPARENTRECT_H
  1. cmake_minimum_required(VERSION 3.5)
  2. project(frameLessHelper VERSION 0.1 LANGUAGES CXX)
  3. add_definitions(-DTITLEBAR)
  4. #add_definitions(-DRUBBER)
  5. set(CMAKE_AUTOUIC ON)
  6. set(CMAKE_AUTOMOC ON)
  7. set(CMAKE_AUTORCC ON)
  8. set(CMAKE_CXX_STANDARD 17)
  9. set(CMAKE_CXX_STANDARD_REQUIRED ON)
  10. find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets WebEngineWidgets)
  11. find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets WebEngineWidgets)
  12. file(GLOB PROJECT_SOURCES "*.cpp" "*.h" "*.ui" "framelessHelper/*.*")
  13. if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
  14. qt_add_executable(frameLessHelper
  15. MANUAL_FINALIZATION
  16. ${PROJECT_SOURCES}
  17. )
  18. # Define target properties for Android with Qt 6 as:
  19. # set_property(TARGET frameLessHelper APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
  20. # ${CMAKE_CURRENT_SOURCE_DIR}/android)
  21. # For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
  22. else()
  23. if(ANDROID)
  24. add_library(frameLessHelper SHARED
  25. ${PROJECT_SOURCES}
  26. )
  27. # Define properties for Android with Qt 5 after find_package() calls as:
  28. # set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
  29. else()
  30. add_executable(frameLessHelper
  31. ${PROJECT_SOURCES}
  32. framelessHelper/titleBarImg.qrc
  33. webview.h webview.cpp
  34. )
  35. endif()
  36. endif()
  37. target_link_libraries(frameLessHelper PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::WebEngineWidgets)
  38. set_target_properties(frameLessHelper PROPERTIES
  39. MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
  40. MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
  41. MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
  42. MACOSX_BUNDLE TRUE
  43. WIN32_EXECUTABLE TRUE
  44. )
  45. install(TARGETS frameLessHelper
  46. BUNDLE DESTINATION .
  47. LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
  48. RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
  49. )
  50. if(QT_VERSION_MAJOR EQUAL 6)
  51. qt_finalize_executable(frameLessHelper)
  52. endif()
  1. #include "mainwindow.h"
  2. #include "./ui_mainwindow.h"
  3. #include <QGridLayout>
  4. #include <QWebEngineView>
  5. #include <QFrame>
  6. #include "webview.h"
  7. #include <QDebug>
  8. MainWindow::MainWindow(QWidget *parent)
  9. : QMainWindow(parent)
  10. , ui(new Ui::MainWindow)
  11. , m_frameHelper(new FrameLessHelper(this))
  12. {
  13. ui->setupUi(this);
  14. setWindowFlags(Qt::FramelessWindowHint);
  15. installEventFilter(this);
  16. #ifdef TITLEBAR
  17. //titleBar
  18. auto titleBar = m_frameHelper->getTitleBar();
  19. if(titleBar){
  20. QGridLayout *layout = new QGridLayout(centralWidget());
  21. layout->setSpacing(0);
  22. layout->setContentsMargins(0,0,0,0);
  23. layout->addWidget(titleBar,0,0,0,0,Qt::AlignTop);
  24. titleBar->setFixedHeight(32);
  25. #if 0
  26. WebView *view = new WebView();
  27. view->load(QUrl("https:www.baidu.com"));
  28. auto childs = view->children();
  29. for(auto child:childs){
  30. // if(child->metaObject()->className()==QString("QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget"))
  31. child->installEventFilter(this);
  32. }
  33. view->installEventFilter(this);
  34. #else
  35. QFrame *view = new QFrame();
  36. #endif
  37. layout->addWidget(view,1,0);
  38. }
  39. setMouseTracking(true);
  40. #endif
  41. }
  42. MainWindow::~MainWindow()
  43. {
  44. delete ui;
  45. }
  46. bool MainWindow::eventFilter(QObject *watched, QEvent *event)
  47. {
  48. return m_frameHelper->eventFilter(watched,event);
  49. }
  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3. #include <QMainWindow>
  4. #include "framelessHelper/framelessHelper.h"
  5. QT_BEGIN_NAMESPACE
  6. namespace Ui { class MainWindow; }
  7. QT_END_NAMESPACE
  8. class MainWindow : public QMainWindow
  9. {
  10. Q_OBJECT
  11. public:
  12. MainWindow(QWidget *parent = nullptr);
  13. ~MainWindow();
  14. bool eventFilter(QObject *watched, QEvent *event) override;
  15. private:
  16. Ui::MainWindow *ui;
  17. FrameLessHelper *m_frameHelper;
  18. };
  19. #endif // MAINWINDOW_H

 源码:

https://download.csdn.net/download/weixin_40953784/88248380

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/95174
推荐阅读
相关标签
  

闽ICP备14008679号