QWidget :: mouseMoveEvent does not fire when the cursor is over child widgets

I am trying to capture the coordinates of a cursor when a mouse moves within a QWidget , overriding QWidget::mouseMoveEvent() . With mouse tracking turned on, mouse movement events are generated when I move the cursor around the main widget. However, when the cursor is placed over the child widgets, mouse movement events stop working.

Mouse click and release events work when the cursor is over the same child widgets, and event movement works correctly if the mouse button is held down. I tried to enable mouse tracking for kids as well, but it doesn't seem to make any difference. How can I fire mouse movement events when the mouse is over child widgets?

Here is a minimal working example demonstrating the problem:

 import sys from PyQt4 import QtCore, QtGui class MyWindow(QtGui.QWidget) : def __init__(self): QtGui.QWidget.__init__(self) tabs = QtGui.QTabWidget() tab1 = QtGui.QWidget() tab2 = QtGui.QWidget() tabs.addTab(tab1, "Tab 1") tabs.addTab(tab2, "Tab 2") layout = QtGui.QVBoxLayout() layout.addWidget(tabs) self.setLayout(layout) self.setMouseTracking(True) def mouseMoveEvent(self, event): print 'mouseMoveEvent: x=%d, y=%d' % (event.x(), event.y()) app = QtGui.QApplication(sys.argv) window = MyWindow() window.setFixedSize(640, 480) window.show() sys.exit(app.exec_()) 

When the mouse moves outside the QTabWidget , the coordinates of the mouse are printed as expected. Nothing happens inside this if the mouse button is not held.

+6
source share
4 answers

The problem with your code is that you need to enable mouse tracking for all widgets explicitly. You can do this by iterating over all the children of your main widget and calling setMouseTracking(True) for each of them. Here I redefined setMouseTracking() to do just that:

 import sys from PyQt4 import QtCore, QtGui class MyWindow(QtGui.QWidget) : def __init__(self): QtGui.QWidget.__init__(self) tabs = QtGui.QTabWidget() tab1 = QtGui.QWidget() tab2 = QtGui.QWidget() tabs.addTab(tab1, "Tab 1") tabs.addTab(tab2, "Tab 2") layout = QtGui.QVBoxLayout() layout.addWidget(tabs) self.setLayout(layout) self.setMouseTracking(True) def setMouseTracking(self, flag): def recursive_set(parent): for child in parent.findChildren(QtCore.QObject): try: child.setMouseTracking(flag) except: pass recursive_set(child) QtGui.QWidget.setMouseTracking(self, flag) recursive_set(self) def mouseMoveEvent(self, event): print 'mouseMoveEvent: x=%d, y=%d' % (event.x(), event.y()) app = QtGui.QApplication(sys.argv) window = MyWindow() window.setFixedSize(640, 480) window.show() sys.exit(app.exec_()) 
+11
source

LAST UPDATE 8/19/2014 2:37 p.m. The fixed tab bar does not track the mouse move event. (you can see in my code)


I also suggest implementing QWidget.mouseMoveEvent (self, QMouseEvent) as you do it. But not only the root widget just because it tracks the area of ​​an interesting widget, so you need to set the mouse move event. All widgets can track your application. So, create a delegate method to connect them all, and if you have any mouse event to move the waveform, get the current mouse point. eg:

 import sys from PyQt4 import QtGui class QCustomWidget (QtGui.QWidget): def __init__ (self, parent = None): super(QCustomWidget, self).__init__(parent) self.myQTabWidget = QtGui.QTabWidget(self) self.my1QWidget = QtGui.QWidget() self.my2QWidget = QtGui.QWidget() self.myQTabWidget.addTab(self.my1QWidget, 'Tab 1') self.myQTabWidget.addTab(self.my2QWidget, 'Tab 2') myQLayout = QtGui.QVBoxLayout() myQLayout.addWidget(self.myQTabWidget) self.setLayout(myQLayout) self.setMouseMoveEventDelegate(self) self.setMouseMoveEventDelegate(self.myQTabWidget) self.setMouseMoveEventDelegate(self.myQTabWidget.tabBar()) self.setMouseMoveEventDelegate(self.my1QWidget) self.setMouseMoveEventDelegate(self.my2QWidget) def setMouseMoveEventDelegate (self, setQWidget): def subWidgetMouseMoveEvent (eventQMouseEvent): currentQPoint = self.mapFromGlobal(QtGui.QCursor.pos()) print currentQPoint.x(), currentQPoint.y() QtGui.QWidget.mouseMoveEvent(setQWidget, eventQMouseEvent) setQWidget.setMouseTracking(True) setQWidget.mouseMoveEvent = subWidgetMouseMoveEvent appQApplication = QtGui.QApplication(sys.argv) windowQCustomWidget = QCustomWidget() windowQCustomWidget.setFixedSize(640, 480) windowQCustomWidget.show() sys.exit(appQApplication.exec_()) 

Hello,

+1
source

I would try to make your QTabWidget a logical child of MyWindow by passing self when the QTabWidget constructor is called. Also pass the parent for the children of the tab widgets, but pass the tabs widget variable to the appropriate constructors. Without a hierarchy of children declared this way, events may not be redirected properly to the containing widget, since its “children” will be considered as separate widgets drawn on top of your class from the point of view of qt's graph / scene.

0
source

I had the same problem and found the answer here :

self.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)

-1
source

Source: https://habr.com/ru/post/973983/


All Articles