Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Deleting a specific row from a QFormLayout
QtWS25 Last Chance

Deleting a specific row from a QFormLayout

Scheduled Pinned Locked Moved Solved Qt for Python
3 Posts 2 Posters 997 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    MNix
    wrote on last edited by MNix
    #1

    I have a list of an arbitrary number of dictionaries I want to build in to a QFormLayout. Each element from the list will represent a row in the layout and, nested within that, will be a row for each key in the dictionary - QLabel with the key name, QLineEdit for the value.
    Programmatically, this looks like:

    from os import linesep
    import sys
    from PySide2 import QtWidgets, QtGui
    from PySide2.QtCore import Signal, Slot
    from PySide2.QtGui import QColor, QFont, QPalette, Qt, qBlue
    from PySide2.QtWidgets import (
        QApplication,
        QFileDialog,
        QFormLayout, QFrame,
        QHBoxLayout,
        QLabel,
        QLineEdit,
        QMessageBox,
        QPushButton, QSpacerItem,
        QVBoxLayout,
    )
    
    myList = [
        {
            "name": "mn",
            "phone": "2806"
        },
        {
            "name": "ts",
            "phone": "2800"
        },
        {
            "name": "mb",
            "phone": "2801"
        }
    ]
    
    outRow = QFormLayout()
    class nestedLayouts(QtWidgets.QWidget):
        def __init__(self):
            super().__init__()
            mainLt = QVBoxLayout()
    
            for l in myList:
                print (f"List element=>{l}")
                print(outRow.rowCount())
                deleteButton = delBtn(outRow.rowCount())
                deleteButton.setText(f"delete row {outRow.rowCount()}")
                deleteButton.clicked.connect(self.deleteRow)
                outRow.addRow(deleteButton, newRow(l))
                print (outRow.rowCount())
    
            mainLt.addLayout(outRow)
            self.setLayout(mainLt)
        
        @Slot(int)
        def deleteRow(self, num):
            print("deleting a row...", self, num)
            outRow.removeRow(num)
    
    class newRow(QFormLayout):
        def __init__(self, pList):
            super().__init__()
            self.pList = pList
    
            print (f"newRow dictionary input=>{pList}")
            for name, phone in pList.items():
                print(name, phone)
                label = QLabel(name)
                field = QLineEdit()
                field.setText(phone)
                self.addRow(label, field)
    
    class delBtn(QPushButton):
        def __init__(self, row):
            super().__init__()
            clicked = Signal(int)
    
            # clicked.emit(row)
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        app.setStyle("windowsvista")
        nest = nestedLayouts()
        nest.resize(800, 300)
        nest.show()
        sys.exit(app.exec_())
    

    Now, the should produce a layout of rows, each with a "delete" button adjacent to a set of label/field rows. And when I press the "delete" button, it should remove its parent row from the layout.

    How do I tell my deleteRow Slot function the row number of the calling button so I can issue an appropriate outRow.removeRow("the rownumber of the button's row")? The sample above ALWAYS deletes the first row and throws an index error looking for row 0.

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      There are several possibilities. You can use a lambda. You can set the number on your button using a dynamic property and then use the sender method to retrieve the caller and from it the number in the dynamic property. You can use QSignalMapper.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      1
      • M Offline
        M Offline
        MNix
        wrote on last edited by
        #3

        Thanks SGaist,

        I'm too new to this to fully understand what you've said. I'm not sure how to set a dynamic property but I have seen references to sender methods - I'll have to do some further reading for that. Also not sure where I'd put the lambda you suggest or how to use QSignalMapper (more reading I guess!).

        However, I found that by defining the "delBtn" inside the row it belongs to, instead of creating it outside and then adding it, the deleteRow (now renamed to zapRow) slot function operates on its own row.

        from os import linesep
        import sys
        from PySide2 import QtWidgets, QtGui
        from PySide2.QtCore import Signal, Slot
        from PySide2.QtGui import QColor, QFont, QPalette, Qt, qBlue
        from PySide2.QtWidgets import (
            QApplication,
            QFileDialog,
            QFormLayout, QFrame,
            QHBoxLayout,
            QLabel,
            QLineEdit,
            QMessageBox,
            QPushButton, QSpacerItem,
            QVBoxLayout,
        )
        
        myList = [    {"name": "mn",  "phone": "2806"    },
            {"name": "ts", "phone": "2800" },
            {"name": "mb", "phone": "2801" }
        ]
        
        outRow = QFormLayout()
        class nestedLayouts(QtWidgets.QWidget):
            def __init__(self):
                super().__init__()
                mainLt = QVBoxLayout()
                for l in myList:
                    outRow.addRow(delBtn(outRow.rowCount()), newRow(l))
                outRow.addRow(addBtn(outRow.rowCount()))
                mainLt.addLayout(outRow)
                self.setLayout(mainLt)
        
        class delBtn(QPushButton):
            def __init__(self, row):
                super().__init__()
                self.num = row
                self.setText(f"Delete this row")
                self.clicked.connect(self.zapRow)
        
            @Slot()
            def zapRow(self):
                row = outRow.getWidgetPosition(self)[0]
                print("deleting a row...", row)
                outRow.removeRow(self)
                print(f"delBtn {row} deleted, outRow count = {outRow.rowCount()}")
        
        class addBtn(QPushButton):
            def __init__(self, row):
                super().__init__()
                self.num = row
                self.setText(f"Add a row")
                self.clicked.connect(self.newRow)
        
            @Slot()
            def newRow(self):
                row = outRow.getWidgetPosition(self)[0]
                outRow.insertRow(row, delBtn(row), newRow({"name": "?", "phone": "?"}))
        
        class newRow(QFormLayout):
            def __init__(self, pList):
                super().__init__()
                self.pList = pList
                for name, phone in pList.items():
                    print(name, phone)
                    label = QLabel(name)
                    field = QLineEdit()
                    field.setText(phone)
                    self.addRow(label, field)
        
        if __name__ == "__main__":
            app = QApplication(sys.argv)
            app.setStyle("windowsvista")
            nest = nestedLayouts()
            nest.resize(800, 300)
            nest.show()
            sys.exit(app.exec_())
        
        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved