当光标在子控件上时,QWidget::mouseMoveEvent未触发
我正在尝试在一个 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 个回答
我建议你在创建 QTabWidget 的时候,把它设置为 MyWindow 的一个逻辑子对象,也就是在调用 QTabWidget 的构造函数时传入 self。同时,为选项卡里面的子控件也传入一个父对象,但要把选项卡的变量 tabs
传给它们各自的构造函数。如果不这样设置子控件的层级关系,事件可能就无法正确地传递到包含它们的控件,因为从 Qt 的场景图和事件队列的角度来看,这些“子控件”会被当作是单独的控件,而不是你这个类的一部分。
我也遇到过同样的问题,找到了解决办法,链接在这里:
self.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
最后更新于 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_())
祝好,
你代码的问题在于,你需要明确地为所有的控件开启鼠标追踪功能。你可以通过遍历主控件的所有子控件,然后对每一个子控件调用 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_())