How to destroy a specific widget at once ? Tkinter - python

When i pressed the "Create New" button a submit button will be appear at the bottom. But whenever i choose the drop down value the submit button will be destroyed and a new button called "Update" will be shown. But the problem is that, when I repeatedly choose the drop down value and go back to "Create New" button, the "update" button can only be destroy once. Is it a way to find all the update button and destroy all at once ? Thanks
When i pressed create new button :
When i choose a few times of drop down list value and go back to "create new", the submit and update button is stacked together :
Code:
def submit():
deleteAllEntry()
global CreateJsonBtn, profilenameLbl, ProfileNameEntry
CreateJsonBtn = Button(jsonframe, text="Submit", command=submit, width=11)
CreateJsonBtn.place(x=370, y=540)
CreateNewJsonBtn.configure(state=DISABLED)
UpdateJsonBtn.destroy()
#Get value inside the dropdown value
def dropdown(choice):
if (jsonprofileName == ""):
tkMessageBox.showinfo("ERROR", "Fail to retrieve value. Try again later", icon="error")
else:
cursor = con.cursor()
cursor.execute("select * from json where jsonprofilename='" +options.get() + "'")
rows = cursor.fetchall()
deleteAllEntry()
global row
for row in rows:
insertAllEntry()
cursor.close()
try:
#Delete submit button when select existing value
CreateJsonBtn.destroy()
CreateNewJsonBtn.configure(state=NORMAL)
except:
pass
finally:
global UpdateJsonBtn
UpdateJsonBtn = Button(jsonframe, text="Update", command=submit, width=11)
UpdateJsonBtn.place(x=370, y=550)

Instead of destroying and creating buttons multiple times, you can configure them, check the example below
from tkinter import *
def foo():
print('called foo')
button.configure(text='bar',command=bar)
def bar():
print('called bar')
button.configure(text='foo',command=foo)
root=Tk()
button=Button(root,text='foo',command=foo)
button.pack()
root.mainloop()
config/configure is a universal widget method, you can use this refernece to learn more about them.
The reason you are currently facing the issue is that every time the dropdown is used, a new button "Update" is placed on top of the previous one (if one already exists). The UpdateJsonBtn holds the last assigned instance and hence deletes the topmost one, if there are buttons underlying, they will not be destroyed. I would not suggest the approach currently used by you.
In the question you stated if there is a way to get all the buttons that say "Update", you can do that using the following (again, I am not suggesting to use this in your case, but just to answer your question)
for widget in jsonframe.winfo_children():
if isinstance(widget,Button):
if widget['text']=='Update':
widget.destroy()

So I know that it should work with CreateJsonBtn.place_forget()
You can try that

Related

ttk.Combobox triggers <<ListboxSelect>> event in different tk.Listbox

