当前位置:   article > 正文

Qt C++ 实现无边框窗体自定义缩放和拖动_qt无边框窗口缩放

qt无边框窗口缩放

引言

在现代应用程序中,用户界面的个性化定制越来越重要。Qt C++作为强大的框架,为我们提供了丰富的工具来实现各种定制化的用户界面。本文将介绍如何在Qt C++中创建一个无边框窗体,并实现自定义缩放和拖动功能,让您的应用程序更加灵活和个性化。

创建无边框窗体

要创建无边框窗体,我们需要在窗体的构造函数中添加以下代码:

  1. MainWindow::MainWindow(QWidget *parent)
  2. : QMainWindow(parent) {
  3. setWindowFlags(Qt::FramelessWindowHint); // 设置为无边框窗体
  4. setMouseTracking(true); // 设置鼠标追踪,以便在鼠标不按下时也能接收鼠标移动事件
  5. }

通过setWindowFlags函数,我们将窗体的标志设置为Qt::FramelessWindowHint,这将隐藏窗体的边框,使其成为无边框窗体。另外,我们通过setMouseTracking函数设置鼠标追踪,这样即使鼠标不按下,窗体也能接收鼠标移动事件。

监听窗体和顶部栏,实现窗口缩放和拖动

为了实现窗体的拖动和缩放功能,我们需要使用事件过滤器来监听窗体和顶部栏的事件。在构造函数中添加以下代码:

  1. MainWindow::MainWindow(QWidget *parent)
  2. : QMainWindow(parent) {
  3. // ...
  4. qApp->installEventFilter(this); // 监听整个应用程序的事件
  5. ui->header->installEventFilter(this); // 监听顶部栏的事件
  6. }

通过以上代码,我们将事件过滤器安装在整个应用程序和顶部栏上,这样我们就可以捕获窗体和顶部栏的事件,并进行相应的处理。

实现拖动和缩放功能

现在我们已经设置了无边框窗体并监听了窗体和顶部栏的事件,接下来我们将实现拖动和缩放功能。在窗体类中添加以下事件过滤器:

  1. bool MainWindow::eventFilter(QObject *watched, QEvent *event)
  2. {
  3. if (event->type() == QEvent::MouseButtonPress) {
  4. QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
  5. if (mouseEvent->button() == Qt::LeftButton) {
  6. // 如果鼠标按下位置位于窗口边缘,记录鼠标按下位置和窗口当前大小
  7. if (watched == this && !isInFrameSection(mouseEvent->pos(), Qt::NoSection)) {
  8. dragStartPosition = mouseEvent->globalPos();
  9. windowGeometry = geometry();
  10. frameSection = getEdgeSection(mouseEvent->pos());
  11. isResizing = true;
  12. return true; // 截取并处理该事件
  13. }
  14. // 如果鼠标按下位置位于 spacer 区域,记录鼠标按下位置
  15. else if (watched == ui->header && ui->headerSpacer->geometry().contains(mouseEvent->pos())) {
  16. dragStartPosition = mouseEvent->globalPos() - frameGeometry().topLeft();
  17. isDragging = true;
  18. return true; // 截取并处理该事件
  19. }
  20. }
  21. }
  22. else if (event->type() == QEvent::MouseMove) {
  23. QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
  24. if (watched->isWindowType()) {
  25. setCursorStyle(mouseEvent->pos());
  26. }
  27. if (mouseEvent->buttons() & Qt::LeftButton) {
  28. // 如果正在缩放窗口,计算新的窗口大小并移动
  29. if (watched->isWindowType() && isResizing) {
  30. QPoint delta = mouseEvent->globalPos() - dragStartPosition;
  31. if (frameSection == Qt::LeftSection) {
  32. move(windowGeometry.topLeft() + QPoint(delta.x(), 0));
  33. resize(windowGeometry.size() + QSize(-delta.x(), 0));
  34. } else if (frameSection == Qt::RightSection) {
  35. resize(windowGeometry.size() + QSize(delta.x(), 0));
  36. } else if (frameSection == Qt::TopSection) {
  37. resize(windowGeometry.size() + QSize(0, -delta.y()));
  38. move(windowGeometry.topLeft() + QPoint(0, delta.y()));
  39. } else if (frameSection == Qt::BottomSection) {
  40. resize(windowGeometry.size() + QSize(0, delta.y()));
  41. } else if (frameSection == Qt::TopLeftSection) {
  42. resize(windowGeometry.size() + QSize(-delta.x(), -delta.y()));
  43. move(windowGeometry.topLeft() + QPoint(delta.x(), delta.y()));
  44. } else if (frameSection == Qt::BottomRightSection) {
  45. resize(windowGeometry.size() + QSize(delta.x(), delta.y()));
  46. } else if (frameSection == Qt::BottomLeftSection) {
  47. resize(windowGeometry.size() + QSize(-delta.x(), delta.y()));
  48. move(windowGeometry.topLeft() + QPoint(delta.x(), 0));
  49. } else if (frameSection == Qt::TopRightSection) {
  50. resize(windowGeometry.size() + QSize(delta.x(), -delta.y()));
  51. move(windowGeometry.topLeft() + QPoint(0, delta.y()));
  52. }
  53. return true; // 截取并处理该事件
  54. }
  55. else if (isDragging) {
  56. // 如果正在拖动 spacer 区域,移动窗口
  57. QPoint newPos = mouseEvent->globalPos() - dragStartPosition;
  58. move(newPos);
  59. return true; // 截取并处理该事件
  60. }
  61. }
  62. }
  63. else if (event->type() == QEvent::MouseButtonRelease) {
  64. isDragging = false;
  65. isResizing = false;
  66. }
  67. return QWidget::eventFilter(watched, event); // 其他事件交给父类处理
  68. }

