-1

I have a Grid layout in which I add Qlineedits at runtime.
while pushing the button I want to delete the last qline edit from the gridlaout
Why does this function delete all qlinedits at the same time ?

 def deleate_widgets(self):
        widgets = (self.main_layout.itemAt(i).widget() for i in range(self.main_layout.count()))
        for widget in widgets:
            if isinstance(widget, qtw.QLineEdit):
                print("linedit: %s  - %s" %(widget.objectName(), widget.text()))
                widget.deleteLater() # all objects

How to change the code to only delete one widget at a time, preferably the last added widget ?

full code

#!/usr/bin/env python

"""
Interface to get the specific  weight of each of the 5 containers
start_measurment_button starts thread /thread_worker
transfer_data button start query and send data to database
"""

import sys
import sqlite3

from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
from PyQt5 import QtSql as qsql

from  PyQt5 import sip

class AddWidget(qtw.QWidget):
    '''
    Interface with embedded SQL functions
    '''

    # Attribut Signal

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # your code will go here

        self.mylist = []
        # interface

        # position
        qtRectangle = self.frameGeometry()
        centerPoint = qtw.QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)
        self.move(qtRectangle.topLeft())
        # size
        self.resize(700, 410)
        # frame title
        self.setWindowTitle("add  Widget")
        # heading
        heading_label = qtw.QLabel('add Widget')
        heading_label.setAlignment(qtc.Qt.AlignHCenter | qtc.Qt.AlignTop)

        # add Button
        self.addwidget_button = qtw.QPushButton("add Widget")
        self.getlistof_button = qtw.QPushButton("deleate")

        self.main_layout = qtw.QGridLayout()
        self.main_layout.addWidget(self.getlistof_button,0,0)
        self.main_layout.addWidget(self.addwidget_button, 1, 0)

        self.setLayout(self.main_layout)

        self.show()

        # functionality
        self.addwidget_button.clicked.connect(self.add_widget)
        # self.getlistof_button.clicked.connect(self.deleate_widgets_try)


    def add_widget(self):
        self.my_lineedit = qtw.QLineEdit()
        self.mylist.append(self.my_lineedit)
        self.main_layout.addWidget(self.my_lineedit)


    def deleate_widgets(self):
        widgets = (self.main_layout.itemAt(i).widget() for i in range(self.main_layout.count()))
        for widget in widgets:
            if isinstance(widget, qtw.QLineEdit):
                print(widget)
                # print("linedit: %s  - %s" %(widget.objectName(), widget.text()))
                # widget.deleteLater() # alle objects


    # 
    # def deleate_widgets_try(self):
    #     widgets = (self.main_layout.itemAt(i).widget() for i in range(self.main_layout.count()))
    #     my_iter = iter(widgets)
    # 
    #     if isinstance(my_iter, qtw.QLineEdit):
    #         next(my_iter.deleteLater()) # alle objects)

if __name__ == '__main__':
    app = qtw.QApplication(sys.argv)
    w = AddWidget()
    sys.exit(app.exec_())
David Buck
  • 3,752
  • 35
  • 31
  • 35
Sator
  • 636
  • 4
  • 13
  • 34

1 Answers1

0

Your function removes all widgets because you are cycling through all the widgets, from the first to the last.

Also, there is really no need to go through the whole layout, since you already keep a list of widgets that always appends the last one at the end.

Just pop out the last item from the list. Removing it from the layout shouldn't be necessary, as deleteLater() would take care of it, but that's just for demonstration purposes.

def deleate_widgets(self):
    # remove the last item from the list
    lastWidget = self.mylist.pop(-1)
    self.main_layout.removeWidget(lastWidget)
    lastWidget.deleteLater()

For the sake of completeness, your function should have done the following:

  1. cycle the widgets through the layout backwards;
  2. break the cycle as soon as the first (as in last) item is found;
def deleate_widgets(self):
    widgets = [self.main_layout.itemAt(i).widget() for i in range(self.main_layout.count())]
    # use reversed() to cycle the list backwards
    for widget in reversed(widgets):
        if isinstance(widget, qtw.QLineEdit):
            print("linedit: %s  - %s" %(widget.objectName(), widget.text()))
            widget.deleteLater()
            # the line edit has been found, exit the cycle with break to avoid
            # deleting further widgets
            break

Also, there's really no use in creating instance attributes (self.someobject = ...) for objects that don't need a persistent reference, especially if you are creating those objects repeatedly (which will result in a constant overwrite of that attribute, making it useless) and you already are keeping them in an persistent data model object (usually a list, a tuple, a dictionary) like self.mylist in your case (and that has to be an instance attribute):

def add_widget(self):
        # no need to create a "self.my_lineedit"
        my_lineedit = qtw.QLineEdit()
        self.mylist.append(my_lineedit)
        self.main_layout.addWidget(my_lineedit)

Having seen your previous questions and comments, I strongly suggest you to better study and experiment with the Python data models, control flows and classes, as they are basic concepts (of Python and programming in general) that must be understood and internalized before attempting to do anything else.

musicamante
  • 41,230
  • 6
  • 33
  • 58
  • thanks for your answer and explanation really appreciate it, It tworks better for me to learn the concepts through projects but your right Im lacking some fundamental concepts – Sator Mar 28 '20 at 12:53
  • my script crashes at `for widget in reversed(widgets):` i get an TypeError "generator" object is not reversible` any idea how to start from the last widget without using the list ? – Sator Mar 28 '20 at 13:27
  • @HoboCoder I know that going all back to the basics might look annoying and unexciting, but consider this: you've been stuck with almost the same code in the last couple of days at least, asking questions that are covered by those basics. In the meantime you'd have been able to study and understand them, and solve your problems on your own probably in a matter of hours. About the crash, my fault; I'll fix it, but I'll leave you a hint before that: [`reversed()`](https://docs.python.org/3/library/functions.html#reversed) requires a sequence object which has a determined length, such as a list. – musicamante Mar 28 '20 at 13:35
  • can you give me another hint :) ? – Sator Mar 30 '20 at 08:29