PyQt5获得另一个小部件的位置?

时间:2018-06-15 03:46:54

标签: python pyqt pyqt5

我正在尝试将一个小部件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设置的内容。

1 个答案:

答案 0 :(得分:1)

小部件的位置相对于父级,它不是相对于屏幕的位置,因此在您的示例中,您应该获得(400, 400)

根据docs

  

pos:QPoint

     

此属性包含小部件在其父级中的位置   插件

     

如果窗口小部件是窗口,则位置是窗口小部件的位置   桌面,包括它的框架。

     

更改位置时,窗口小部件(如果可见)会收到移动   event(moveEvent())立即生效。如果小部件当前不是   可见,它保证在显示之前收到一个事件。

     

默认情况下,此属性包含引用的位置   原点。

有些方法似乎有效,但这是因为你已经在(0, 0)中确定了父窗口小部件的位置,如果你改变它,它就会失败。

考虑到您想要A相对于B的位置,解决方案如下:

  1. 使用以下内容获取小部件B相对于屏幕的位置:

    gp = self.WidgetB.mapToGlobal(QtCore.QPoint(0, 0))
    
  2. 传递(0, 0),因为mapToGlobal需要与使用该功能的窗口小部件相关的位置,在您的情况下,WidgetB相对于WidgetB的位置是(0, 0)

    1. 然后映射WidgetA的全局位置:

      b_a = self.WidgetA.mapFromGlobal(gp)
      
    2. 以下示例显示了我的解决方案的操作:

      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_())