Adding Checkbutton Options from database with Tkinter Menubutton - python

I have categories saved in a database on table Geo_Cat. I know my geo_list is getting populated correctly, because I was able to make an OptionMenu earlier. I also printed the list and it worked. So the query is good. However, I need to be able to select more than one option at a time and need to use a MenuButton instead. The options that I need are none and the categories in the table. I've been able to add the "None" checkbutton, but I haven't been able to add the geo_list. Below is a code excerpt:
from Tkinter import *
root = Tk()
location_frame = Frame(root)
location_frame.grid(column=0, row=0, sticky=(N, W, E, S))
location_frame.columnconfigure(0, weight=1)
location_frame.rowconfigure(0, weight=1)
location_frame.pack(pady=25, padx=50)
geo_list= ["geo1","geo2","geo3","geo4"]
amb = Menubutton(location_frame,text="Geo Category", relief=RAISED)
amb.grid(sticky="ew", row=1,column=0)
amb.menu = Menu(amb,tearoff=0)
amb['menu'] = amb.menu
Item0 = IntVar()
amb.menu.add_checkbutton(label="None", variable=Item0)
location_vars = {}
for category in geo_list:
location_vars["Item{0}".format(category)] = IntVar()
amb.menu.add_checkbutton(label=geo_list[category])
amb.pack()
root.mainloop()
I also tried this:
location_vars["Item{0}".format(category)] = IntVar()
amb.menu.add_checkbutton(label=geo_list[category],
variable=location_vars["Item{0}".format(category)])
How can I add my geo_list to the checkbuttons? Any advice would be greatly appreciated.

If you want the items in the geo_list for menu labels, why not just set them; you are already looping over them:
amb.menu.add_checkbutton(label=category)
Also, don't pack amb at the very end; you have already gridded it earlier.
I'm adding an example of how to trace changes associated with each menu item. I have changed the code slightly but I think you will have no problem to get the general idea.
I'm using a BooleanVar() instead of an IntVar(), then each var is saved in location_vars with the key "Item{0}".format(category). Finally I'm setting up a trace for changes in each menu item to to a callback function which will inspect the selections.
Is this what you are after?
from tkinter import *
root = Tk()
amb = Menubutton(root, text="Geo Category", relief=RAISED)
amb.pack(padx=50, pady=25)
amb.menu = Menu(amb, tearoff=0)
amb['menu'] = amb.menu
def callback(*args):
# Callvack function is called when menu items are changed
for key, value in location_vars.items():
print(key, value.get())
print() # To make the printout more readable
geo_list= ["None","geo1","geo2","geo3","geo4"]
location_vars = {}
for category in geo_list:
location_vars["Item{0}".format(category)] = BooleanVar()
# Set "variable" for every menu item
amb.menu.add_checkbutton(label=category,
variable=location_vars["Item{0}".format(category)])
# Trace changes in the variables
location_vars["Item{0}".format(category)].trace("w", callback)
root.mainloop()

Related

Clearing objects from a frame, without deleting the Frame

I'm attempting to create a simple point of sale system where when a button is pressed, its quantity and price are added up and eventually a total is shown (haven't gotten to this bit yet)
I've decided to also incorporate a clear button which will clear the frame in which the clicked items and their prices + quantities are shown however I'm having some problems with clearing the frame and still being able to click buttons afterwards.
This is the code I have for the Item button:
def AddButton():
global item_num #calls global variable
item_num += 1
item_text = "Chips 2.00"+" "+str(item_num) #concatonates text & variable
item1.config(text=item_text) #updates label text - doesn't add multiple
item1.pack()
addButton = Button(itemFrame, text="Chips", width=10, height=10, command=AddButton)
addButton.grid(row=1, column=1)
item1 = Label(receiptFrame)
and I began by trying to use .destroy like this:
def clearClick(): #blank function for clear button
receiptFrame.destroy()
however, since this completely deletes the frame, I'm then not able to re-input more items after it's been cleared
I also tried re-creating the frame:
def clearClick(): #blank function for clear button
receiptFrame.destroy()
receiptFrame = Frame(root, width=600, height=500, bd=5, relief="ridge")
receiptFrame.grid(row=1, column=3, columnspan=2)
but this still doesn't work
Is there a way to clear the contents of a frame without deleting the frame itself or does .destroy have to be used?
fr.winfo_children() returns the list of widgets inside the frame:
root = tk.Tk()
fr = tk.Frame()
lb = tk.Label(fr)
lb.grid()
print(fr.winfo_children())
for child in fr.winfo_children():
child.destroy()
print(fr.winfo_children()) # Now empty

