Я работаю над своим пет-проектом. При работе над графическим интерфейсом я столкнулся с проблемой. Я хочу добавить новый виджет после первого нажатия на флажок, а при втором нажатии этот виджет должен быть удален. Но на самом деле у меня с этим проблема. Мой новый виджет был добавлен, но не удален. Не могли бы вы найти решение этой проблемы?
Это моя минимальная воспроизводимая часть кода. Класс Window при инициализации создает объект TK как переменную self.root и создает для него флажок cb. Этот флажок имеет команду self.create_or_delete_new_field, которая зависит от статуса cb_var, который является переменной флажка. Если cb_var имеет значение True, на self.root создается новый лабек lbl, если False — удаляется.
import tkinter as tk
class Window:
def __init__(self):
# pre-setups window
self.root = tk.Tk()
# checkbox
cb_var = tk.BooleanVar()
cb_var.set(0)
cb = tk.Checkbutton(self.root, text = "Checkbox1", onvalue=True, offvalue=False, variable=cb_var,
command=lambda: self.create_or_delete_new_field(cb_var))
cb.grid(row=0, column=0)
self.root.mainloop()
def create_or_delete_new_field(self, cb_var: bool):
lbl = tk.Label(self.root, text=f" Created Label")
if cb_var.get():
lbl.grid(row=0, column=1, sticky='w')
else:
lbl.grid_remove()
app = Window()
Я пробовал не только метод Grid_remove(), но и Grid_forget(), Destroy(). Как я вижу, корень проблемы глубже, чем эти методы, но мой опыт не может этого обнаружить.
Вот рабочий пример. Идея состоит в том, чтобы создать экземпляр Label
во время Window.__init__()
, чтобы вы создавали только одну метку. Я также использовал Window
в качестве root
, наследуя от tk.Tk
, поскольку это обычная практика. Другой трюк заключается в правильном использовании self
, чтобы метод toggle_widget
имел доступ как к cb_var
, так и к lbl
.
import tkinter as tk
class Window(tk.Tk):
def __init__(self) -> None:
super().__init__()
self.geometry('400x400')
self.title('Window')
self.cb_var = tk.BooleanVar(self, False) # you can set the initial value here
# NOTE: specifying on/off values isn't strictly necessary
self.cb = tk.Checkbutton(
self,
text='Checkbox1',
variable=self.cb_var,
command=self.toggle_widget,
)
self.cb.grid(row=0, column=0)
self.lbl = tk.Label(self, text='Hello!')
def toggle_widget(self) -> None:
if self.cb_var.get():
self.lbl.grid(row=0, column=1, sticky='w')
else:
self.lbl.grid_forget()
if __name__ == '__main__':
app = Window()
app.mainloop()
спасибо большое, ваш пример очень полезен!
Рад, что смог помочь. Если этот ответ вам помог, отметьте его как «принятый» с помощью кнопки с галочкой, чтобы другие знали, что на этот вопрос уже дан ответ.
Объяснение в виде комментариев
import tkinter as tk
class Window(tk.Tk): #make root as argument
def __init__(self):
#Add this line
super().__init__()
self.geometry('200x100')
self.title('Window')
# No need of declaring boolen_variable as we create 2 functions
# Declare self.lbl here and don't pack (or don't add grid)
#There is no need of using f-string
self.lbl = tk.Label(self, text= "Created Label")
self.cb = tk.Checkbutton(self, text = "Create Label", command=self.create_lbl)
self.cb.grid(row=0, column=0)
def create_lbl(self):
# pack the lbl here
self.lbl.grid(row=1, column=0, sticky='w')
# Change the text of check button as 'Hide label'
self.cb.configure(text = 'Hide_Label', command = self.hide_lbl)
def hide_lbl(self):
# Use grid_forget to hide label
self.lbl.grid_forget()
# Change the text of check button as 'Create label'
self.cb.configure(text = 'Create Label', command = self.create_lbl)
if __name__ == '__main__':
app = Window()
app.mainloop()
Каждый раз, когда вы звоните
create_or_delete_new_field()
, вы создаете совершенно новую метку, а затем либо делаете ее видимой, либо оставляете невидимой. Вы НИКОГДА ничего не делаете с предыдущей меткой, потому что это значениеlbl
исчезло, как только функция завершилась. Вам нужно, чтобыlbl
было чем-то постоянным — атрибутом вашего класса или глобальной переменной.