如何在 PyQt5 中的两个 类 之间来回传递变量?

How can I pass variables back and forth between two classes in PyQt5?

我正在开发一个用于导入和绘制数据(csv 文件)的 GUI。数据最初使用 getfile()on_pushButtonLoad_clicked()TabWidget() class 中导入,然后传递到 FirstTab() class,其中 MRChart() 是绘制在 infrastructure() 小部件中。为此,我在 TabWidget() 中创建了 firstTab 实例(如果我的术语在这里不正确,请见谅)。

最终目标是根据在范围滑块上选择的数值范围更新绘图。首先,我想将 slider1 的值传递给 FirstTab(),我应该可以从那里进行管理。为此,我尝试在 FirstTab() 中创建 tabwidget 实例。但是,我得到以下信息:“RecursionError:超出最大递归深度”。我认为这是由于每个 class 都有一个自己的实例包含在另一个中。

感谢任何帮助。

代码:

class TabWidget(QDialog):
    def __init__(self, data):
        super(TabWidget, self).__init__()
        self.data = data
        self.firstTab = FirstTab(self.data)
        self.showMaximized()

        # create Header 
        FilterLayout = QHBoxLayout()
        FilterLayout.addWidget(self.createHeader1a(), 1) 
        FilterLayout.addWidget(self.createHeader2a(), 4)

        # create Tab
        tabwidget = QTabWidget()
        tabwidget.addTab(self.firstTab, "Tab 1")

        vbox = QVBoxLayout()
        vbox.addLayout(FilterLayout)
        vbox.addWidget(tabwidget)

        self.setLayout(vbox)

    def createHeader1a(self):  #Import 
        HeaderBox = QGroupBox("Import Data")

        inputfilebtn = QPushButton("Import")
        inputfilebtn.clicked.connect(self.on_pushButtonLoad_clicked)

        # importrow1
        importrow1layout = QHBoxLayout()
        importrow1layout.addWidget(inputfilebtn)

        HeaderLayout = QVBoxLayout()
        HeaderLayout.addLayout(importrow1layout)
        HeaderBox.setLayout(HeaderLayout)
        HeaderBox.setFlat(True)

        return HeaderBox

    def createHeader2a(self): #Filter

        HeaderBox = QGroupBox("Filter Data")

        rightlayout = QHBoxLayout()
        # range slider bar to filter column data for plotting
        label4 = QLabel(self)
        label4.setText("Filter range:")
        rightlayout.addWidget(label4)
        self.slider1 = QLabeledRangeSlider(Qt.Horizontal)
        self.slider1.setRange(5, 500)
        self.slider1.setValue((150, 300))
        rightlayout.addWidget(self.slider1)

        HeaderBox.setLayout(rightlayout)
        HeaderBox.setFlat(True)  #

        return HeaderBox

    #import and return file
    def getfile(self):
        option = QFileDialog.Options()
        fname = QFileDialog.getOpenFileName(self, 'Open file',
                                            'c:\', "CSV files (*.csv)", options=option)
        return pd.read_csv(fname[0])

    @QtCore.pyqtSlot()
    def on_pushButtonLoad_clicked(self):
        importedfile = self.getfile()
        if importedfile is None:
            return
        self.firstTab.MRChart(importedfile)

        global database
        database = importedfile

    def getslider1value(self):
        return self.slider1.value


class FirstTab(QWidget):
    def __init__(self, data):
        super(FirstTab, self).__init__() 
        self.data = data
        self.tabwidget = TabWidget(self.data)# issue here. Attempting to # access TabWidget class

        # Grid layout of entire tab
        layout = QGridLayout()
        layout.addWidget(self.infrastructure(self.data), 3, 0)
        layout.setRowStretch(4, 3)
        layout.setColumnStretch(0, 1)
        self.setLayout(layout)

    def MRChart(self, importedfile):  # pie chart
        if self.radioButton1.isChecked():
            fig = go.Pie(labels=importedfile[self.radioButton1.label])
        elif self.radioButton2.isChecked():
            fig = go.Pie(labels=importedfile[self.radioButton2.label])

        layout = go.Layout(autosize=True, legend=dict(orientation="h", xanchor='center', x=0.5))
        fig = go.Figure(data=fig, layout=layout)
        fig.update_layout(margin=dict(t=0, b=0, l=0, r=0))
        self.browser.setHtml(fig.to_html(include_plotlyjs='cdn'))

    def infrastructure(self, importedfile):
        groupBox = QGroupBox("Plot")
        self.browser = QtWebEngineWidgets.QWebEngineView(self)

        right = QVBoxLayout()

        # Change/update plot (MRChart) depending on what Radio button is selected
        self.radioButton1 = QRadioButton("Label 1")
        self.radioButton1.label = "Column_label_1"
        self.radioButton1.toggled.connect(lambda: self.MRChart(database))
        right.addWidget(self.radioButton1)

        self.radioButton2 = QRadioButton("Label 2")
        self.radioButton2.setChecked(True)
        self.radioButton2.label = "Column_label_2"
        self.radioButton2.toggled.connect(lambda: self.MRChart(database))
        right.addWidget(self.radioButton2)

        middleright = QHBoxLayout()
        middleright.addWidget(self.browser)
        middleright.addLayout(right)
        groupBox.setLayout(middleright)
        groupBox.setFlat(True)

        print(self.tabwidget.getslider1value())# attempting to print slider value here

        return groupBox

if __name__ == "__main__":
    app = QApplication(sys.argv)
    tabwidget = TabWidget(data=None)
    tabwidget.show()
    app.exec()

递归错误很明显:TabWidget 尝试创建 FirstTab,但您正在尝试创建 另一个 TabWidget,这将创建进一步的 FirstTab 等等。

如果你想保持对象之间的引用,你必须传递引用,而不是创建新的实例(见下面的注释)。

此外,由于 FirstTab__init__ 中调用了 infrastructure,此时父窗口小部件中的滑块尚未创建。

您必须在创建滑块后移动FirstTab的创建,并在构造函数中传递引用。

class TabWidget(QDialog):
    def __init__(self, data):
        super(TabWidget, self).__init__()
        self.data = data
        self.showMaximized()

        # create Header 
        FilterLayout = QHBoxLayout()
        FilterLayout.addWidget(self.createHeader1a(), 1) 
        FilterLayout.addWidget(self.createHeader2a(), 4)

        self.firstTab = FirstTab(self) # <- pass the reference of the parent
        # ...

class FirstTab(QWidget):
    def __init__(self, tabwidget):
        super(FirstTab, self).__init__() 
        self.tabwidget = tabwidget
        self.data = tabwidget.data
        # ...

请注意,这与您在上一个问题中遇到的相同问题。我强烈建议您复习一下 类 和实例以及 OOP 的基础知识,因为对这些方面的知识和理解不容忽视。