What i am trying to do: I am trying to build a GUI using tkinter in Python (i am using version 3.7.7 on Windows) with a main window that has a Listbox and a second window that contains a Combobox.
In the Listbox there are different files that can be opened. When clicking on each entry some additional information are displayed in the main window (That part is not in my shorter example code below). So what i did was binding the Listbox to a function that loads and displays the information (function_1 in the code below) with the <<ListboxSelect>> event.
The second window can be opened with a button and should edit the selected file. In the Combobox in the second window are different options that change other elements of the second window depending on whats selected. Thats why i bind the <<ComboboxSelected>> event to a different function (function_2 in the code below).
My problem with this is: When i select a value in the Combobox of the second window, the first function that is binded to the Listbox of the first window is executed just after the correct function for the Combobox. This only happens the first time a value for the Combobox is selected, for each time the second window is created. Also when looking at the selected value of the Listbox it returns the selected value of the Combobox.
Edit: I just noticed this problem only happens when i previously selected an item in the Listbox. So like i said below it might have something to do that the Listbox is still active or something like that.
My code and an example:
import tkinter as tk
from tkinter import ttk
class MainGUI:
def __init__(self):
self.root = tk.Tk()
items = ['Test 1', 'Test 2', 'Test 3']
self.item_box = tk.Listbox(self.root)
self.item_box.insert('end', *items)
self.item_box.bind('<<ListboxSelect>>', self.function_1)
self.item_box.pack()
tk.Button(self.root, text='Open second window',
command=self.open_window).pack()
self.root.mainloop()
def function_1(self, event):
print('MainGUI function:', event)
print('Text in Listbox:', self.item_box.selection_get())
def open_window(self):
SecondGUI()
class SecondGUI:
def __init__(self):
self.window = tk.Toplevel()
self.window.grab_set()
items = ['A', 'B', 'C']
self.dropdown = ttk.Combobox(self.window, values=items)
self.dropdown.current(0)
self.dropdown.pack()
self.dropdown.bind('<<ComboboxSelected>>', self.function_2)
def function_2(self, event):
print('SecondGUI function:', event)
MainGUI()
Image of the GUI before and after the option B is clicked
The output after selecting Test 1, opening the second window with the button and selecting B looks like this:
MainGUI function: <VirtualEvent event x=0 y=0>
Text in Listbox: Test 1
SecondGUI function: <VirtualEvent event x=0 y=0>
MainGUI function: <VirtualEvent event x=0 y=0>
Text in Listbox: B
My guess: If i had to guess what the problem is, i would say the Combobox maybe had some sort of Listbox in it that sends the event, but as i wasn't able to find more about when and how these events are sent, i couldn't really find anything about it (Edit: Less likely). When looking at the picture, you can see that the entry in the first window is still selected until the entry in the second window is clicked, so my second guess would be that the Listbox is still active and takes the new selected value when it is clicked or something like that (Edit: more likely).
My question: Why does the first function execute when i use a different widget in a different window, how can i fix this, or are there any better way to do this in the first place?
TL;DR: A Listbox recieves an event when a Combobox is selected in a different window. Why?
Thanks in advance!
It may be due to that exportselection=False is not set for both the Listbox and Combobox. So when an item in the Combobox is selected, it will clear the selection of Listbox which triggers the <<ListboxSelect>> event.
Also you have used wrong function, self.item_box.selection_get(), to get the current selected item of Listbox. self.item_box.get(self.item_box.curselection()) should be used instead.
Below changes should fix the issue:
class MainGUI:
def __init__(self):
...
self.item_box = tk.Listbox(self.root, exportselection=False)
...
def function_1(self, event):
print('MainGUI function:', event)
print('Text in Listbox:', self.item_box.get(self.item_box.curselection()))
...
class SecondGUI:
def __init__(self):
...
self.dropdown = ttk.Combobox(self.window, values=items, exportselection=False)
...
...

Drop down button in Tkinter OptionMenu

I need to update my list when I click the button to drop down list:
How can I bind the button to some function?
The event you're looking for is Activate:
optmenu.bind('<Activate>', onactivate)
Your onactivate callback takes an Activate event, but you probably don't care about its attributes.
The second half of your problem is how to update the menu. To do this, you use the menu attribute, which is a Menu object, on which you can call delete and add and whatever else you want. So, for example:
def onactivate(evt):
menu = optmenu['menu']
menu.delete(0, tkinter.END)
menu.add_command(label='new choice 1')
menu.add_command(label='new choice 2')
menu.add_separator()
menu.add_command(label='new choice 3')
optvar.set('new choice 1')
(However, notice that, while setting the var at the end does cause that to become the new default selection, and does show up in the menu header, it doesn't cause the selected item to be highlighted if the cursor isn't over any of the menu items. If you want that, it's tricky, so hopefully you don't.)
'<Activate>' didn't work but i found '<Button-1>' and now it works.
optmenu.bind('<Button-1>', onactivate)
Thank you :)

How to create a combobox that includes checkbox for each item?

