当前位置:   article > 正文

Qt无边框基类(支持拖拽、最大化动画、半屏动画、最大化拖拽还原)

qt无边框

提供FramelessWidget类,可以将任意QMainWindow或者QWidget作为主窗口的程序直接通过setCenterWidget函数设置为无边框窗口。

特点:
1.支持上、下、左、右及左上、左下、右上、右下四角总共八个方向的拖拽

2.支持窗口最大化时向下拖拽进行还原;

3.支持拖动窗口至窗口最上端的动画效果;

4.支持拖动窗口至左侧和右侧进行半屏显示的动画效果;

5.限制了不能将窗口拖出屏幕外面;

6.边框阴影的2种实现方式。

关键代码:

  1. bool FramelessWidget::eventFilter(QObject *watched, QEvent *event)
  2. {
  3. if (event->type() == QEvent::Resize)
  4. {
  5. int width = this->width();
  6. int height = this->height();
  7. //左侧描点区域
  8. rectLeft = QRect(0, padding, padding, height - padding * 2);
  9. //上侧描点区域
  10. rectTop = QRect(padding, 0, width - padding * 2, padding);
  11. //右侧描点区域
  12. rectRight = QRect(width - padding, padding, padding, height - padding * 2);
  13. //下侧描点区域
  14. rectBottom = QRect(padding, height - padding, width - padding * 2, padding);
  15. //左上角描点区域
  16. rectLeftTop = QRect(0, 0, padding, padding);
  17. //右上角描点区域
  18. rectRightTop = QRect(width - padding, 0, padding, padding);
  19. //左下角描点区域
  20. rectLeftBottom = QRect(0, height - padding, padding, padding);
  21. //右下角描点区域
  22. rectRightBottom = QRect(width - padding, height - padding, padding, padding);
  23. }
  24. else if (event->type() == QEvent::HoverMove)
  25. {
  26. QHoverEvent *hoverEvent = dynamic_cast<QHoverEvent *>(event);
  27. QPoint point = hoverEvent->pos();
  28. if (resizeEnable)
  29. {
  30. if (rectLeft.contains(point))
  31. {
  32. this->setCursor(Qt::SizeHorCursor);
  33. }
  34. else if (rectRight.contains(point))
  35. {
  36. this->setCursor(Qt::SizeHorCursor);
  37. }
  38. else if (rectTop.contains(point))
  39. {
  40. this->setCursor(Qt::SizeVerCursor);
  41. }
  42. else if (rectBottom.contains(point))
  43. {
  44. this->setCursor(Qt::SizeVerCursor);
  45. }
  46. else if (rectLeftTop.contains(point))
  47. {
  48. this->setCursor(Qt::SizeFDiagCursor);
  49. }
  50. else if (rectRightTop.contains(point))
  51. {
  52. this->setCursor(Qt::SizeBDiagCursor);
  53. }
  54. else if (rectLeftBottom.contains(point))
  55. {
  56. this->setCursor(Qt::SizeBDiagCursor);
  57. }
  58. else if (rectRightBottom.contains(point))
  59. {
  60. this->setCursor(Qt::SizeFDiagCursor);
  61. }
  62. else
  63. {
  64. this->setCursor(Qt::ArrowCursor);
  65. }
  66. }
  67. //根据当前鼠标位置,计算XY轴移动了多少
  68. int offsetX = point.x() - lastPos.x();
  69. int offsetY = point.y() - lastPos.y();
  70. //当前最大&拖动距离大于20
  71. if (pressed)
  72. {
  73. QPoint distance = point - lastPos;
  74. int length = distance.manhattanLength();
  75. if (length > 20)
  76. {
  77. if(this->isMaximized())
  78. { //! 最大化-->恢复初始状态
  79. QRect rect = this->normalGeometry();
  80. int desX = lastPos.x() * rect.width() / this->geometry().width();
  81. int desY = lastPos.y();
  82. rect.moveTopLeft(point - QPoint(desX, desY));
  83. // this->setGeometry(rect);
  84. lastPos = QPoint(desX, desY);
  85. setZeroMargin(false);
  86. this->showNormal();
  87. m_windowState = DefaultWindow;
  88. moveEnable = true;
  89. resizeEnable = true;
  90. }
  91. else if(m_windowState == LeftHalfWindow || m_windowState == RightHalfWindow)
  92. { //! 半屏-->恢复初始状态
  93. int desX = lastPos.x() * m_lastRect.width() / this->geometry().width();
  94. int desY = lastPos.y();
  95. m_lastRect.moveTopLeft(point - QPoint(desX, desY));
  96. this->setGeometry(m_lastRect);
  97. m_windowState = DefaultWindow;
  98. moveEnable = true;
  99. resizeEnable = true;
  100. }
  101. }
  102. }
  103. if (moveEnable)
  104. {
  105. if (pressed)
  106. {
  107. QRect _rect = QApplication::desktop()->availableGeometry();
  108. if (_rect.width() - mapToGlobal(point).x() < 10)
  109. {
  110. if (!m_baseWidget->m_bHelpWidhetShow)
  111. {
  112. m_bubbleWidget->setMagicPoint(point+pos());
  113. m_baseWidget->startAnimation(this->geometry(), QRect(_rect.width() / 2, 0, _rect.width() / 2, _rect.height()));
  114. m_windowState = RightHalfWindow;
  115. setZeroMargin(true);
  116. }
  117. }
  118. else if (mapToGlobal(point).x() < 10)
  119. {
  120. if (!m_baseWidget->m_bHelpWidhetShow)
  121. {
  122. m_bubbleWidget->setMagicPoint(point+pos());
  123. m_baseWidget->startAnimation(this->geometry(), QRect(0, 0, _rect.width() / 2, _rect.height()));
  124. m_windowState = LeftHalfWindow;
  125. setZeroMargin(true);
  126. }
  127. }
  128. else if (mapToGlobal(point).y() < 10)
  129. {
  130. if (!m_baseWidget->m_bHelpWidhetShow)
  131. {
  132. m_bubbleWidget->setMagicPoint(point+pos());
  133. m_baseWidget->startAnimation(this->geometry(), QRect(0, 0, _rect.width(), _rect.height()));
  134. m_windowState = MaximumWindow;
  135. setZeroMargin(true);
  136. }
  137. }
  138. else
  139. {
  140. m_baseWidget->hide();
  141. setZeroMargin(false);
  142. }
  143. //! 限制不能拖到屏幕底部之外
  144. int height = QApplication::desktop()->availableGeometry().height();
  145. if(mapToGlobal(point).y() >= height)
  146. offsetY = 0;
  147. this->move(this->x() + offsetX, this->y() + offsetY);
  148. }
  149. }
  150. if (resizeEnable)
  151. {
  152. if (pressedLeft)
  153. {
  154. int resizeW = this->width() - offsetX;
  155. if (this->minimumWidth() <= resizeW)
  156. {
  157. this->setGeometry(this->x() + offsetX, rectY, resizeW, rectH);
  158. }
  159. }
  160. else if (pressedRight)
  161. {
  162. this->setGeometry(rectX, rectY, rectW + offsetX, rectH);
  163. }
  164. else if (pressedTop)
  165. {
  166. int resizeH = this->height() - offsetY;
  167. if (this->minimumHeight() <= resizeH)
  168. {
  169. this->setGeometry(rectX, this->y() + offsetY, rectW, resizeH);
  170. }
  171. }
  172. else if (pressedBottom)
  173. {
  174. this->setGeometry(rectX, rectY, rectW, rectH + offsetY);
  175. }
  176. else if (pressedLeftTop)
  177. {
  178. int resizeW = this->width() - offsetX;
  179. int resizeH = this->height() - offsetY;
  180. if (this->minimumWidth() <= resizeW)
  181. {
  182. this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
  183. }
  184. if (this->minimumHeight() <= resizeH)
  185. {
  186. this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
  187. }
  188. }
  189. else if (pressedRightTop)
  190. {
  191. int resizeW = rectW + offsetX;
  192. int resizeH = this->height() - offsetY;
  193. if (this->minimumHeight() <= resizeH)
  194. {
  195. this->setGeometry(this->x(), this->y() + offsetY, resizeW, resizeH);
  196. }
  197. }
  198. else if (pressedLeftBottom)
  199. {
  200. int resizeW = this->width() - offsetX;
  201. int resizeH = rectH + offsetY;
  202. if (this->minimumWidth() <= resizeW)
  203. {
  204. this->setGeometry(this->x() + offsetX, this->y(), resizeW, resizeH);
  205. }
  206. if (this->minimumHeight() <= resizeH)
  207. {
  208. this->setGeometry(this->x(), this->y(), resizeW, resizeH);
  209. }
  210. }
  211. else if (pressedRightBottom)
  212. {
  213. int resizeW = rectW + offsetX;
  214. int resizeH = rectH + offsetY;
  215. this->setGeometry(this->x(), this->y(), resizeW, resizeH);
  216. }
  217. }
  218. }
  219. else if (event->type() == QEvent::MouseButtonPress)
  220. {
  221. QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent *>(event);
  222. if(mouseEvent->button() != Qt::LeftButton)
  223. return QObject::eventFilter(watched, event);
  224. rectX = this->x();
  225. rectY = this->y();
  226. rectW = this->width();
  227. rectH = this->height();
  228. lastPos = mouseEvent->pos();
  229. //判断按下的区域位置
  230. if (rectLeft.contains(lastPos))
  231. {
  232. pressedLeft = true;
  233. }
  234. else if (rectRight.contains(lastPos))
  235. {
  236. pressedRight = true;
  237. }
  238. else if (rectTop.contains(lastPos))
  239. {
  240. pressedTop = true;
  241. }
  242. else if (rectBottom.contains(lastPos))
  243. {
  244. pressedBottom = true;
  245. }
  246. else if (rectLeftTop.contains(lastPos))
  247. {
  248. pressedLeftTop = true;
  249. }
  250. else if (rectRightTop.contains(lastPos))
  251. {
  252. pressedRightTop = true;
  253. }
  254. else if (rectLeftBottom.contains(lastPos))
  255. {
  256. pressedLeftBottom = true;
  257. }
  258. else if (rectRightBottom.contains(lastPos))
  259. {
  260. pressedRightBottom = true;
  261. }
  262. else
  263. {
  264. pressed = true;
  265. }
  266. }
  267. else if (event->type() == QEvent::MouseMove)
  268. {
  269. //已用HoverMove处理
  270. }
  271. else if (event->type() == QEvent::MouseButtonRelease)
  272. {
  273. pressed = false;
  274. pressedLeft = false;
  275. pressedRight = false;
  276. pressedTop = false;
  277. pressedBottom = false;
  278. pressedLeftTop = false;
  279. pressedRightTop = false;
  280. pressedLeftBottom = false;
  281. pressedRightBottom = false;
  282. this->setCursor(Qt::ArrowCursor);
  283. if (m_baseWidget->m_bHelpWidhetShow)
  284. {
  285. switch (m_windowState) {
  286. case DefaultWindow:
  287. moveEnable = true;
  288. resizeEnable = true;
  289. break;
  290. case LeftHalfWindow:
  291. case RightHalfWindow:
  292. m_lastRect = this->geometry();
  293. this->setGeometry(m_baseWidget->m_endRect);
  294. moveEnable = false;
  295. resizeEnable = false;
  296. break;
  297. case MaximumWindow:
  298. this->showMaximized();
  299. moveEnable = false;
  300. resizeEnable = false;
  301. setZeroMargin(true);
  302. break;
  303. }
  304. }
  305. m_baseWidget->stopAnimation();
  306. }
  307. else if(event->type() == QEvent::MouseButtonDblClick)
  308. {
  309. if(this->isMaximized())
  310. {
  311. setZeroMargin(false);
  312. this->showNormal();
  313. btn_max->setStyleSheet("QPushButton { border-image: url(:/pictures/max.png); background-color: transparent; }\
  314. QPushButton:hover { background-color: #5477a2; }\
  315. QPushButton:pressed { background-color: #5477a2; }");
  316. moveEnable = true;
  317. resizeEnable = true;
  318. }
  319. else
  320. {
  321. setZeroMargin(true);
  322. this->showMaximized();
  323. btn_max->setStyleSheet("QPushButton { border-image: url(:/pictures/restore.png); background-color: transparent }\
  324. QPushButton:hover { background-color: #5477a2; }\
  325. QPushButton:pressed { background-color: #5477a2; }");
  326. moveEnable = false;
  327. resizeEnable = false;
  328. }
  329. }
  330. return QObject::eventFilter(watched, event);
  331. }

全套代码链接: https://www.wpsshop.cn/w/笔触狂放9/article/detail/81477

推荐阅读
相关标签
  

闽ICP备14008679号