如何禁用鼠标事件传递给小部件而不是 Qt 中的 children?

How to disable the delivery of mouse events to the widget but not its children in Qt?

在过去的两天里,我一直在寻找一种方法将鼠标事件传递给用作 container/parent 的小部件后面的小部件,因为它是 children。我知道有一种方法可以使小部件对鼠标事件透明,如下所示:

QWidget w;
w.setAttribute( Qt::WA_TransparentForMouseEvents );

但这也禁止将鼠标事件传递到其 children!我想让前台小部件的children和前台小部件后面的小部件接收鼠标事件。

Qt::WA_TransparentForMouseEvents: When enabled, this attribute disables the delivery of mouse events to the widget and its children. Mouse events are delivered to other widgets as if the widget and its children were not present in the widget hierarchy; mouse clicks and other events effectively “pass through” them. This attribute is disabled by default.

如果您对如何使小部件对鼠标事件透明但不是 children 有任何想法,请分享!

终于找到解决办法了:)

QWidget::setMask (const QRegion & region)

https://doc.qt.io/qt-5/qwidget.html#setMask-1

http://qt-project.org/doc/qt-4.8/qwidget.html#setMask

我在这里找到了解决方案:http://www.qtcentre.org/archive/index.php/t-3033.html

QRegion reg(frameGeometry());
reg -= QRegion(geometry());
reg += childrenRegion();
setMask(reg);

现在前端widget的子组件和前端widget后面的widget都可以根据需要响应鼠标事件!

请记住,只要重新调整前面小部件的大小以重新计算遮罩的几何形状,您就需要再次调用这些行!

void someWidget::resizeEvent(QResizeEvent *e){
  QWidget::resizeEvent(e);
  QRegion reg(frameGeometry());
  reg-=QRegion(geometry()); 
  reg+=childrenRegion();
  setMask(reg);
}

OP的解决方案很棒,也很优雅。为了完整起见,另一种选择是在鼠标事件到达容器小部件时忽略它们。它可以通过子类化或通过 eventFilter.

来完成

如果小部件 hides/shows 有许多动态子小部件并且计算掩码变得困难,则此解决方案可能会有所帮助。

注意:如果您想在后台小部件中跟踪鼠标移动事件,您必须 setMouseTracking(true) 接收(然后忽略)QEvent::MouseMove当没有按下按钮时。

子分类示例

ContainerWidget::ContainerWidget(...) {
  setMouseTracking(true);
}

void ContainerWidget::mouseMoveEvent(QMouseEvent* e) {
  e->ignore();
}
void ContainerWidget::mousePressEvent(QMouseEvent* e) {
  e->ignore();
}

使用事件过滤器的示例

// Assume the container widget is configured in the constructor
MainWindow::MainWindow(...) {
  // ...
  containerWidget->installEventFilter(this);
  containerWidget->setMouseTracking(true);
  // ...
}

bool MainWindow::eventFilter(QObject* o, QEvent* e) {
  if (o == containerWidget &&
     (e->type() == QEvent::MouseMove || e->type() == QEvent::MouseButtonPress)) {
    e->ignore();
    return false;
  }
  return QMainWindow::eventFilter(o, e);
}