-1

I try to create a UI using PyQt5 where a user can create and delete labels, each label being a button (QPushButton) created following a text entry (QLineEdit), and each of these label buttons being accompanied by an associated X-button, which delete the label when clicked.

For this I have created a first QWidget class to create and display the main Widgets (the entry box, the Add Label button, and the overall layout).

I have then created a second QWidget class to generate each label button and its associated X button. Such elements are generated when user click the "Add Label" button of the first QWidget class.

My problem is that I now can't find how to properly display such generated label and X button. Nothing appears when I click the Add Label button, while the function to generate the label and X buttons is properly called (I checked with print).

GUI unable to display the label and X buttons:
GUI unable to display the label and X buttons

Here is the code:

from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QLineEdit, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QGroupBox
import sys


class MyWindow(QMainWindow):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.setWindowTitle("My Program")
        self.setGeometry(100, 100, 1500, 1500)
        self.initUI()

    def initUI(self):
        widgets = MainWidgets()
        self.setCentralWidget(widgets)


class MainWidgets(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.grid = QGridLayout()
        self.grid.setColumnStretch(0, 1)
        self.grid.setColumnStretch(1, 1)
        self.grid.setColumnStretch(2, 1)
        self.grid.setColumnStretch(3, 1)

        self.labelEntry = QLineEdit(self)

        self.addLabelButton = QPushButton(self)
        self.addLabelButton.setText("Add Label")
        self.addLabelButton.clicked.connect(self.addNewLabel)

        self.hbox_labelAdd = QVBoxLayout()
        self.hbox_labelAdd.addWidget(self.labelEntry)
        self.hbox_labelAdd.addWidget(self.addLabelButton)

        self.vbox1 = QVBoxLayout()
        self.vbox1.addLayout(self.hbox_labelAdd)

        self.vbox2 = QVBoxLayout()
        self.vbox2.addStretch(1)

        self.vbox_right = QVBoxLayout()
        self.vbox_right.addLayout(self.vbox1)
        self.vbox_right.addLayout(self.vbox2)

        self.groupBox = QGroupBox("Labelling")
        self.groupBox.setLayout(self.vbox_right)

        self.grid.addWidget(self.groupBox, 0, 3)
        self.setLayout(self.grid)

    def addNewLabel(self):
        labelname = self.labelEntry.text()
        newLabelItems = Labels(self, labelname)
        self.vbox1.addWidget(newLabelItems)


class Labels(QWidget):
    def __init__(self, parent, labelname, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.mylabelname = labelname
        self.initUI()

    def initUI(self):
        self.labelButton = QPushButton(self)
        self.labelButton.setText(str(self.mylabelname))
        self.labelButton.clicked.connect(self.printbutton)
        self.buttonErase = QPushButton(self)
        self.buttonErase.setText("X")
        self.buttonErase.clicked.connect(self.erasebutton)

    def printbutton(self):
        print('clicked:', self.labelButton.text())

    def erasebutton(self):
        self.labelButton.deleteLater()
        self.buttonErase.deleteLater()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    # app.setStyle('Fusion')
    window = MyWindow()
    window.show()
    sys.exit(app.exec_())

I found a trick by creating an empty QPushButton and associating it to the label and X buttons in a layout, which allows to display the label and X button, but this is not a long-term solution, plus I can't find a way to display these label and X buttons full width in the layout, there get restricted to half the layout (whether I use grid, Vbox, or Hbox layout) for some reason I can't explain.

Here is the trick code (replace the def addNewLabel (self) function in the previous code):

    def addNewLabel(self):
        labelname = self.labelEntry.text()
        newLabelItems = Labels(self, labelname)
        fake_widget = QPushButton(self)
        labelitems_lay = QHBoxLayout()
        labelitems_lay.addWidget(fake_widget)
        labelitems_lay.addWidget(newLabelItems)
        self.vbox1.addLayout(labelitems_lay)

In the below picture you can see what it looks like with this trick: GUI with the trick - zoomed on the area of interest:
GUI with the trick - zoomed on the area of interest

The overall goal is to be able to generate buttons in a quite similar way as in this picture: Scheme representing the desired output:
Scheme representing the desired output

I think the issue I have is related to to layout, because thank to @furas yesterday I was able to achieve this goal but using the move() function to display buttons. Now that I'm trying to organise my UI with layouts, I unfortunately can't achieve it anymore.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Marc
  • 29
  • 6

1 Answers1

1

One way would to add the two buttons to a layout in Labels.initUi, e.g.


class Labels(QWidget):
    ....

    def initUI(self):
        self.labelButton = QPushButton(self)
        self.labelButton.setText(str(self.mylabelname))
        self.labelButton.clicked.connect(self.printbutton)
        self.buttonErase = QPushButton(self)
        self.buttonErase.setText("X")
        self.buttonErase.clicked.connect(self.erasebutton)

        layout = QHBoxLayout(self)
        layout.setContentsMargins(0,0,0,0)
        layout.addWidget(self.labelButton, stretch=1)
        layout.addWidget(self.buttonErase, stretch=0)
Heike
  • 24,102
  • 2
  • 31
  • 45