user4884072
user4884072

Reputation: 81

Python PyQt - How to edit a variable in another function when function is run multiple times

In my PyQt5 program, I have tabs and use one function for creating the same tab multiple times. In PyQt, to run code when a button is clicked you need to connect it to another function. In the createATab function, I have a QLineEdit which needs to be edited when a button is clicked. Here's an example of what I am trying to do:

class Example(QWidget, QWindow):
    def __init__(self):
        super().__init__()

        self.initUI()
    def runThisWhenButtonClicked(self):
        getText = editThisLine.text()
        editThisLine.clear() # edits variable in other function except other function is run multiple times
    def addTheTab(self, username):
        addingTab = QWidget()
        aButton = QPushButton("Stuff")
        editThisLine = QLineEdit()
        aButton.clicked.connect(self.runThisWhenButtonClicked)
        tabGrid = QGridLayout(addingTab)
        tabGrid.addWidget(editThisLine, 3, 1, 4, 2)
        tabGrid.addWidget(aButton, 3, 3, 4, 3)
        tab_widget.addTab(addingTab, str(username))    

    def initUI(self):
        global tab_widget
        tab_widget = QTabWidget()
        listwidget = QListWidget()
        listwidget.itemDoubleClicked.connect(self.addTheTab)
        splitterrr = QSplitter()
        splitterrr.addWidget(listwidget)
        splitterrr.addWidget(tab_widget)
        QListWidgetItem("Test1", listwidget)
        QListWidgetItem("Test2", listwidget)
        mainLayout = QHBoxLayout()
        mainLayout.addWidget(splitterrr)
        self.setLayout(mainLayout)
        self.setGeometry(300, 300, 300, 300)
        self.setWindowTitle('Test')
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

How do I pass a variable by reference?

I have read through this and although it does explain a lot, it doesn't explain how to solve this issue.

pyqt4 button click handler

This explains how you are only passing the function, not calling it. So, passing variables to the runThisWhenButtonClicked function is not possible.

Upvotes: 1

Views: 1620

Answers (1)

ekhumoro
ekhumoro

Reputation: 120638

The concept you are missing is closure. A closure wraps up a scope with a function, so that code in the function can access variables within that associated scope. The simplest way to utilise closures when connecting signals is with a lambda (although some people prefer to use functools.partial).

In your example, this would mean connecting the signal like this:

    aButton.clicked.connect(lambda: self.runThisWhenButtonClicked(editThisLine))
    ...

def runThisWhenButtonClicked(self, editThisLine):
    print(editThisLine.text())

However, I think this may be "papering over the cracks" in your code, and is possibly not the best solution. A better solution would be to make proper use of the namespaces that classes provide. The addTheTab and runThisWhenButtonClicked should be refactored into a Tab class which has all its child widgets as attributes:

class Tab(QWidget):
    def __init__(self, parent=None):
        super(Tab, self).__init__(parent)
        self.editThisLine = QLineEdit()
        self.aButton = QPushButton("Stuff")
        self.aButton.clicked.connect(self.runThisWhenButtonClicked)
        ...

    def runThisWhenButtonClicked(self):
        print(self.editThisLine.text())

This would completely eliminate the need for closures in your example.

Upvotes: 1

Related Questions