I have a python program that accesses databases for stuff that needs to be displayed on a screen. It's purpose is to display when a person's order is ready to be picked up. I have all the code to get the data and display it on the window. However, I need every 60 seconds to re-query the databases as some orders will be picked up and need to disappear from the list and some need to be added. I just don't know how to do this, as it appears that once the app.mainloop() is called, it takes human interaction with the window to make something happen. Any assistance would be greatly appreciated... Sorry for being long winded!
Here is an example I threw together to show you some basics of how you can use after() to check ever so many seconds to update your tracker.
Let me know if you have any questions.
import tkinter as tk
class Example(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.geometry("600x400")
self.current_ticket_number = 1
self.data = [[97, "Mike"], [98, "Kaite"], [99, "Tom"]]
self.display_frame = tk.Frame(self)
self.display_frame.grid(row=2, column=0, columnspan=3, sticky="nsew")
self.lbl1 = tk.Label(self, text="Next ticket number: {}".format(self.current_ticket_number))
self.lbl1.grid(row=0, column=0)
self.lbl2 = tk.Label(self, text="Customer Name: ".format(self.current_ticket_number))
self.lbl2.grid(row=0, column=1)
self.entry1 = tk.Entry(self)
self.entry1.grid(row=0, column=2)
tk.Button(self, text="Refresh List", command=self.refresh).grid(row=1, column=0, pady=5)
tk.Button(self, text="Submit new ticket", command=self.new_ticket).grid(row=1, column=1, pady=5)
self.timed_refresh()
def new_ticket(self):
x = self.entry1.get().strip()
if x != "":
self.data.append([self.current_ticket_number, x])
#self.refresh() # you could do self.refresh() here if you want to update as soon as you create a ticket
#I left it out though so you can see how after() works below.
if self.current_ticket_number >= 99:
self.current_ticket_number = 1
else:
self.current_ticket_number += 1
def refresh(self):
self.display_frame.destroy()
self.display_frame = tk.Frame(self)
self.display_frame.grid(row=2, column=0, columnspan=3, sticky="nsew")
for ndex, item in enumerate(self.data):
tk.Label(self.display_frame, text=r"Order #{} is ready for {}.".format(item[0], item[1])).grid(row=ndex, column=1)
tk.Button(self.display_frame, text=r"Remove Ticket".format(item[0], item[1]), command=lambda x=ndex: self.remove_ticket(x)).grid(row=ndex, column=0)
def remove_ticket(self, ndex):
self.data.pop(ndex)
self.refresh()
def timed_refresh(self):
#this after statement is set for every 6 seconds
self.after(6000, self.timed_refresh)
self.refresh()
if __name__ == "__main__":
Example().mainloop()
Here is what I ended up with. Seems to do what I need it to do. Thanks for all the help, it was spot on.
class Application(tk.Frame):
def __init__(self,master=None):
self.createWidgets()
def createWidgets(self):
tk.Frame.__init__(self)
self.pack()
for b in range(0,int(len(myItems)/2)):
#print (myItems[b])
self.btn = tk.Button(self)
self.btn["text"] = myItems[b,0]
# self.btn["command"] = (lambda tck=b, binst=btn : pickUp(tck, binst))
# self.btn["command"] = lambda ticketNo=myItems[b,1] : self.pickUp(ticketNo)
self.btn.pack(fill='x')
def pp(self) :
#print('Im in pp')
self.destroy()
getArrowDataAndUpdateSQLite()
myItems = getDisplayData()
app.createWidgets()
app.master.after(30000, self.pp)
app = Application()
app.master.title('Customer Order Status')
app.master.after(30000,app.pp)
app.mainloop()
Related
I'm building a desktop application that lets you insert some data into a form and then the data is displayed in a series (3) of Treeview widgets.
This is the form that I'm using to enter new data:
It's in a Toplevel widget. When the Add button is pressed the new data is stored in a file and it also should insert the new data in the corresponding Treeview Widget.
This is the root window:
It's comprised of 3 Treeview widgets. The purpose of the application is to give the user the opportunity to sort candidates into the right Treeview widget.
The issue that I'm facing is that when the Add button is pressed the new data is not shown in the Treeview widget and no errors are given. I think it may be an issue of class instantiation. This is an excerpt from my app, please see below a Minimal, Complete and Verifiable example
class MainApp(tk.Tk):
def __init__(self, *args, **kwargs):
...
# frame and menu classes are instantiated here
self.FrameList = {ViableCandidates: ViableCandidates(self),
NotViableCandidates: NotViableCandidates(self),
InProgressCandidates: InProgressCandidates(self)}
...
def InstanceLinker(self, frame):
link = self.FrameList[frame]
return link
class GUIMenu(tk.Menu):
def __init__(self, parent):
...
# menu code is here
addcandidates.add_command(label='Quick Add', command=lambda: QuickAdd(parent))
class QuickAdd(tk.Toplevel):
def __init__(self, parent):
...
# code for the small Toplevel window
...
# this is the code that I use to add the new item to Treeview when the Add button is pressed
if CandidateInfo['status'] == 'Viable':
app.InstanceLinker(ViableCandidates).AddtoList()
elif CandidateInfo['status'] == 'Not Viable':
app.InstanceLinker(NotViableCandidates).AddtoList()
else:
app.InstanceLinker(InProgressCandidates).AddtoList()
# ViableCandidates, NotViableCandidates, InProgressCandidates are created with the same pattern
class InProgressCandidates(tk.Frame):
def __init__(self, parent):
global Counter
tk.Frame.__init__(self, parent)
self.columnconfigure(0, weight=1)
self.rowconfigure(1, weight=1)
title = tk.Label(self, text="Candidates In Progress", font="Verdana 10 bold")
title.grid(row=0, column=0, sticky='nesw')
self.tree = ttk.Treeview(self)
self.tree.grid(row=1, column=0, sticky='nesw')
scrollbar = ttk.Scrollbar(self, orient='vertical', command=self.tree.yview)
scrollbar.grid(row=1, column=1, sticky='nws')
self.tree.config(columns=('Name', 'Date'), selectmode='browse', height=20, yscrollcommand=scrollbar.set)
self.tree.column('#0', width=20, minwidth=10, stretch=tk.YES)
self.tree.column('Name', width=150, minwidth=10, stretch=tk.YES)
self.tree.column('Date', width=80, minwidth=10, stretch=tk.YES)
self.tree.heading('#0', text='#', anchor=tk.W)
self.tree.heading('Name', text='Name', anchor=tk.W)
self.tree.heading('Date', text='Date', anchor=tk.W)
if Counter < 4:
Counter += 1
self.PopulateList()
def PopulateList(self):
selection = Database().SelectFromDB('name, date', "status = 'In progress'")
for i in range(len(selection)):
name = list(selection[i])[0]
date = adjusttotimezone(list(selection[i])[1])
self.tree.insert("", i, name, text=i + 1)
self.tree.set(name, 'Name', name)
self.tree.set(name, 'Date', date)
CandidateCounter['InProgressCandidates'] = i
def AddtoList(self):
CandidateCounter['InProgressCandidates'] += 1
print('I was here')
self.tree.insert("", CandidateCounter['InProgressCandidates'], CandidateInfo['name'],
text=CandidateCounter['InProgressCandidates'])
self.tree.set(CandidateInfo['name'], 'Name', CandidateInfo['name'])
selection = Database().SelectFromDB('date', "name = '" + CandidateInfo['name'] + "'")
date = adjusttotimezone(list(selection[0])[0])
self.tree.set(CandidateInfo['name'], 'Date', date)
app = MainApp()
app.mainloop()
When the "Add" button is pressed there are no errors and "I was here" is printed so the AddtoList method is instantiated, but there are no new items added to Treeview. I did check if the variables that I'm using to create the new Treeview item hold the correct data and they do.
EDIT: This is a Minimal, Complete and Verifiable example:
import tkinter as tk
from tkinter import ttk
Bigbadtext = ''
Counter = 0
class MainApp(tk.Tk):
def __init__(self, *args, **kwargs):
self.MainWindow = tk.Tk.__init__(self, *args, **kwargs)
menu = GUIMenu(self)
self.config(menu=menu)
frame = InProgressCandidates(self)
frame.grid(row=0, column=1, sticky='nesw')
self.FrameList = {InProgressCandidates:InProgressCandidates(self)}
def InstanceLinker(self, frame):
link = self.FrameList[frame]
return link
class GUIMenu(tk.Menu):
def __init__(self, parent):
tk.Menu.__init__(self, parent)
addcandidates = tk.Menu(self, tearoff=0)
self.add_cascade(label='Add Candidates', menu=addcandidates)
addcandidates.add_command(label='Quick Add', command=lambda: QuickAdd(parent))
class QuickAdd(tk.Toplevel):
def __init__(self, parent):
tk.Toplevel.__init__(self, parent)
saysomething = tk.Entry(self)
saysomething.grid(row=1, column=0)
def addbutton():
global Bigbadtext
Bigbadtext = saysomething.get()
app.InstanceLinker(InProgressCandidates).AddtoList()
okbutton = ttk.Button(self, text='Add', command=addbutton)
okbutton.grid(row=2, column=0)
class InProgressCandidates(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.tree = ttk.Treeview(self)
self.tree.grid(row=1, column=0, sticky='nesw')
scrollbar = ttk.Scrollbar(self, orient='vertical', command=self.tree.yview)
scrollbar.grid(row=1, column=1, sticky='nws')
self.tree.config(columns='something', selectmode='browse', height=20, yscrollcommand=scrollbar.set)
self.tree.column('#0', width=20, minwidth=10, stretch=tk.YES)
self.tree.column('something', width=150, minwidth=10, stretch=tk.YES)
self.tree.heading('#0', text='#', anchor=tk.W)
self.tree.heading('something', text='Say something', anchor=tk.W)
def AddtoList(self):
global Counter
Counter += 1
print('I was here')
self.tree.insert("", Counter, Bigbadtext, text=Counter)
self.tree.set(Bigbadtext, 'something', Bigbadtext)
app = MainApp()
app.mainloop()
The problem is that you are creating two treeview widgets, and then adding items to the one that is invisible.
You create one here:
frame = InProgressCandidates(self)
Then you create another one here:
self.FrameList = {InProgressCandidates:InProgressCandidates(self)}
Since you've already created one, the one you created should be what goes in self.FrameList:
self.FrameList = {InProgressCandidates:frame}
It is not really an answer but I up voted the question because it solved me a problem. I wanted to add items to the widget but did not want to show it to the user until I finished to populate the tree. But each insert showed right away. Now I create 2 identical widgets, one visible and the other is not, and once it is populated I change between them. Thus even a mistake can have a benefit.
Is it even possible to set the absolute position of a grid within Tkinter? I am trying to create a GUI that looks like the one below, but I am probably going about it the wrong way. So if it is possible, how do you set the grid position?
Target GUI:
This is how my GUI is turning out, so far:
As you can see, my New Contact needs to be on the right, while the Contact List should be on the left. I understand how to move the Contact List using absolute values, but can I do the same for my grid elements? Or should I use absolute values with all of them, combined with padding?
Currently, this is my code:
from tkinter import *
contacts=['Justin Day']
class Contact_manager (Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Contact Manager")
self.pack(fill=BOTH, expand=1)
#New contact grid
Label (self, text = "New Contact").grid (row=0, columnspan=2)
Label (self, text = "First Name:").grid (row=1, sticky=E)
Label (self, text = "Last Name:").grid (row=2, sticky=E)
Label (self, text = "Phone#").grid (row=3, sticky=E)
self.entry1 = Entry(self)
self.entry2 = Entry(self)
self.entry3 = Entry(self)
self.entry1.grid (row=1, column=1)
self.entry2.grid (row=2, column=1)
self.entry3.grid (row=3, column=1)
friend_check = IntVar()
self.friend_check = Checkbutton (self, variable = friend_check,
command = self.friend_box,
text = "Friend")
self.friend_check.grid (row=4, columnspan=2)
Label (self, text = "Email:").grid (row=5, sticky=E)
Label (self, text = "Birthday:").grid (row=6, sticky=E)
self.entry4 = Entry(self)
self.entry5 = Entry(self)
self.entry4.grid (row=5, column=1)
self.entry5.grid (row=6, column=1)
#Contact listbox
Label (self, text = "Contact List").place(x=20, y=190)
contact_lb = Listbox(self)
for i in contacts:
contact_lb.insert(END, i)
contact_lb.bind("<<ListboxSelect>>", self.onSelect)
contact_lb.place(x=20, y=210)
def onSelect(self, val):
sender = val.widget
idk = sender.curselection()
value = sender.get(idx)
self.var.set(value)
def friend_box():
if friend_check.get() == 1:
contacts.append(Friend(f, l, p, e, bd))
else:
contacts.append(Person(f, l, p))
def main():
root = Tk()
ex = Contact_manager(root)
root.geometry('600x700+200+100')
root.mainloop()
if __name__ == '__main__':
main()
You should take a divide-and-conquer approach to laying out widgets in a GUI. Don't try to do everything at once or use one geometry manager to coordinate everything in one window. Be methodical, and tackle one small problem at a time.
For example, in your target GUI it appears you have four sections: the contact list, a search box and button, a new contact form, and something in the lower right corner (search results?). If I am correct that those are four distinct areas, start by creating four frames. Use grid to place them in the four corners of the main window. Give each frame a distinct color (for debugging purposes). Now, fiddle with options until those four areas grow and shrink in the way that you want. Make sure you give the columns and rows weight so that they all resize properly.
Now that you've done that, you have four smaller, more manageable layout problems. Now, it could be that I'm wrong -- maybe you have two areas, left and right. Or maybe you have three -the left, and then the upper right and the lower right. For now we'll assume I'm right but the technique remains the same regardless.
It looks like you already have the layout for the contact form, so move those into the upper-right frame. Make sure they all expand and shrink properly when you grown and shrink the window (and thus, you grow and shrink the containing frame).
Once you have done that, work on the next section -- put the contact list in the upper left corner. Again, make sure it all resizes properly. At this point you shouldn't have to worry about the widgets on the right because you already have those sorted out. For this section you don't need grid, you can use pack since it's just a couple widgets stacked on top of each other. However, you can use whichever makes the most sense.
Continue on this way, working on the remaining two corners of the GUI. Be methodical, and tackle small independent sections one at a time.
I did something similar, check it out:
from Tkinter import Tk, N, S, W, E, BOTH, Text, Frame,Label, Button,Checkbutton, IntVar,Entry
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Windows")
Label(text="Contact List").grid(row=0,column=0,columnspan=2)
Text(width=30,height=15).grid(row=1,rowspan=9, column=0,columnspan=2,padx=20)
Button(text="Display Contact").grid(row=10, column=0,columnspan=2,pady=10)
Label(text="Last Name:").grid(row=11, column=0,pady=10)
Entry().grid(row=11,column=1)
Button(text="Search").grid(row=12,column=0,columnspan=2)
Label(text="New Contact").grid(row=0,column=2,columnspan=2)
Label(text="First Name:").grid(row=1,column=2,sticky=E)
Entry().grid(row=1,column=3)
Label(text="Last Name:").grid(row=2,column=2,sticky=E)
Entry().grid(row=2,column=3)
Label(text="Phone #:").grid(row=3,column=2,sticky=E)
Entry().grid(row=3,column=3)
friend_check = IntVar()
Checkbutton(variable=friend_check, command = self.friend_box, text = "Friend").grid(row=4,column=3,sticky=W)
#Label(text="Friend").grid(row=4,column=3,padx=20,sticky=W)
Label(text="Email:").grid(row=5,column=2,sticky=E)
Entry().grid(row=5,column=3)
Label(text="Birthday:").grid(row=6,column=2,sticky=E)
Entry().grid(row=6,column=3)
Button(text="Add Contact").grid(row=7,column=3,sticky=E)
def friend_box(self):
if friend_check.get() == 1:
print '1'
else:
print '0'
def main():
root = Tk()
root.geometry("600x450+900+300")
root.resizable(0,0)
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
Here is something that looks much closer to what you need:
from tkinter import *
contacts=['Justin Day']
class Contact_manager (Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Contact Manager")
self.pack(fill=BOTH, expand=1)
#New contact grid
Label (self, text = "New Contact").grid (row=0, column=2, columnspan=2, sticky=W)
Label (self, text = "First Name:").grid (row=1, column=1, sticky=E)
Label (self, text = "Last Name:").grid (row=2, column=1, sticky=E)
Label (self, text = "Phone#").grid (row=3, column=1, sticky=E)
self.entry1 = Entry(self)
self.entry2 = Entry(self)
self.entry3 = Entry(self)
self.entry1.grid (row=1, column=2)
self.entry2.grid (row=2, column=2)
self.entry3.grid (row=3, column=2)
friend_check = IntVar()
self.friend_check = Checkbutton (self, variable = friend_check,
command = self.friend_box,
text = "Friend")
self.friend_check.grid (row=4, column=2, columnspan=2)
Label (self, text = "Email:").grid (row=5, column=1, sticky=E)
Label (self, text = "Birthday:").grid (row=6, column=1, sticky=E)
self.entry4 = Entry(self)
self.entry5 = Entry(self)
self.entry4.grid (row=5, column=2)
self.entry5.grid (row=6, column=2)
#Contact listbox
Label (self, text = "Contact List").grid(row=0)
contact_lb = Listbox(self)
for i in contacts:
contact_lb.insert(END, i)
contact_lb.bind("<<ListboxSelect>>", self.onSelect)
contact_lb.grid(row=1, rowspan=5)
def onSelect(self, val):
sender = val.widget
idk = sender.curselection()
value = sender.get(idx)
self.var.set(value)
def friend_box():
if friend_check.get() == 1:
contacts.append(Friend(f, l, p, e, bd))
else:
contacts.append(Person(f, l, p))
def main():
root = Tk()
ex = Contact_manager(root)
root.geometry('600x700+200+100')
root.mainloop()
if __name__ == '__main__':
main()
I am not sure if you should mix .grid() and .place(), as far as I know, you shouldn't mix .pack() and .grid(). Anyway I would try not to mix any of them.
And about main question 'how do you set position of a grid', well, just try to draw what you expect on paper, and try to divide it into rows and columns...
So I am currently trying to create a button on a GUI that will let the user generate a new entry field.
I have no idea how to do this. I'm guessing that it will require a lambda function, but apart from that, I have no idea.
Here's the basic code I have so far:
from tkinter import *
class prac:
def autoAddWidget(self,frame,x,y):
self.entryField = Entry(frame,text="Entry Field")
self.entryField.grid(row=x, column=y)
#lambda function?
def __init__(self, master):
frame = Frame(master, width=60, height=50)
frame.pack()
x=1
self.addWidgetButton = Button(frame, text="Add new widget", command=self.autoAddWidget(frame, x,0))
self.addWidgetButton.grid(row=0, column=0)
x+=1
root = Tk()
app = prac(root)
root.mainloop()
Would appreciate the help.
Thanks
You're passing to the command argument result from the method self.autoAddWidget(frame, x,0) not method itself. You have to pass there a reference to a callable object, a function that will be called when the event occurs. Please check a documentation next time before you ask the question.
Ok, I fixed the code, now it works:
from tkinter import *
class Prac:
def autoAddWidget(self):
self.entryField = Entry(self.frame,text="Entry Field")
self.entryField.grid(row=self.x, column=0)
self.x+=1
def __init__(self, master):
self.frame = Frame(master, width=60, height=50)
self.frame.pack()
self.x=1
self.addWidgetButton = Button(self.frame, text="Add new widget", command=self.autoAddWidget)
self.addWidgetButton.grid(row=0, column=0)
root = Tk()
app = Prac(root)
root.mainloop()
In the below code I am having trouble with the line self.dmenu1.bind("<Button-1>", self.branches), and I'd be really grateful if someone can please set me in the right direction.
I'm expecting to select the an option in the dropdown menu and it changes the sorting inside the Listbox below it.
However what is actually happening, is that after I make my selection, then I have to click the drop down box one more time before the sorting takes effect.
This is not how users would expect the dropdown menu to work. I've posted the full code, as you can see I'm new to it all, but it's a nice challenge to learn :)
Thanks in advance for your help.
Regards,
from tkinter import *
ALL = N+S+W+E
users = ['Fred Asus','Tom Yahoo','Jessy Samsung','Jermain Sony','Nikki Nikon',
'Ian IBM','Elena Google','Rob Braun','Tammy Tonika','James Intel',
'Murphy Richards','Daniel Denon']
branchlst = {138:'Driving - St Albans', 170:'Brighton', 271:'Driving - Birmingham',
330:'Leeds', 680:'Edinburgh'}
class Application(Frame):
def __init__(self, master=None):
#initiate the primary window.
Frame.__init__(self, master)
self.master.rowconfigure(0, weight=1)
self.master.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=0)
self.rowconfigure(1, weight=0)
self.rowconfigure(2, weight=3)
self.columnconfigure(0, weight=0)
self.columnconfigure(1, weight=1)
self.columnconfigure(2, weight=1)
self.grid(sticky=ALL)
self.frameset()
def frameset(self):
#define and setup frames with columns and rows for widgets
#Colours added to framesets to help designing layout. delete them
self.Frame1 = Frame(self) # D
self.Frame2 = Frame(self, bg='blue') # E
self.Frame3 = Frame(self) # L
self.Frame4 = Frame(self, bg='blue') # E
self.Frame5 = Frame(self) # T
self.Frame6 = Frame(self) # E colours
self.Frame1.rowconfigure(0,weight=0)
self.Frame2.rowconfigure(0,weight=0)
self.Frame3.rowconfigure(0,weight=1)
self.Frame4.rowconfigure(0,weight=1)
self.Frame5.rowconfigure(0,weight=1)
self.Frame6.rowconfigure(0,weight=1)
self.Frame1.columnconfigure(0,weight=0)
self.Frame2.columnconfigure(0,weight=0)
self.Frame3.columnconfigure(0,weight=1)
self.Frame4.columnconfigure(0,weight=1)
self.Frame5.columnconfigure(0,weight=1)
self.Frame6.columnconfigure(0,weight=1)
self.Frame1.grid(row=0, column=0, rowspan=1, columnspan=1, sticky=ALL)
self.Frame2.grid(row=0, column=1, columnspan=2, sticky=ALL)
self.Frame3.grid(row=1, column=0, rowspan=2, sticky=ALL)
self.Frame4.grid(row=1, column=1, columnspan=2, sticky=ALL)
self.Frame5.grid(row=2, column=1, rowspan=1, columnspan=1, sticky=ALL)
self.Frame6.grid(row=2, column=2, sticky=ALL)
label4a = Label(self.Frame4, text='table1', bg='orange')
label4b = Label(self.Frame4, text='table2', bg='yellow')
label4a.pack(side=LEFT)
label4b.pack(side=RIGHT)
self.objects()
def objects(self):
var = StringVar()
var.set('Name')
self.dmenu1 = OptionMenu(self.Frame1, var,'Costcode','Name')
self.dmenu1.pack(side=TOP, fill=BOTH)
self.dmenu1.bind("<Button-1>", self.branches)
self.f3ListBox = Listbox(self.Frame3, selectmode='single')
#self.branches()
self.f3ListBox.grid(sticky=ALL)
self.f3ListBox.bind("<Button-3>", self.f1handler1)
f5ListBox = Listbox(self.Frame5, selectmode='single')
n = 0
for item in users:
f5ListBox.insert(n,item)
n += 1
f5ListBox.grid(sticky=ALL)
f6ListBox = Listbox(self.Frame6, selectmode='single')
f6ListBox.insert(1,'S123456') # DELETE
f6ListBox.insert(2,'S313414') # DELETE
f6ListBox.insert(3,'S573343') # DELETE
f6ListBox.grid(sticky=ALL)
def f1handler1(self, event):
"""Creates a popup menu for the alternative mouse button.
Edit this to add more options to that popup"""
select = lambda: self.f3ListBox.delete(ACTIVE)
popup = Menu(self, tearoff=0)
popup.add_command(label='Quit',command=self.quit)
popup.add_command(label='delete',command=select) #add more of these for more options
try:
popup.post(event.x_root, event.y_root)
except:
pass
def branches(self, event):
self.f3ListBox.delete(0,END)
n = 0
if self.dmenu1.cget('text') == 'Costcode':
cc = sorted(list(branchlst.keys()))
for item in cc:
self.f3ListBox.insert(n,str(item)+' '+branchlst[item])
n += 1
elif self.dmenu1.cget('text') == 'Name':
bb = sorted(list(branchlst.values()))
for item in bb:
for name,val in branchlst.items():
if item == val:
self.f3ListBox.insert(n,item+' '+str(name))
root = Tk()
app = Application(master=root)
app.mainloop()
I prefer the route of understanding the problem and solving it, so let us go through it. In your code you have self.dmenu1.bind("<Button-1>", self.branches).
Did you ask yourself when is this event actually fired ? It is fired when you click on the OptionMenu. This means that the current option will be the one used. So, suppose option "a" was active and you changed to option "b". This selection change doesn't fire a Button-1 event, but when you click on your OptionMenu again it will fire and then the widget will have "b" as the current option.
What you actually in your code is:
self.dmenu1 = OptionMenu(self.Frame1, var,'Costcode','Name',
command=self.branches)
and the earlier mentioned binding can be safely eliminated. The just added command option will call a certain function whenever a selection is made on your OptionMenu. Besides this change, you probably also want to populate the listbox bellow it when the program starts. For that, call self.branches(None) after you have defined self.f3ListBox.
The StringVar class has a trace method, which allows you to attach a callback function to it. The function will be called when the variable changes value.
In your code, add this line just below the var.set('Name') line in the objects method.
var.trace('w', self.branches)
This will cause self.branches to be called whenever var changes. It will be called with three arguments, so you'll need to change branches' definition to:
def branches(self, name, index, mode):
You should also delete the self.dmenu1.bind("<Button-1>", self.branches) line, as it is now redundant.
I am having difficulty updating a python Tkinter frame. I draw the frame with
some labels and text fields, when a person presses a button, I want to do some
calculations and update the labels and text fields. I can print the data to my
stdout, but I cannot get the Tk screen to update. How can I get the countFld to display an updated value?
class Application(Frame):
def __init__(self):
self.root = Tk()
Frame.__init__(self, self.root)
self.count = 0
self.createWidgets()
def createWidgets(self):
self.countFrame = Frame(self, bd=2, relief=RIDGE)
Label(self.countFrame, text='Count:').pack(side=LEFT, padx=5)
self.countFld = IntVar()
Label(self.countFrame, text=str(self.count)).pack(side=RIGHT, padx=5)
self.countFld.set(self.count)
self.countFrame.pack(expand=1, fill=X, pady=10, padx=5)
self.CNTBTN = Button(self)
self.CNTBTN["text"] = "UPDATE"
self.CNTBTN["fg"] = "red"
self.CNTBTN["command"] = self.update_count
self.CNTBTN.pack({"side": "left"})
def update_count(self):
self.count = self.count + 1
print "Count = %" % self.count #prints correct value
self.countFld.set(self.count) #Does not update display
Your problem is that you do not attach the Variable to the widget. In addition you need to use a StringVar, as the Label Widget operates on Strings and not Ints.
Try something like:
self.countStr = StringVar()
self.countStr.set(str(self.count))
Label(self.countFrame, textvariable=self.countStr).pack(side=RIGHT, padx=5)
Tk updates the display when the eventloop is idle. So you need to re-enter the event loop after you set the new value.
You should try destroying the label itself and making it again in the code with the updated text and use self.root.update()