Philip
Philip

Reputation: 17

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

I am developing a GUI that imports and plots data (csv file). Data are initially imported in the TabWidget() class using getfile() and on_pushButtonLoad_clicked() and passed to the FirstTab() class, where MRChart() is plotted in the infrastructure() widget. To achieve this, I created the firstTab instance in TabWidget() (apologies if my terminology is incorrect here).

The end goal is to update the plot based on the numerical range selected on a rangeslider. Firstly, I want to pass the value of slider1 to FirstTab() and I should be able to manage from there. To do this, I have attempted to create the tabwidget instance in FirstTab(). However, I get the following: "RecursionError: maximum recursion depth exceeded". I presume this is due to each class having an instance of itself contained in the other.

Any help appreciated.

Code:

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

Upvotes: 0

Views: 1218

Answers (1)

musicamante
musicamante

Reputation: 48529

The recursion error is clear: TabWidget tries to create FirstTab, but there you're trying to create another TabWidget, which will create a further FirstTab and so on.

If you want to keep reference between objects, you must pass references, not create new instances (see the note below).

Also, since FirstTab calls infrastructure in the __init__, at that point the slider in the parent widget has not been created yet.

You must move the creation of FirstTab after the slider is created, and pass the reference in the constructor.

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
        # ...

Note that this is the same problem you had in your previous question. I strongly suggest you to review the basics of classes and instances and OOP in general, as knowledge and comprehension of those aspects cannot be ignored.

Upvotes: 1

Related Questions