当光标在子控件上时,QWidget::mouseMoveEvent未触发

9 投票
4 回答
12737 浏览
提问于 2025-04-18 17:41

我正在尝试在一个 QWidget 中捕捉鼠标光标的位置,方法是重新实现 QWidget::mouseMoveEvent() 这个函数。当我开启鼠标追踪功能后,鼠标移动时会在主窗口中生成移动事件。但是,当光标移动到一个子窗口上时,鼠标移动事件就不再触发了。

在光标位于同一个子窗口上时,鼠标按下和释放的事件是可以正常工作的,如果按住鼠标按钮,移动事件也会正常触发。我尝试在子窗口上也开启鼠标追踪功能,但似乎没有什么效果。 我该如何在鼠标位于子窗口上时触发鼠标移动事件呢?

下面是一个简单的示例,展示了这个问题:

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_())

当鼠标移动到 QTabWidget 外面时,鼠标坐标会正常打印出来。但在里面时,除非按住鼠标按钮,否则什么都不会发生。

4 个回答

0

我建议你在创建 QTabWidget 的时候,把它设置为 MyWindow 的一个逻辑子对象,也就是在调用 QTabWidget 的构造函数时传入 self。同时,为选项卡里面的子控件也传入一个父对象,但要把选项卡的变量 tabs 传给它们各自的构造函数。如果不这样设置子控件的层级关系,事件可能就无法正确地传递到包含它们的控件,因为从 Qt 的场景图和事件队列的角度来看,这些“子控件”会被当作是单独的控件,而不是你这个类的一部分。

1

我也遇到过同样的问题,找到了解决办法,链接在这里

self.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)

1

最后更新于 2014年8月19日 14:37 固定的标签栏没有跟踪鼠标移动事件。(你可以在我的代码中看到)


我建议你像这样实现 QWidget.mouseMoveEvent (self, QMouseEvent)。不过,不仅仅是在根部件上,因为它只会跟踪你感兴趣的部件区域。所以你需要在应用程序中的所有部件上都设置鼠标移动事件,这样才能跟踪到鼠标的移动。你可以创建一个代理方法,把它们连接起来,如果你有任何来自鼠标移动事件的信号,就获取当前鼠标的位置。像这样;

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_())

祝好,

19

你代码的问题在于,你需要明确地为所有的控件开启鼠标追踪功能。你可以通过遍历主控件的所有子控件,然后对每一个子控件调用 setMouseTracking(True) 来实现这一点。在这里,我重写了 setMouseTracking() 方法来完成这个任务:

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_())

撰写回答