我正在尝试将一个小部件pos()
(A)映射到另一个小部件(B),以便B可以根据A的位置做一些工作。我WidgetA
获得了WidgetB
个pos,这些小部件可以有不同的父级层次结构:
Global
+--- Window
+--- WidgetA
+--- WidgetB
Global
+--- Window
+--- Sub
| +--- Sub
| +--- WidgetB
|
+--- WidgetA
Global
+--- Window
| +--- WidgetB
|
+--- WidgetA
等
我试图将B
的位置转换为A
'的相对位置。 via(两个小部件共享同一个父级):
WidgetB.setGeometry(150, 150, 100, 100)
# expected vs result
WidgetA.mapFromGlobal(WidgetB.mapToGlobal(WidgetB.pos())) # 150, 150 125, 200
WidgetA.mapFrom(WidgetA.parent, WidgetB.pos()) # 150, 150 -25, 50
WidgetA.parent.mapFromGlobal(WidgetB.mapToGlobal(WidgetB.pos())) # 150, 150 300, 300
执行此映射的正确方法是什么?我似乎无法正确包装它。
代码:
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5 import QtCore
import sys
class Window(QWidget):
def __init__(self, Parent=None):
super().__init__()
self.WidgetA = QWidget(self)
self.WidgetA.setAttribute(QtCore.Qt.WA_StyledBackground, True)
self.WidgetA.setObjectName("WidgetA")
self.WidgetA.setGeometry(400, 400, 100, 100)
self.WidgetB = QWidget(self)
self.WidgetB.setAttribute(QtCore.Qt.WA_StyledBackground, True)
self.WidgetB.setObjectName("WidgetB")
self.WidgetB.setGeometry(0, 0, 100, 100)
self.setGeometry(0, 0, 500, 500)
self.setStyleSheet("""
#WidgetA {
background-color: red;
}
#WidgetB {
background-color: blue;
}
""")
def resizeEvent(self, event):
print(self.WidgetB.pos())
print(self.WidgetA.pos())
print(self.WidgetA.mapFromGlobal(self.WidgetB.mapToGlobal(self.WidgetB.pos())))
print(self.WidgetA.mapFrom(self, self.WidgetB.pos()))
print(self.mapFromGlobal(self.WidgetB.mapToGlobal(self.WidgetB.pos())))
if __name__ == "__main__":
app = QApplication(sys.argv)
screen = Window()
screen.show()
sys.exit(app.exec_())
输出:
PyQt5.QtCore.QPoint()
PyQt5.QtCore.QPoint(400, 400)
PyQt5.QtCore.QPoint(-400, -400)
PyQt5.QtCore.QPoint(-400, -400)
PyQt5.QtCore.QPoint()
我希望得到(0, 0)
,因为这是WidgetB
设置的内容。
答案 0 :(得分:1)
小部件的位置相对于父级,它不是相对于屏幕的位置,因此在您的示例中,您应该获得(400, 400)
。
根据docs:
pos:QPoint
此属性包含小部件在其父级中的位置 插件
如果窗口小部件是窗口,则位置是窗口小部件的位置 桌面,包括它的框架。
更改位置时,窗口小部件(如果可见)会收到移动 event(moveEvent())立即生效。如果小部件当前不是 可见,它保证在显示之前收到一个事件。
默认情况下,此属性包含引用的位置 原点。
有些方法似乎有效,但这是因为你已经在(0, 0)
中确定了父窗口小部件的位置,如果你改变它,它就会失败。
考虑到您想要A相对于B的位置,解决方案如下:
使用以下内容获取小部件B相对于屏幕的位置:
gp = self.WidgetB.mapToGlobal(QtCore.QPoint(0, 0))
传递(0, 0)
,因为mapToGlobal
需要与使用该功能的窗口小部件相关的位置,在您的情况下,WidgetB
相对于WidgetB
的位置是(0, 0)
。
然后映射WidgetA
的全局位置:
b_a = self.WidgetA.mapFromGlobal(gp)
以下示例显示了我的解决方案的操作:
import sys
from random import randint
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.WidgetA = QtWidgets.QWidget(self)
self.WidgetA.resize(100, 100)
self.WidgetA.setAttribute(QtCore.Qt.WA_StyledBackground, True)
self.WidgetA.setObjectName("WidgetA")
self.WidgetB = QtWidgets.QWidget(self)
self.WidgetB.resize(100, 100)
self.WidgetB.setAttribute(QtCore.Qt.WA_StyledBackground, True)
self.WidgetB.setObjectName("WidgetB")
self.posA = QtCore.QPoint(randint(0, self.width()-100), randint(0, self.height()-100))
self.posB = QtCore.QPoint(randint(0, self.width()), randint(0, self.height()))
self.WidgetA.move(self.posA)
self.WidgetB.move(self.posB)
self.setStyleSheet("""
#WidgetA {
background-color: red;
}
#WidgetB {
background-color: blue;
}
""")
self.WidgetA.installEventFilter(self)
self.WidgetB.installEventFilter(self)
self.installEventFilter(self)
def eventFilter(self, obj, event):
if obj in (self.WidgetA, self.WidgetB, self) and event.type() in (QtCore.QEvent.Resize, QtCore.QEvent.Move) :
gp = self.WidgetB.mapToGlobal(QtCore.QPoint(0, 0))
b_a = self.WidgetA.mapFromGlobal(gp)
print(b_a, self.posB -self.posA)
assert(b_a == (self.posB -self.posA))
return QtWidgets.QWidget.eventFilter(self, obj, event)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())