Tkinter Accessing Variables from Different Function

Is there a way to access variables from different files if the widget is an Entry? I have tried using the command option but found that was exclusive to Buttons. I'm trying to separate my functions into different files to modulate.
ttk.Label(root, text="How many points do you want to input:").pack()
cell_content = StringVar()
cell_content.trace_add("write", my_tk.retrieve_cell_content)
cell_content_entry = Entry(root, width = 8, textvariable = cell_content)
cell_content_entry.pack()
tkinterFunctions.py
def retrieve_cell_col(self, *args):
global CELL_COL
temp = cell_col.get()
temp = temp.upper()
If I get it right, you want to get your text in Entry widget when it is writing. Not by pushing a Button. please check this if I am right:
from tkinter import *
def call(tex):
print(tex.get())
root = Tk()
tx = StringVar()
tx.trace("w", lambda name, index, mode, tex=tx: call(tex))
entry = Entry(root, textvariable=tx)
entry .pack()
root.mainloop()

Radiobutton not updating values when clicked in python with tkinter

This is my first attempt at a GUI. Right now I just want to be able to click a radiobutton and make it print the value I assigned to the button. However, var.get() isn't giving me anything. I tried it with IntVar (and had my values as 1 and 2 instead of "proton" and "electron") and var.get() would just give me 0. With StringVar it gives nothing (nothing prints when choosecharge is called by the radiobutton). I've tried reading stuff about radiobuttons and I wrote my code based on how I saw it done and it successfully creates the radiobuttons, but the whole point is to be able to use their values when clicked.
import tkinter as tk
def choosecharge():
print(var.get())
root = tk.Tk()
var = tk.StringVar()
proton = tk.Radiobutton(root, text = "proton", variable = var, value = "proton", command = choosecharge)
proton.pack( )
electron = tk.Radiobutton(root, text="electron", variable = var, value= "electron", command = choosecharge)
electron.pack( )
root.mainloop()
I have taken a slightly different approach to accomplish this task.
I created a dictionary of the integer radiobutton values as key and
the string that you wish to print as value.
Used a label widget to print the string in the GUI
import tkinter as tk
root = tk.Tk()
# define an IntVar
var = tk.IntVar()
# create a dictionary of key:value pair as radiobutton_value: str_name_to_print
values = {1: "proton", 2: "electron"}
# instantiate a label widget
lbl = tk.Label(root)
def choosecharge():
# update the label widgets using the dictionary
lbl.config(text=values[var.get()])
proton = tk.Radiobutton(root, text="proton", variable=var, value=1, command=choosecharge)
proton.pack(anchor=tk.W)
electron = tk.Radiobutton(root, text="electron", variable=var, value=2, command=choosecharge)
electron.pack(anchor=tk.W)
# pack the label widget below the two radiobuttons
lbl.pack()
root.mainloop()
Screenshot
I have commented the lines in the code for better understanding. I hope this solution helps you.

How to autocall a function with a Listbox based on data in a separate Entry Widget without a button

