How to disable the delivery of mouse events to the

2019-03-19 09:48发布

问题:

Since last two days, i'm searching and figuring out a way to pass mouse events to the widgets behind a widget used as a container/parent for it's children. I know there is a way to make a widget transparent for mouse events like this:

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

But this also disables the delivery of mouse events to its children! Actually i want the children of the front widget and the widgets behind the front widget to respond to the mouse events.

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.

If you have any idea about how to make a widget transparent for mouse events but not it's children then please share!

回答1:

At last I found a solution :) This answer is for those who are in search of solution for this kind of problem. Key: The key of the solution is QWidget::setMask ( const QRegion & region )

http://doc.qt.io/qt-5/qwidget.html#setMask-2

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

I had found the solution here: http://www.qtcentre.org/archive/index.php/t-3033.html

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

Now children of the front widget and the widgets behind the front widget respond to the mouse events as required!

Remember you would need to call these lines again whenever the front widget is re-sized to recalculate the geometry for the mask!(in my case it's not required but it's for those who may need).

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


回答2:

The solution of the OP is awesome and very elegant. Just for completeness, another option would be to ignore mouse events when they reach the container widget. It can be done either by sub-classing or through a eventFilter.

This solution can be helpful if the widget hides/shows many children widgets dynamically and computing the mask becomes difficult.

Note: In the case you want to track mouse-move events in background widgets, you'd have to setMouseTracking(true) to receive (and then ignore) the QEvent::MouseMove when no button is pressed.

Example by sub-classing

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

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

Example using the event filter

// 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);
}