Search code examples
pythonfor-looppyqt5qpushbutton

PyQt5 retrieving ID and values from multiple Buttons created in an open loop


I'm trying to create buttons (QPushButtons) based on an entry (QLineEdit). The idea is that I want the user to be able to create as many buttons as wanted, simply by adding new text in the entry box and by then pressing "Add Label" (see picture below).

UI so far

While I'm able to do this, I can't for now retrieve the label value of each of these buttons, since the procedure I use erases all the previous values (I can only retrieve the last value entered). I'd like to be able to print each specific Label Value when clicking each button.

My code is below:

from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QLineEdit
import sys

    class MyWindow(QMainWindow):
        def __init__(self):
            super(MyWindow, self).__init__()
            self.setGeometry(100, 100, 1500, 1500)
            self.setWindowTitle("My Program")
            self.labelButtons = []  # List of all the buttons displaying labels
            self.eraseButtons = []  # List of all the buttons displaying "X"
            self.Yposition = 50
            self.initUI()

        def initUI(self):
            self.labelEntry = QLineEdit(self)
            self.labelEntry.move(50, self.Yposition)
            self.labelEntry.resize(300, 40)

            self.addLabelButton = QPushButton(self)
            self.addLabelButton.setText("Add Label")
            self.addLabelButton.move(400, self.Yposition)
            self.addLabelButton.resize(300, 40)
            self.addLabelButton.clicked.connect(self.addNewLabel)

        def addNewLabel(self):
            self.Yposition += 50
            self.newLabelName = self.labelEntry.text()
            self.labelButtons.append(self.createButtonLabel(self.newLabelName))
            self.eraseButtons.append(self.eraseButtonLabel())
            self.updatelabels()

        def createButtonLabel(self, labelname):
            self.button = QPushButton(self)
            self.button.setText(str(labelname))
            self.button.resize(300, 40)
            self.button.move(50, self.Yposition)
            self.button.clicked.connect(self.printbutton)
            return self.button

        def eraseButtonLabel(self):
            self.buttonErase = QPushButton(self)
            self.buttonErase.setText("X")
            self.buttonErase.resize(40, 40)
            self.buttonErase.move(360, self.Yposition)
            self.buttonErase.clicked.connect(self.printbutton)
            return self.buttonErase

        def updatelabels(self):
            for button in self.labelButtons:
                button.show()
            for button in self.eraseButtons:
                button.show()

        def printbutton(self):
            print(self.button.text())


    if __name__ == '__main__':
        app = QApplication(sys.argv)
        win = MyWindow()
        win.show()
        sys.exit(app.exec_())

<!-- end snippet -->