I am trying to have my Listbox automatically run a query and populate immediately when corresponding Entry box has a value. This would be done without the use of a UPDATE or SELECT button(command=). If all fails I will have to resort to a button function call... I was hoping this could be accomplished without the use of a button. Essentially the autoquery would get (l) from 'team_input' and update levlistbox with the database result.
def autoquery(l):
levListbox.delete(0, "end")
l = team_input.get()
cursor = dbi.cursor()
cursor.execute("""SELECT level FROM teamstatus WHERE game='%s'"""%(l,))
rows = cursor.fetchall()
for results in rows:
levListbox.insert("end", results)
root.after(5000, autoquery)
root = Tk()
teamLabel=Label(topListFrame, text="Team", font="Verdana 8 bold")
teamLabel.grid(row=0,column=0)
team_input = StringVar()
team_input = Entry(topListFrame, textvariable=team_input, width=10)
team_input.grid(row=1,column=0)
levLabel=Label(topListFrame, text="Level", font="Verdana 8 bold")
levLabel.grid(row=0,column=1)
levListbox=Listbox(topListFrame, height=1,width=8)
#TRIED TO USE lambda WITH autoquery(team_input))
levListbox.grid(row=1, column=1)
autoquery()
root.mainloop()
You can callback a method when the string in an entry is changed by making use of special tkinter variables or variable classes such as StringVar and the method trace_add. Now you already seem to want to use StringVar but:
team_input = StringVar()
team_input = Entry(topListFrame, textvariable=team_input, width=10)
lines make team_input first be the variable class required to do that but you then overwrite that variable with Entry which makes not much sense. Try replacing to:
team_input_var = StringVar()
team_input = Entry(topListFrame, textvariable=team_input_var, width=10)
and then add before mainloop:
team_input_var.trace_add('write', autoquery)
If you want to call autoquery whenever what's written in entry is changed.
Also note that def autoquery(l) looks redundant, but since trace_add sends 3 somewhat not related arguments, replace it with def autoquery(*args).

Python Tkinter retrieving input of multiple values

Here is the below code and I am having issues surrounding retrieving input from multiple values. I have been working on this issue for some time now without any suggest. I do appreciate the insight; however, I am at wits end. If someone could please provide a fix to my code I would be ever so grateful.
#!C:/Python27/python.exe
from Tkinter import *
import ImageTk, Image
root = Tk()
root.title('HADOUKEN!')
def retrieve_input(text,chkvar,v):
textarea_result = text.get()
checkbox_result = chkvar.get()
radiobutton_result = v.get()
root.destroy()
text = Text(root, height=16, width=40)
scroll = Scrollbar(root, command=text.yview)
text.configure(yscrollcommand=scroll.set)
text.grid(sticky=E)
scroll.grid(row=0,column=1,sticky='ns')
text.focus()
chkvar = IntVar()
chkvar.set(0)
c = Checkbutton(root, text="CaseIt", variable=chkvar)
c.grid(row=1,column=0,sticky=W)
v = ""
radio1 = Radiobutton(root, text="Src", variable=v, value=1)
radio1.grid(row=1,column=0)
radio1.focus()
radio2 = Radiobutton(root, text="Dst", variable=v, value=2)
radio2.grid(row=2,column=0)
b1 = Button(root, text="Submit", command=lambda: retrieve_input(text,chkvar,v))
b1.grid(row=1, column=2)
img = ImageTk.PhotoImage(Image.open("Hadoken.gif"))
panel = Label(root, image = img)
panel.grid(row=0, column=2)
root.mainloop()
print textarea_result
print checkbox_result
print radiobutton_result
You have several problems in your code, though most of them produce errors that should be self-explanatory. My suggestion is to start over with just a single widget, and get the logic working for that to reduce the number of things that could go wrong. Once you have that working, you can then add one widget at a time as you learn how to use that widget.
That being said, here are the most obvious errors that I spotted:
The first problem is that you are incorrectly calling the get method of a text widget. This method is documented to take two arguments -- a starting index and an ending index. Since tkinter always adds a trailing newline, you want to get everything from the start ("1.0"), to the end minus one character ("end-1c"). Thus, you should be getting the value in the text widget like this:
textarea_result = text.get("1.0", "end-1c")
The second problem is that retrieve_input seems to assume that v is a StringVar or IntVa since you are calling a get method on it. Given that you are using that variable with a radiobutton, that's what it should be. However, you created it as a normal variable, which of course doesn't have a get method. You should declare it as one of the special tkinter variables:
...
v = StringVar()
radio1 = Radiobutton(root, text="Src", variable=v, value=1)
...
The third problem is, retrieve_input is setting local variables. If you want to set the value of global variables (which I assume, since you are later trying to access them after the widget is destroyed), then you need to declare them as global:
def retrieve_input(text,chkvar,v):
global textarea_result, checkbox_result, radiobutton_result
...

Categories