Here is another possible solution that calls the existing one QApplication.widgetAtseveral times.
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
Example

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_()
Here are some results.
[u'Overlay', u'Window']
[u'Overlay', u'Button 1', u'Window']
[u'Overlay', u'Button 2', u'Window']
[u'Overlay', u'Button 2', u'Button 1', u'Window']
It seems that the results are O (1), with the added benefit of returning each widget in the order in which they overlap. However, they overlap overlapping windows (Windows 8) because their attribute is changed and restored.
source
share