【问题标题】:QWidget::mouseMoveEvent not firing when cursor over child widget当光标悬停在子小部件上时,QWidget::mouseMoveEvent 不会触发
【发布时间】:2014-08-18 16:55:12
【问题描述】:

我试图通过重新实现QWidget::mouseMoveEvent()QWidget 内移动鼠标时捕获光标坐标。启用鼠标跟踪后,当我在主小部件周围移动光标时会生成鼠标移动事件。但是,当光标放在子小部件上时,鼠标移动事件将停止触发。

当光标在同一个子部件上时,鼠标按下/释放事件起作用,如果按住鼠标按钮,移动事件会正确触发。我也尝试过对孩子启用鼠标跟踪,但似乎没有什么不同。 当鼠标悬停在子部件上时如何触发鼠标移动事件?

这是一个演示问题的最小工作示例:

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 时,鼠标坐标会按预期打印。在它里面什么都不会发生,除非按住鼠标按钮。

【问题讨论】:

    标签: python pyqt pyqt4


    【解决方案1】:

    您的代码的问题是您需要为所有小部件显式启用鼠标跟踪。您可以通过遍历主小部件的所有子小部件并为每个小部件调用 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_())
    

    【讨论】:

    • 我想在我尝试过的 tabwidget 和 tabs 上启用鼠标跟踪是不够的。我希望可能有一个比显式启用对层次结构中的每个小部件的跟踪更简单的解决方案。不过,这很好用,谢谢!
    【解决方案2】:

    LAST UPDATED 19 / 8 / 2014 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_())
    

    问候,

    【讨论】:

    • 你测试过这段代码吗?过去,我在为 mouseMoveEvent 之类的猴子修补事件处理程序时没有成功。 AFAIK 覆盖此类方法的唯一方法是通过子类化。
    • 我已经测试了这段代码。 (是不是有什么问题,请告诉我修复,谢谢)。以同样的方式覆盖此方法,但不直接继承。
    • 嗯,很奇怪。我发誓像这样的猴子修补在过去对我没有用。但是您的代码确实有效(尽管在将鼠标移到选项卡上时它不会打印坐标!)
    • 我可能是 python 版本或 pyqt lib 版本?我懂了。在标签栏中移动时,我的代码不打印坐标! (=[]=")
    • 谢谢,这也有效。但是,我接受了@three_pineapples 的答案,因为它是一个更通用的解决方案,并且类似的逻辑可以应用于 c++ 代码,因为它不依赖于monkeypatching。
    【解决方案3】:

    我遇到了同样的问题,找到了答案here

    self.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)

    【讨论】:

      【解决方案4】:

      我会尝试通过在调用 QTabWidget 构造函数时传递 self 来使您的 QTabWidget 成为 MyWindow 的逻辑子级。还为选项卡小部件的子级传递父级,但将选项卡小部件变量 tabs 传递给它们各自的构造函数。如果没有像这样声明的子层次结构,事件可能不会正确地转发到包含的小部件,因为从 qt 场景图/事件队列的角度来看,它的“孩子”将被视为在您的类顶部绘制的单独的小部件。

      【讨论】:

      • 谢谢,不幸的是,在构造函数中设置父母似乎没有任何区别。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      • 2021-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多