簡體   English   中英

PyQt5獲取另一個小部件的pos?

[英]PyQt5 get pos of another widget?

我試圖將一個小部件pos() (A)映射到另一個小部件(B),以便B可以根據A的位置進行一些工作。 我有WidgetA來獲取WidgetB pos,這些小部件可以具有不同的育兒層次結構:

Global
+--- Window
     +--- WidgetA
     +--- WidgetB

Global
+--- Window
     +--- Sub
     |    +--- Sub
     |         +--- WidgetB
     |
     +--- WidgetA

Global
+--- Window
|    +--- WidgetB
|
+--- WidgetA

等等

我試圖通過(兩個小部件共享同一個父對象)將B的位置轉換為A '上的相對位置:

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設置的。

小部件的位置是相對於父級的,而不是相對於屏幕的位置,因此在您的示例中,您應該獲得(400, 400)

根據文檔

pos:QPoint

此屬性保存窗口小部件在其父窗口小部件內的位置

如果窗口小部件是窗口,則位置是桌面上窗口小部件(包括其框架)的位置。

更改位置時,小部件(如果可見)會立即接收一個移動事件(moveEvent())。 如果該窗口小部件當前不可見,則可以保證在顯示該事件之前會收到一個事件。

默認情況下,此屬性包含一個指向原點的位置。

有些方法似乎可行,但這是因為您已在(0, 0)建立了父窗口小部件的位置,如果更改它,它將失敗。

考慮到您想要A相對於B的位置,解決方案如下:

  1. 使用以下方法獲取小部件B相對於屏幕的位置:

     gp = self.WidgetB.mapToGlobal(QtCore.QPoint(0, 0)) 

它被傳遞(0, 0)因為mapToGlobal要求相對於使用該函數的小部件的位置,在您的情況下WidgetB相對於WidgetB的位置為(0, 0)

  1. 然后映射關於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_())

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM