这里有另一种可能的解决方案,多次调用现有的QApplication.widgetAt
函数。
import sys
from PySide import QtGui, QtCore
def widgets_at(pos):
"""Return ALL widgets at `pos`
Arguments:
pos (QPoint): Position at which to get widgets
"""
widgets = []
widget_at = QtGui.qApp.widgetAt(pos)
while widget_at:
widgets.append(widget_at)
widget_at.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
widget_at = QtGui.qApp.widgetAt(pos)
for widget in widgets:
widget.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents, False)
return widgets
示例
class Overlay(QtGui.QWidget):
def __init__(self, parent=None):
super(Overlay, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_StyledBackground)
self.setStyleSheet("QWidget { background-color: rgba(0, 255, 0, 50) }")
def mousePressEvent(self, event):
pos = QtGui.QCursor.pos()
print [w.objectName() for w in widgets_at(pos)]
return super(Overlay, self).mousePressEvent(event)
app = QtGui.QApplication(sys.argv)
window = QtGui.QWidget()
window.setObjectName("Window")
window.setFixedSize(200, 100)
button = QtGui.QPushButton("Button 1", window)
button.setObjectName("Button 1")
button.move(10, 10)
button = QtGui.QPushButton("Button 2", window)
button.setObjectName("Button 2")
button.move(50, 15)
overlay = Overlay(window)
overlay.setObjectName("Overlay")
overlay.setFixedSize(window.size())
window.show()
app.exec_()
这里是一些输出。
[u'Overlay', u'Window'] # Clicking an empty area
[u'Overlay', u'Button 1', u'Window'] # Button 1
[u'Overlay', u'Button 2', u'Window'] # Button 2
[u'Overlay', u'Button 2', u'Button 1', u'Window'] # Overlap
看起来结果是O(1),并且额外的好处是以它们重叠的顺序返回每个小部件。但是,这会导致重叠的窗口闪烁(在Windows 8上),因为它们的属性被更改和恢复。