上述代码实现了事件过滤器,我们处理了鼠标点击、鼠标移动和鼠标释放事件。当用户点击顶部栏时,启用拖动功能,允许用户拖动窗体。当用户点击窗体边缘时,启用缩放功能,允许用户调整窗体的大小。

完善边缘区域判断功能

我们需要添加另外两个函数isInFrameSectiongetEdgeSection来判断鼠标当前位置位于窗体的哪个边缘区域,并根据边缘区域设置鼠标样式。

  1. bool MainWindow::isInFrameSection(const QPoint &pos, Qt::WindowFrameSection edge) {
  2. QRect area = QRect(0, 0, width(), height()).adjusted(distance, distance, -distance, -distance);
  3. if (edge == Qt::NoSection) { // center包含于edge包含于corner,判断顺序必须是 center>edge>corner
  4. return area.contains(pos);
  5. }
  6. if (edge == Qt::LeftSection || edge == Qt::TopLeftSection || edge == Qt::BottomLeftSection) {
  7. area.adjust(-distance * 2, 0, 0, 0); // 乘2是为了增加偏移量,超出窗体边缘,避免光标抖动
  8. }
  9. if (edge == Qt::RightSection || edge == Qt::TopRightSection || edge == Qt::BottomRightSection) {
  10. area.adjust(0, 0, distance * 2, 0);
  11. }
  12. if (edge == Qt::TopSection || edge == Qt::TopLeftSection || edge == Qt::TopRightSection) {
  13. area.adjust(0, -distance * 2, 0, 0);
  14. }
  15. if (edge == Qt::BottomSection || edge == Qt::BottomLeftSection || edge == Qt::BottomRightSection) {
  16. area.adjust(0, 0, 0, distance * 2);
  17. }
  18. return area.contains(pos);
  19. }
  20. Qt::WindowFrameSection MainWindow::getEdgeSection(const QPoint &pos) {
  21. QList<Qt::WindowFrameSection> sections = {Qt::NoSection, Qt::LeftSection, Qt::RightSection, Qt::TopSection, Qt::BottomSection,
  22. Qt::TopLeftSection, Qt::TopRightSection, Qt::BottomLeftSection, Qt::BottomRightSection};
  23. for (Qt::WindowFrameSection section : sections) {
  24. if (isInFrameSection(pos, section)) {
  25. return section;
  26. }
  27. }
  28. return Qt::NoSection;
  29. }

通过上述代码,我们完成了边缘区域的判断功能。isInFrameSection函数根据edge参数的值调整了边缘区域的范围,并通过adjusted函数增加了偏移量,避免了鼠标在窗体边缘时的抖动问题。而getEdgeSection函数则用于获取当前鼠标位置所处的窗体边缘区域。

设置鼠标样式

通过辅助函数getEdgeSection,我们可以在MouseMove事件中调用setCursorStyle函数来设置鼠标样式,以便在拖动和缩放过程中提供直观的鼠标反馈。

  1. void MainWindow::setCursorStyle(const QPoint &pos) {
  2. Qt::WindowFrameSection frameSection = getEdgeSection(pos);
  3. if (frameSection == Qt::NoSection) {
  4. setCursor(Qt::ArrowCursor);
  5. } else if (frameSection == Qt::LeftSection || frameSection == Qt::RightSection) {
  6. setCursor(Qt::SizeHorCursor);
  7. } else if (frameSection == Qt::TopSection || frameSection == Qt::BottomSection) {
  8. setCursor(Qt::SizeVerCursor);
  9. } else if (frameSection == Qt::TopLeftSection || frameSection == Qt::BottomRightSection) {
  10. setCursor(Qt::SizeFDiagCursor);
  11. } else if (frameSection == Qt::TopRightSection || frameSection == Qt::BottomLeftSection) {
  12. setCursor(Qt::SizeBDiagCursor);
  13. }
  14. }

通过以上代码,我们完善了鼠标样式设置功能。在拖动和缩放过程中,根据鼠标所处的边缘区域,我们设置不同的鼠标样式来提供直观的用户反馈。

实现效果

附图一张,gif就不弄了。

总结

在本文中,我们使用Qt C++中创建了一个无边框窗体,并实现自定义缩放和拖动功能。我们利用Qt::FramelessWindowHint标志隐藏了窗体的边框,并通过事件过滤器监听了窗体和顶部栏的事件,从而实现了窗口的拖动和缩放功能。我们还通过辅助函数判断鼠标所处的边缘区域,并设置相应的鼠标样式,提供了直观的用户反馈。

最后,本人纯纯门外级,如果你有意见或想法,欢迎留言。祝大家心意顺遂,学有所成。

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

闽ICP备14008679号