簡體   English   中英

從嵌套子部件向 Qt 中的祖先發送信號(PyQT5)

[英]Send signals from Nested children widgets to ancestors in Qt (PyQT5)

我有一個 window,其中包含兩個主要小部件,這兩個小部件都是其他小部件的容器,而其他小部件又可能包含更多小部件。

每個Widget都是一個單獨的class(保持代碼可讀性),子widgets直接在這個class內部實例化,類似於React組件結構。

我想從任何小部件調用一些方法到頂級小部件,或者從深度嵌套的小部件發送信號到接近頂層的小部件,而不必使用類似於“self.parent().parent().parent()”的東西.doStuff(args)”,它可以工作,但如果層次結構發生變化,這將引發錯誤,我的 GUI 變得越復雜,就越難維護。

編輯:這是我要實現的簡化示例:

from PySide2.QtWidgets import *
import sys


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.central = QWidget()
        self.central.setObjectName("Central_Widget")
        self.setCentralWidget(self.central)
        mainLayout = QHBoxLayout(self.central)
        self.central.setStyleSheet("""
        #Central_Widget{
            background-color: #2489FF;
        }""")

        #init mainView widget
        self.leftSide = leftWindow(self.central)
        self.rightSide = rightWindow(self.central)

        mainLayout.addWidget(self.leftSide)
        mainLayout.addWidget(self.rightSide)

class leftWindow(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.setObjectName("leftWindow")
        layout = QVBoxLayout()
        self.setLayout(layout)
        self.label = QLabel(" Left ")
        self.leftButton = customBtn(" Left Button ", "someSVGHere", self)
        layout.addWidget(self.label)
        layout.addWidget(self.leftButton)

        self.setStyleSheet("border : 2px solid white;")


class rightWindow(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.setObjectName("rightWindow")
        layout = QVBoxLayout()
        self.setLayout(layout)
        self.label = QLabel(" Right ")
        self.rightButton = customBtn(" Right Button ", "someSVGHere", self)
        layout.addWidget(self.label)
        layout.addWidget(self.rightButton)

        self.setStyleSheet("border : 2px solid black;")


class customBtn(QWidget):
    def __init__(self, text, svgIcon, parent):
        super().__init__(parent)
        layout = QVBoxLayout()
        self.setLayout(layout)
        self.btnText = QLabel(text)
        self.Icon = svgIcon
        layout.addWidget(self.btnText)
        # setup the icon and the stylesheet etc ....

    def mouseReleaseEvent(self, event):
        # if it's the right button getting clicked, change the stylesheet of the central widget in main window
        # How do I do that here ???
        return super().mouseReleaseEvent(event)
        

# Launcher
if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MainWindow()
    win.setWindowTitle("nesting test")
    win.show()
    sys.exit(app.exec_())

在上面的示例中,我想使用 rightWindow 小部件內的右鍵更改 MainWindow class 中中央小部件的背景,在這個示例中它只有 2 層嵌套,所以它不是很深,但在我的應用程序中我會有最多 5 或 6 層。 理想情況下,每個 class 都在一個單獨的文件中,但這不會改變這個例子。

不幸的是,我不能使用 QT 設計器,因為我正在構建一個現代 GUI 應用程序,所以每個小部件都是自定義的,我想保持我的代碼碎片化,而不是像 QT 設計器生成的那樣在單個 class 中實例化所有內容。

一般來說,在處理 object 層級時,子對象不應試圖直接與父對象交互。 事實上,他們應該總是能夠自己“工作”,不管他們的父母是誰,甚至在他們根本沒有父母的時候。

考慮到這一點,而不是將信號連接到 [great-][grand]parent 的插槽,應該是將 [great-][grand]child 信號連接到它自己的插槽的父級。 這個觀點很重要,因為它也允許我們連接彼此(也可能)知道彼此的兄弟對象。

class customBtn(QWidget):
    customSignal = pyqtSignal(Qt.MouseButton)

    def mouseReleaseEvent(self, event):
        self.customSignal.emit(event.button())


class MainWindow(QMainWindow):
    def __init__(self):
        # ...
        self.leftSide = leftWindow(self.central)
        self.leftSide.leftButton.customSignal.connect(self.something)

    def something(self):
        # whatever

如果結構有很多級別,那么為中間類創建自定義信號也是一種很好的做法,因為信號也可以鏈接起來,只要它們具有兼容的簽名(目標信號必須具有相同的參數類型或更少的arguments 具有相同的類型).

class leftWindow(QWidget):
    customSignal = pyqtSignal()
    def __init__(self, parent):
        # ...
        self.leftButton = customBtn(" Left Button ", "someSVGHere", self)
        self.leftButton.customSignal.connect(self.customSignal)

class MainWindow(QMainWindow):
    def __init__(self):
        # ...
        self.leftSide = leftWindow(self.central)
        self.leftSide.customSignal.connect(self.something)

在上面的例子中, leftWindow的信號沒有任何 arguments,因此它與按鈕信號兼容,因為那些 arguments 將被自動丟棄。

暫無
暫無

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

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