0

I created entries and labels by loops. If user click the button there will be new entries and lables in two-two seperated row. Now I want to delete them by other button clicking, but labels are not deletable -only entries are.

My other problem is I want to delete just only the last widgets that were added by one clicking. To make it clear: I want to delete the last 18-18 labels and entries by one clicking. Currently, all the added entries so far will be deleted. The labels are not at all. Here is the relevant code:

self._1thLabel_list = ['Label1', 'Label2', 'Label3', 'Label4', 'Label5',
                       'Label6', 'Label7', 'Label8', 'Label9']

self._2thLabel_list = ['Label10', 'Label11', 'Label12', 'Label13', 'Label14', 
                  'Label15', 'Label16', 'Label17', 'Label18']

nothingList2 = []

self.col = 4
        for j in range(len(self._1thLabel_list)):
            self.myLab = Label(root, text=self._1thLabel_list[j]).grid(row=0, column=j+1)
            for k in range(1):
                self.myEntry_loop = Entry(root)
                self.myEntry_loop.grid(row=k + 1, column=j+1, pady=10, padx=10)
                self.myEntry_loop_2 = Entry(root)
                self.myEntry_loop_2.grid(row=k + 3, column=j + 1, pady=10, padx=10)
                nothingList2.append(self.myEntry_loop)
                nothingList2.append(self.myEntry_loop_2)
        for l in range(len(self._2thLabel_list)):
            self.myLab_2 = Label(root, text=self.mylist_2[l]).grid(row=2, column=l + 1)

self.myButton_newWidgets = Button(root, text="Add", command=self.Add)
self.myButton_newWidgets.grid(row=self.col, column=4)
self.myButton_deleteWidgets = Button(root, text="Delete", command=self.deleteThem)
self.myButton_deleteWidgets.grid(row=self.col, column=5)

And here is how try to delete them:

def deleteThem(self):
     for v in range(18):
         nothingList2.pop(0)
     for dele in nothingList2:
         dele.destroy()  # Here, it is deleting entries but delete all of them. I want just delete the last 18 of them. 

     for w in range(9):
         self._1thLabel_list.pop(0)
     for delet in self._1thLabel_list:
         delet.destroy()   # I got "AttributeError: 'str' object has no attribute 'destroy'" error in this line

     for x in range(9):
         self._2thLabel_list.pop(0)
     for delet2 in self._2thLabel_list:
         delet2.destroy()
Nirevezs
  • 71
  • 8
  • That's how I am trying to delete them. But if anyone has a better idea then I am open to it as well. – Nirevezs Mar 31 '21 at 12:04
  • Try to just use `pop()` and then store it an a variable and then delete it, instead of using a `for` loop? – Delrius Euphoria Mar 31 '21 at 14:07
  • `nothingList2` is a local variable inside the first code block (assume it is inside a function), so it cannot be accessed inside `deleteThem()` function. Also the first for loop inside `deleteThem()` will clear `nothingList2` (assume it can be accessed here), so the second for loop will do nothing. Better provide [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – acw1668 Mar 31 '21 at 14:36

1 Answers1

2

Here is a solution (explanation below):

from tkinter import Tk, Button


root = Tk()
removable_widget_dict = {}


class RemovableWidget(Button):
    def __init__(self, parent, title, key):
        Button.__init__(self, parent)
        self.key = key

        self.config(text=title)
        self.pack()

    def delete(self):
        self.destroy()
        removable_widget_dict.pop(self.key)


for i in range(10):
    key = f'item{i}'
    removable_widget_dict[key] = RemovableWidget(root, f'Button {i}', key)

for key in removable_widget_dict.keys():
    if key == 'item5':
        removable_widget_dict[key].delete()
        break

root.mainloop()

Explanation:

First of I would like to mention that this is something I came up with (at least similar to this) when doing a personal project so all of this comes from experience in a sense that this may not be the best solution but it certainly works.

After doing the basic stuff with tkinter (root = Tk(), root.mainloop()) You create a dictionary which will sort of store classes. Now classes are an important factor here since each instance of a class can act independently which cannot really be achieved with functions at least not as easy.

So then You create a class for whatever widget You need, You can create multiple classes for multiple widgets or somehow merge them all into one (don't know how that would work) but lets stick to one class for one type of widget.

In this class You define all the basic stuff You would for a widget but also You add an important argument "key". This is not as important but certainly is necessary because You do not want to leave unused classes in memory (don't know about the technical aspects but imo it keeps everything more clean especially if You have to read it[dictionary] for some reason)

Then You define the deletion function and here is where the independence of class instances comes in: for each class instance You will be able to call this function which will only affect that class instance. So now in this function You will destroy the widget that class created (in this case the button in self.button) or multiple widgets. and then the cleanup part comes in: You globally define the dictionary and then delete the "key" from it. and the key also makes it easier to access the class instance for other reasons.

The final note. You can access the classes who are stored in dictionaries functions like this: dictionary[key].that_class_function

Matiiss
  • 5,970
  • 2
  • 12
  • 29
  • I'd like some time while I try to convert is to my code – Nirevezs Mar 31 '21 at 12:07
  • @Nirevezs sure, I am not in a hurry. – Matiiss Mar 31 '21 at 12:11
  • Thank you for this code snippet, which might provide some limited, immediate help. A [proper explanation](https://meta.stackexchange.com/q/114762/349538) would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you’ve made. – Delrius Euphoria Mar 31 '21 at 14:07
  • @CoolCloud will do – Matiiss Mar 31 '21 at 14:08
  • @CoolCloud well is this better now? – Matiiss Mar 31 '21 at 14:22
  • @Matiiss Did not have to go through so much ;) But its perfect now. – Delrius Euphoria Mar 31 '21 at 15:12
  • ok, I noticed upvotes so I came and looked at the answer and noticed that it can be improved so that is what I did, I edited in the better code, not entirely sure about the applications here but btw it is not necessary to loop over the dictionary, it is also possible to just `dictionary['item5'].delete()` if You need, again I didn't read much just improved on what I could without changing the functionality – Matiiss Jun 13 '21 at 21:18