-3

i have this function that deleates the last QLineEdit widget from the QGridLayout

it checks if the index of the widget is the last one and if the widget is a instance of QLineEdit ---> deleates the widget

  def deleate_lastlineedit(self):
        widgets = (self.main_layout.itemAt(i).widget() for i in range(self.main_layout.count()))
        for index, widget in enumerate(widgets):
            if index == (self.main_layout.count()-1) and isinstance(widget, (qtw.QLineEdit,qtw.QLabel)):
                widget.deleteLater()
                break

I have added a Qlabel widget to the same row and want that the function deleates the last Qlabel and Qlinedit widget at the same time after pushing a button, so far its deleates one at a time, need to click the button two times.

I tried to insert an counter so the iteration stops not at one iteration but at two iterrations so it gets the two widgets but didnt had an effekt.

also inserted two versions of the function one that deleates the qline edit and the other that deleates the qlabel and connected them to the same button but didnt work either

self.getlistof_button.clicked.connect(self.deleate_lastlineedit)
self.getlistof_button.clicked.connect(self.deleate_lastqlabel)

so how can I deleate the two widgets at the same time ?


fullcode

#!/usr/bin/env python

"""
Creates an linedit when button pushed
dleates last linedit


"""

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
    '''

    # Attribut Signal

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


        # 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.linedittext_button = qtw.QPushButton("linedit text")

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



        self.setLayout(self.main_layout)


        self.show()

        # functionality
        self.addwidget_button.clicked.connect(self.add_widget)
        self.getlistof_button.clicked.connect(self.deleate_lastlineedit)
        self.getlistof_button.clicked.connect(self.deleate_lastqlabel)

        self.linedittext_button.clicked.connect(self.count)




    def count(self):
        x = self.main_layout.rowCount()
        print(self.main_layout.rowCount()+1)
        print(type(x))

    def add_widget(self):
        my_lineedit = qtw.QLineEdit()
        x1 = (self.main_layout.rowCount()+1)
        my_dynmic_label = qtw.QLabel("Dynamic")
        self.main_layout.addWidget(my_dynmic_label,x1,0)
        self.main_layout.addWidget(my_lineedit,x1,1)


    def deleate_lastqlabel(self):
        widgets = (self.main_layout.itemAt(i).widget() for i in range(self.main_layout.count()))
        for index, widget in enumerate(widgets):
            if index == (self.main_layout.count()-1) and isinstance(widget, qtw.QLabel):
                # print("yes")
                widget.deleteLater()
                break



    def deleate_lastlineedit(self):
        widgets = (self.main_layout.itemAt(i).widget() for i in range(self.main_layout.count()))
        for index, widget in enumerate(widgets):
            if index == (self.main_layout.count()-1) and isinstance(widget, qtw.QLineEdit):
                widget.deleteLater()
                break




if __name__ == '__main__':
    app = qtw.QApplication(sys.argv)
    w = AddWidget()
    sys.exit(app.exec_())



Sator
  • 636
  • 4
  • 13
  • 34

1 Answers1

0

As the name suggests, deleteLater() deletes the object later.

Schedules this object for deletion.

The object will be deleted when control returns to the event loop.

If you add a print(self.main_layout.count()) after each deleteLater call in the cycle, you'll see that the count is still the same, and that's because the control is not yet returned to the event loop.

You should use layout.removeWidget() instead.

Besides that, it will not be enough anyway.
You are cycling through the whole list until you find the last element, but this means that the next-to-last will not be checked. A possible solution would be to do the for cycle twice, but doing it wouldn't be the smartest thing to do.

So, as I already suggested, you should use reversed(). Also, you need some form of control since you're going to remove two widgets, otherwise the cycle will break as soon as it finds the first match for isinstance.

def deleate_lastlineedit(self):
    labelRemoved = editRemoved = False
    widgets = [self.main_layout.itemAt(i).widget() for i in range(self.main_layout.count())]
    for widget in reversed(widgets):
        if isinstance(widget, qtw.QLineEdit):
            editRemoved = True
        elif isinstance(widget, qtw.QLabel):
            labelRemoved = True
        else:
            continue
        # in this case, removeWidget is not necessary, since we're not
        # checking the count, but I'll leave it anyway for completeness;
        self.main_layout.removeWidget(widget)
        widget.deleteLater()
        if editRemoved and labelRemoved:
            break

Since you only need to remove the last widgets, creating a generator for the whole widgets is unnecessary. As long as you always insert only QLabels and QLineEdits at the end of the layout, you can just use a while loop.

def deleate_lastlineedit(self):
    labelRemoved = editRemoved = False
    while not (labelRemoved and editRemoved):
        widget = self.main_layout.itemAt(self.main_layout.count() - 1).widget()
        # now here removeWidget *IS* required, otherwise the while loop will
        # never exit
        self.main_layout.removeWidget(widget)
        widget.deleteLater()
        if isinstance(widget, qtw.QLineEdit):
            editRemoved = True
        elif isinstance(widget, qtw.QLabel):
            labelRemoved = True

PS: I've already suggested you to better study Python's control flows, please follow my advice: this is your FOURTH question with almost the same issue, and I only answered because I wanted to clarify the deleteLater() problem, but you wouldn't even have needed to ask it, if you'd follow my previous suggestions and answers. Please, do study and practice, you can't expect to code a GUI if you don't even understand the most elementary basics of its language.

musicamante
  • 41,230
  • 6
  • 33
  • 58
  • I changed `widget.deleteLater()` to `widget.setParent(None)` and the widgets getting deleated as they sould, only thing is that the .`rowcount() ` stays the same – Sator Mar 31 '20 at 12:43
  • Why use setParent, why?!? Who told you to do that? Why don't you use `removeWidget()` as explained in the answer? Why don't you just follow the suggestions people gives you? Why should I keep answering if you are always doing something else instead? – musicamante Mar 31 '20 at 12:51
  • [pyqt: how to remove a widget?](https://stackoverflow.com/a/5899974/12753324) – Sator Mar 31 '20 at 13:12
  • If you remove a *widget* from a QGridLayout, the row count (which is **not** the layout count) won't change, as the layout will still have an empty layout item for the row/column/span position; also, a grid layout always has at least one column and one row, even when it's empty. Besides that, that's a different answer for a different problem (also only partially correct, 9 years old AND referring to an outdated version of Qt), and I really don't understand why you should follow it instead of doing what's written in *this* answer to *your* question, which does exactly what you asked for. – musicamante Mar 31 '20 at 13:43
  • thank you for the solution and explanation I will follow your advice for studying the basics seriosly, I already found a good Introduction to CS course, keep up the good work ! – Sator Mar 31 '20 at 14:23
  • @HoboCoder Sorry, but your edit is rejected, since it's already explained that the while cycle would only work "As long as you always insert only QLabels and QLineEdits". – musicamante Apr 06 '20 at 09:04
  • ah okay, one question why does this change `if isinstance(widget, (qtw.QLineEdit, qtw.QLabel)): labelRemoved = editRemoved = True` only deleates one label at a time ? – Sator Apr 06 '20 at 09:58
  • @HoboCoder my `while` condition exists as soon as *both* `labelRemoved` and `editRemoved` are True. You are setting *both* variables to True when *any* widget that matches `isinstance` (no matter if it's a line edit or a label) is found, so it will exit immediately. If you do that, it would be like using only one variable instead of two. I used two `isinstance` calls exactly for that: you have to separately check **if** it's a label **or** if it's a line edit (*not* whether its one of them) and exit only **when** it has found **both**; your code exists just as soon as it finds *one* of them. – musicamante Apr 06 '20 at 11:07