Fairly new to tkinter and python I was wondering how to achieve a button that would act like this :
Click on button drops down a list (so that's a combobox)
Each line of the list has a checkbox.
Finally if a checkbox is clicked run a function, or (even better) once combobox is no more dropped run a function with items checked as args.
UPDATE
The button/menuButton will have to act like a filter. When menu is dropped down user can uncheck multiple options (without the menu to disappear each time an item is clicked) he don't want. Therefore it's really important to be able to see checkboxes so as the user know which options are currently active.
I finally used the idea of Bryan by creating a top level frame. Here is what I have :
There is no widget to do what you want. You'll have to create a toplevel window with a bunch of checkbuttons. You can then trigger the appearance with a normal button.
I don't think the OptionMenu is intended to hold anything but strings. It sounds like you want the functionality of a Listbox, which has options to allow for multiple selections, get all selected items, and so on.
This gives you an OptionMenu with checkboxes in the contained Menu. Check whichever items you like, then right-click in the tkinter window to print the values of the checkboxes to the console.
from tkinter import *
master = Tk()
var = StringVar(master)
var.set("Check")
w = OptionMenu(master, variable = var, value="options:")
w.pack()
first = BooleanVar()
second = BooleanVar()
third = BooleanVar()
w['menu'].add_checkbutton(label="First", onvalue=True,
offvalue=False, variable=first)
w['menu'].add_checkbutton(label="Second", onvalue=True,
offvalue=False, variable=second)
w['menu'].add_checkbutton(label="Third", onvalue=1,
offvalue=False, variable=third)
master.bind('<Button-3>', lambda x: print("First:", first.get(), " Second:",
second.get(), " - Third:", third.get()))
mainloop()
See also this.

Tkinter add entry on basis of an answer of a OptionMenu

I'm using TKinter (I'm new with GUI tools), and I would like to know if it is possible to add (or activate) a entry with base on the answer of a option menu. Below is a part of the code
from Tkinter import *
win=Tk()
Label(win, text="Is This a Data Cube?",font='20').grid(row=14, column=0,sticky=W)
DataCubeValue = StringVar(win)
DataCubeValue.set("False")
DataCube = OptionMenu(win,DataCubeValue,"True","False")
DataCube.grid(row=15, column=0,sticky=W)
If the answer is True is choosen I would like to display this:
Label(win, text="X and Y values (x,y)",font='20').grid(row=14, column=1,sticky=W)
XYValue = StringVar(win)
XYValue.set("10,7")
XY = Entry(win,textvariable=XYValue)
XY.grid(row=15, column=1,sticky=W)
A central idea of GUI programming is to register code to be executed in reaction of user actions. Such code is usually named callback (the toolkit call it back depending on user actions on the interface).
You can bind to DataCubeValue changes with the following line. callback method (to be defined before) will be cause each time the value of DataCubeValue change.
DataCubeValue.trace("w", callback)
In the callback method, you can either choose to place the block of code with Label and Entry instantiation, but think that callback will be called every time the user change the OptionMenu value. You could either deactivate the OptionMenu once the user used it, but I would advise to instantiate your widgets in the initial run, and just display or hide them from the callback.
def callback(*args):
if DataCubeValue.get() == "True":
label.grid(row=14, column=1,sticky=W)
XY.grid(row=15, column=1,sticky=W)
else:
label.grid_forget()
XY.grid_forget()

Pass text to menu label in tkinter

I want to make the text under the selection, in variable 'a' to appear as a label of the menu.
Here is the code:
def popup(event):
a=t_start.get("sel.first", "sel.last")
menu.post(event.x_root, event.y_root)
return a
def insert_word():
pass
t_start.bind("<Button-3>", popup)
menu = Menu(root, tearoff=0)
menu.add_command(label="Set selection 1", command=set_selection_1)
menu.add_command(label="Set selection 2", command=set_selection_2)
menu.add_command(label="%s" %popup, command=set_selection_2)
Right now, all I get is function popup address.
If I try popup.a, I get an error, function has no attribute 'a'. How do I overcome this and get whatever is in 'a' to be printed as menu label?
Callback methods like popup are not supposed to return anything. Instead, you should manipulate the menu from inside the function.
Also, as suggested by Brian, you probably rather want to modify an existing entry in the menu, instead of adding a new one each time you click the button. In this case, create the entry outside the function (like you do now), but use some placeholder for the label.
def popup(event):
a = t_start.get("sel.first", "sel.last")
menu.post(event.x_root, event.y_root)
menu.add_command(label=a, command=set_selection_2) # add to menu
# menu.entryconfig(2, label=a) # modify existing entry
If you want to change the text on a menu, you must use the entryconfig method. For example, to change the text of the first item you would do:
menu.entryconfig(0, label=a)

Categories

Resources