Solution

  • Using Google pyqt clicked event I found you have to use

    def printbutton(self):
        widget = self.sender()
        print(widget.text())
        
    

    ZetCode: Events and signals in PyQt5


    EDIT:

    As for erease button - you should get button from createButtonLabel and send it to eraseButtonLabel

        labelbutton = self.createButtonLabel(self.newLabelName)
        erasebutton = self.eraseButtonLabel(labelbutton)
    

    and you can use lambda to assing function with argument

    def eraseButtonLabel(self, labelbutton):
        # ... code ...
        self.buttonErase.clicked.connect(lambda: self.erasebutton(labelbutton))
    

    and function should get this argument

    def erasebutton(self, button):
        widget = self.sender()
        print('clicked:', widget.text())
        print('  erase:', button.text())
    

    Or you can assing button to own variable in buttonErase

    def eraseButtonLabel(self, labelbutton):
        # ... code ...
        self.buttonErase.assigned_button = labelbutton
        self.buttonErase.clicked.connect(self.erasebutton)
    

    and use it in function

    def erasebutton(self):
        widget = self.sender()
        print('clicked:', widget.text())
        print('  erase:', widget.assigned_button.text())
    

    Full code which uses both methods at the same time but you need only one method.

    from PyQt5.QtWidgets import *
    import sys
    
    class MyWindow(QMainWindow):
        def __init__(self):
            super(MyWindow, self).__init__()
            self.setGeometry(100, 100, 1500, 1500)
            self.setWindowTitle("My Program")
            self.labelButtons = []  # List of all the buttons displaying labels
            self.eraseButtons = []  # List of all the buttons displaying "X"
            self.Yposition = 50
            self.initUI()
    
        def initUI(self):
            self.labelEntry = QLineEdit(self)
            self.labelEntry.move(50, self.Yposition)
            self.labelEntry.resize(300, 40)
    
            self.addLabelButton = QPushButton(self)
            self.addLabelButton.setText("Add Label")
            self.addLabelButton.move(400, self.Yposition)
            self.addLabelButton.resize(300, 40)
            self.addLabelButton.clicked.connect(self.addNewLabel)
    
        def addNewLabel(self):
            self.Yposition += 50
            self.newLabelName = self.labelEntry.text()
            
            labelbutton = self.createButtonLabel(self.newLabelName)
            erasebutton = self.eraseButtonLabel(labelbutton)
            
            self.labelButtons.append(labelbutton)
            self.eraseButtons.append(erasebutton)
            self.updatelabels()
    
        def createButtonLabel(self, labelname):
            self.button = QPushButton(self)
            self.button.setText(str(labelname))
            self.button.resize(300, 40)
            self.button.move(50, self.Yposition)
            self.button.clicked.connect(self.printbutton)
            return self.button
    
        def eraseButtonLabel(self, labelbutton):
            self.buttonErase = QPushButton(self)
            self.buttonErase.setText("X")
            self.buttonErase.resize(40, 40)
            self.buttonErase.move(360, self.Yposition)
            self.buttonErase.assigned_button = labelbutton
            self.buttonErase.clicked.connect(lambda: self.erasebutton(labelbutton))
            #self.buttonErase.clicked.connect(self.erasebutton)
            return self.buttonErase    
    
        def updatelabels(self):
            for button in self.labelButtons:
                button.show()
            for button in self.eraseButtons:
                button.show()
    
        def printbutton(self):
            print('clicked:', self.sender().text())
    
        def erasebutton(self, button):
            widget = self.sender()
            print('clicked:', widget.text())
            print('  erase:', button.text())
            print('  erase:', widget.assigned_button.text())
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        win = MyWindow()
        win.show()
        sys.exit(app.exec_())
    

    EDIT:

    Other method is to create own widget which has both buttons labelbutton and erasebutton and then erasebutton has direct access only to own labelbutton.

    BTW: and for similar reason I would keep buttons as pairs

     self.buttons.append([labelbutton, erasebutton])
    

    instead of separted lists

     self.labelButtons.append(labelbutton)
     self.eraseButtons.append(erasebutton)
    

    Example in which I create own widget.

    from PyQt5.QtWidgets import *
    import sys
    
    class MyWidget(QWidget):
        def __init__(self, parent, labelname, *args, **kwargs):
            super().__init__(parent, *args, **kwargs)
    
            self.resize(350, 40)
            
            self.labelButton = QPushButton(self)
            self.labelButton.setText(str(labelname))
            self.labelButton.resize(300, 40)
            self.labelButton.move(0, 0)
            self.labelButton.clicked.connect(self.printbutton)
    
            self.buttonErase = QPushButton(self)
            self.buttonErase.setText("X")
            self.buttonErase.resize(40, 40)
            self.buttonErase.move(310, 0)
            self.buttonErase.clicked.connect(self.erasebutton)
    
            self.show()
    
        def printbutton(self):
            print('clicked:', self.labelButton.text())
    
        def erasebutton(self):
            print('clicked:', self.buttonErase.text())
            print('  erase:', self.labelButton.text())
    
    
    class MyWindow(QMainWindow):
        def __init__(self):
            super(MyWindow, self).__init__()
            self.setGeometry(100, 100, 1500, 1500)
            self.setWindowTitle("My Program")
            self.widgets = []
            self.Yposition = 50
            self.initUI()
    
        def initUI(self):
            self.labelEntry = QLineEdit(self)
            self.labelEntry.move(50, self.Yposition)
            self.labelEntry.resize(300, 40)
    
            self.addLabelButton = QPushButton(self)
            self.addLabelButton.setText("Add Label")
            self.addLabelButton.move(400, self.Yposition)
            self.addLabelButton.resize(300, 40)
            self.addLabelButton.clicked.connect(self.addNewLabel)
    
        def addNewLabel(self):
            self.Yposition += 50
            text = self.labelEntry.text()
                    
            widget = MyWidget(self, text)
            widget.move(50, self.Yposition)
            
            self.widgets.append(widget)
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        win = MyWindow()
        win.show()
        sys.exit(app.exec_())