I am creating a set of buttons via this function:
from tkinter import *
from random import randint
window = Tk()
window.title("Test")
window.geometry('200x200')
color = ["red","blue","green","yellow","black","purple","orange"]
RandInt = 0
j = 0
h = 0
def ButtonDef(xvar = 0,yvar = 0):
btn = Button(command =lambda:[RandomColor()])
btn.grid()
btn.place(x = xvar*50, y = yvar*50, width = 50, height = 50)
def RandomColor():
RandInt = randint (0,6)
btn.configure(bg = color[RandInt])
while j in range (4):
i = 0
j += 1
while i in range (4):
ButtonDef(i,h)
i += 1
if i == 4:
h += 1
window.mainloop()
However, my RandomColor() function is changing only the color of the very button i have pressed - that is fun too, but i wonder how i can make it randomly change the color of all buttons. When being created by a function, i would have guessed that all buttons that were created are named "btn" since thats the only name i have given them.
How could i address all (or one specific) buttons, out of a group of created-by-function buttons?
Or to put it simply, what name do all of those buttons have? Do they share the name "btn"? Are they assigned a hidden ID?
The reason behind your problem:
The problem is that when this line is executed: btn = Button(command =lambda:[RandomColor()]) by the end of the loop, you get a reference only to the last button which is created. You loose reference to other buttons.
Solution:
You can overcome this problem if you rely on winfo_children().
You have to do 2 steps to fix your issue:
First of all, change: btn = Button(command =lambda:[RandomColor()]) to btn = Button(window, command=lambda:[RandomColor()]). That simply means we attach each created button to a parent widget called window.
Then all that you need to change is RandomColor() function body as follows:
def RandomColor():
for child in window.winfo_children():
child.configure(bg=color[randint(0,6)])
Demo:
This solves your problem but your code is not clean. You can ask for suggestions to improve your code on Code Review website.
EDIT:
Here is a solution for the scenario you described in the comment.
Note that I had to create code from scratch, cleaner one (I know you started only today, so I am not blaming you). In this code, I keep reference for every button I create:
import tkinter as tk
import random
class ChangeBottomRightColor(tk.Frame):
def __init__(self, master):
self.master = master
tk.Frame.__init__(self, self.master)
self.__colors = ["red","blue","green","yellow","black","purple","orange"]
self.configure_gui()
self.create_widgets()
def configure_gui(self):
pass
def create_widgets(self):
self.create_buttons()
def create_buttons(self):
self.buttons = {}
c = 0
for i in range(4):
for j in range(4):
self.buttons['button{}'.format(c)] = tk.Button(self.master)
self.buttons['button{}'.format(c)].grid(row=i, column=j)
self.buttons['button{}'.format(c)].config(width=3, height=3)
self.buttons['button{}'.format(c)].config(command=self.change_bottom_right_button_color)
c += 1
def get_random_color(self):
return random.choice(self.__colors)
def change_bottom_right_button_color(self):
self.buttons['button{}'.format(15)].config(bg=self.get_random_color())
if __name__ == '__main__':
root = tk.Tk()
main_app = ChangeBottomRightColor(root)
root.mainloop()
Demo:
Let try
btn = []
for i in range(16):
btn.append(Button(window))
it will create an array of button. So you can access by btn[i].configure(command=lambda:[RandomColor()]) or something else.
Related
I am having a little trouble with this project that I am working on. My project is this GUI application. In my test.py file, I call another file that contains instructions for another GUI window. This is where I am having trouble. In the test.py file, if you click run, a small window will appear. Click TEST in the small window. Then another window will appear that contains text fields if you enter numbers into the text fields for the window and then click enter. My IDE gets these error messages. It says that " ValueError: could not convert string to float: ' ' " My question is how do I fix this so that I do not get this error message? It is supposed to print the input that was entered into the window. I have two files, test.py, and model_objects.py. If you run model_objects.py by itself, it works perfectly. But when I try to import this file into test.py, it does not want to work right. This is programmed in Python. Also, my model_objects.py file is placed in a folder called util in the project. The values that I entered are floating-point values. I am having trouble with this. If you can help, I would greatly appreciate it.
Here is my code:
model_objects.py (This is in a folder called util in the project.)
import tkinter as tk
from tkinter import ttk
from tkinter.ttk import Style
import numpy as np
from util import InputData
class Harmonic_Oscillator:
def __init__(self):
self.type = 0
self.name = "Harmonic Oscillator"
self.nparam = 2
self.label = ["\u03BC", "k"]
self.param = np.zeros(self.nparam, float)
def set_param(self, param_list):
for i in range(self.nparam):
self.param[i] = param_list[i]
return
class Morse_Oscillator:
def __init__(self):
self.type = 1
self.name = "Morse Oscillator"
self.nparam = 3
self.label = ["\u03BC", "De", "a"]
self.param = np.zeros(self.nparam, float)
def set_param(self, param_list):
for i in range(self.nparam):
self.param[i] = param_list[i]
return
class Test_Oscillator:
def __init__(self):
self.type = 2
self.name = "Test Oscillator"
self.nparam = 4
self.mu = 0
self.label = ["a", "b", "c", "d"]
self.param = np.zeros(self.nparam, float)
def set_param(self, param_list):
for i in range(self.nparam):
self.param[i] = param_list[i]
return
def model_prompt(potential_model):
window1 = tk.Tk()
style = Style()
window1.title('PyFGH Parameters')
box_length = 103
for q in range(3):
box_length = box_length + 33 * potential_model[q].nparam
box_len_str = '300x' + str(box_length)
window1.geometry(box_len_str)
entries = []
qvar = np.empty(3, dtype=list)
for i in range(3):
qvar[i] = []
j = 0
y = 5
for q in range(3):
for qparam in range(potential_model[q].nparam):
qvar[q].append(tk.StringVar())
ttk.Label(window1, text=potential_model[q].label[qparam] + " for Q:" + str(q + 1) + ":",
font=("Times New Roman", 15)).place(x=50, y=y)
# set text variable as q1var[j] , each entry will have separate index in the list
a1 = ttk.Entry(window1, textvariable=qvar[q][qparam], font=("Times New Roman", 10)).place(x=140, y=y)
j += 1
y += 35
def enter_button():
for q in range(3):
param_list = []
for qparam in range(potential_model[q].nparam):
param_list.append(qvar[q][qparam].get())
potential_model[q].set_param(param_list) # This is giving me error. Not working properly!!!
for q in range(3):
for qparam in range(potential_model[q].nparam):
print(potential_model[q].param[qparam])
InputData.output.items.model_data = potential_model
print(InputData.output.items.model_data)
window1.destroy()
enter = tk.Button(window1, text='Enter', bd='20', bg='green', fg='white',
command=enter_button).place(x=110, y=y)
window1.mainloop()
def output2():
sections = []
for i in range(3):
if InputData.output.items.v[i] == "Model-Harmonic Oscillator":
sections.append(Harmonic_Oscillator())
elif InputData.output.items.v[i] == "Model-Morse Oscillator":
sections.append(Harmonic_Oscillator())
elif InputData.output.items.v[i] == "Model-Test Oscillator":
sections.append(Harmonic_Oscillator())
#test = [Harmonic_Oscillator(), Morse_Oscillator(), Test_Oscillator()]
#model_prompt(test)
Here is another file called test.py
from util import InputData
from util import model_objects
from util import model_objects
from util.model_objects import Harmonic_Oscillator, Morse_Oscillator, Test_Oscillator, model_prompt
import tkinter as tk
def write_slogan():
test = [Harmonic_Oscillator(), Morse_Oscillator(), Test_Oscillator()]
model_prompt(test)
root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
button = tk.Button(frame,
text="QUIT",
fg="red",
command=quit)
button.pack(side=tk.LEFT)
slogan = tk.Button(frame,
text="TEST",
command=write_slogan)
slogan.pack(side=tk.LEFT)
root.mainloop()
It's a bit esoteric, but the issue is this line in your model_prompt function:
qvar[q].append(tk.StringVar())
The quick fix would be:
qvar[q].append(tk.StringVar(window1))
The tkinter variable types' constructors accept an optional parameter - a handle to the window to which the associated entry widget is attached. If none is supplied, by default, it will pick the first tk.Tk window that was instantiated (in your case, that was root in test.py). The StringVars will update themselves whenever the event queue of the bound window has cleared. Since you spawned a new tk.Tk, this interrupted your root event queue, and since your variables were bound to root, they did not update despite text being entered in the entries.
If you wanted to be super proper, you should look into tk.Toplevel or tkinter.simpledialog to spawn child windows. Your program should never have more than one tk.Tk window in the first place.
i made a little example, i hope it matches yourr mainproblem. if you want to work with classes, in the most cases you need references.
from tkinter import *
class MainWindow(Tk):
def __init__(self):
super(MainWindow, self).__init__()
self.test = Test(self) # test class import
self.outputLbl = Label(self) # output Label
self.outputLbl.pack(side="top", fill="x", ipady=20)
class Test(Frame):
def __init__(self, parent):
super(Test, self).__init__()
self.parent = parent # you can use this way to call between classes
self._input = Entry(self.parent)
self._input.pack()
self._input.bind("<Return>", self.outputMW)
def outputMW(self, event): # function, when pressing return it gives changes the text in your label
var = self._input.get()
self.parent.outputLbl.config(text=var) # self.parent makes the reference to your other class
if __name__ == '__main__':
mw = MainWindow()
mw.geometry("500x500")
mw.mainloop()
I am trying to use lambda to create callbacks for tkinter buttons.
There are multiple buttons and each callback needs to pass an object inside it. Following code is what I am doing and is running fine
var0 = tk.StringVar()
label = tk.Label(top, bg = "White",height = 2, width = 12,textvariable=var0, justify="right")
def b0Callback(var):
var.set(var.get()+"0")
return
# creating a label which will print value of the any of the 0-9 button pressed
# creating a button 0
b0 = tk.Button(numFrame0, height = 1, width = 4, bg = "grey", text =
"0",command = lambda: b0Callback(var0))
#there are more buttons like that
var0 is used to update a label. Above code is working fine but I have to create callback for 0 to 9 and I have to just repeat above definition. So I tried using following example from this tutorial
def myfunc(n):
return lambda a : a * n
mydoubler = myfunc(2)
mytripler = myfunc(3)
print(mydoubler(11))
print(mytripler(11))
Using it I did following
def Callback(n):
return lambda var.set(var.get()+n)
b0Callback = Callback("0")
This shows error invalid index in the return line at var.set
Is there any way to pass var0 in this case to avoid this error?
Maybe its only me, but I don't see a reason for using lambda if you just want to add a number to the label text.
Lets make a function for it that gets your StringVar() as a variable and adds some number to it:
def button_callback(str_var, number):
str_var.set(str_var.get() + str(number))
To run this command we simply put it in the code as a lambda function, otherwise it will run upon initialization (because we are providing a function instead of a reference).
So to run it within a button we declare it like this:
my_button = Button(root, text='Some text here', command=lambda: button_callback(my_string_var, 5))
The '5' could be potentially changed to any other number.
I have now solved the problem, here is the final code:
I have also changed the number of buttons to 300 and added code to arrange them all in a nice grid, just for fun. (You can change this to however many you want by changing for number in range(1, whatever).
import tkinter as tk
class Window(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.var0 = tk.StringVar()
self.var0.set('0')
# creating buttons and adding them to dictionary
self.buttons = {}
for number in range(1, 301):
self.buttons.update({'button' + str(number): tk.Button(self, height=1, width=4, bg="grey", text=number)})
label = tk.Label(self, textvariable=self.var0, font='none 50')
label.grid(column=0, row=0)
for button in self.buttons:
self.buttons[button].bind('<Button-1>', lambda event, num=button[6:]: self.Callback(event, num))
self.buttons[button].grid(column=(int(button[6:]) % 10), row=(int(button[6:]) / 10) + 1)
def Callback(self, event, num):
self.var0.set(num)
self.update()
I am trying to create a Tkinter app, where when you press a button, a new Window opens which has continually updating text about certain parts of the program. My problem is the section of code where I am trying to add the text to the screen. This is what I have written:
import tkinter as tk
import time
class TextWindow(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.textArea = tk.Text(self, height = 10, width = 30)
self.textArea.pack(side = "left", fill = "y")
bar = tk.Scrollbar(self)
bar.pack(side = "right", fill = "y")
bar.config(command = self.textArea.yview)
def output(self, value):
outputVal = str(value)
self.textArea.inser('end', "{0}\n".format(outputVal))
self.textArea.see('end')
def openWindow():
textWindow = tk.Toplevel(root)
textFrame = TextWindow(textWindow)
textFrame.pack()
value = 0.0
alive = True
while alive:
if textWindow.winfo_exists:
value = value + 0.1
textFrame.output(value)
time.sleep(0.1)
else:
alive = False
root = tk.Tk
btn = tk.Button(root, text = "Click", command = openWindow)
btn.pack()
root.mainloop()
When I comment out the while loop in the openWindow method, the window opens and closes, and reopens, no problem. However when the code is there, I never see the window when I press the button.
I tried running it through the IDLE debugger, and I am not getting any errors, and everything runs through the loop fine, however the Window still never appears. What is my problem?
The answer that Jason S gave is not a good example. You can avoid any issues with sleep by just using after() instead. Don't settle for "Kinda works".
Here is a break down of how you could accomplish what you need without having the problems associated with sleep() and tkinter.
First you are importing Tk() wrong. Don't do tk.Tk do tk.Tk()
Now lets move the entire program into a single class. This will provide us with the ability to use class attributes and make things a bit easier to work with.
Here we create a class called guiapp(tk.Frame): you can name it what you want but this is just my example. Then make sure you are passing root using guiapp(root) so we can work in this class on the tk.Tk() instance. This will be shown at the bottom of the program where the class is instantiated.
Because we have passed root to the class we can place the button that opens the Toplevel window on our self.master attribute.
UPDATE: Changed how data is sent to the Textbox in Toplevel so we can retain the information in case you want to reopen top level. per your comment.
import tkinter as tk
class guiapp(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.value = 0.0
self.alive = True
self.list_for_toplevel = [] # added list to retain values for Toplevel
btn = tk.Button(self.master, text = "Click", command = self.TextWindow)
btn.pack()
Here we add the method to define the Topelevel we are going to create.
Because everything is inside this one class we can create this Topelevel as a Toplevel of self.master. At the end of this method we call the self.timed_loop() method I added that manages the timed portion of your program. UPDATE: added a call to a new function.
def TextWindow(self):
self.textWindow = tk.Toplevel(self.master)
self.textFrame = tk.Frame(self.textWindow)
self.textFrame.pack()
self.textArea = tk.Text(self.textWindow, height = 10, width = 30)
self.textArea.pack(side = "left", fill = "y")
bar = tk.Scrollbar(self.textWindow)
bar.pack(side = "right", fill = "y")
bar.config(command = self.textArea.yview)
self.alive = True
self.add_list_first()
UPDATE: Added a new function called add_list_first(self):. This will allow us to first add any values that are stored in the list then we can call timed_loop() to continue appending the list and counting.
def add_list_first(self):
for item in self.list_for_toplevel:
self.textArea.insert('end', "{}\n".format(item))
self.textArea.see('end')
self.timed_loop()
Here we have created a method to perform the task you have in you code for the Toplevel that uses the after() function from tkinter. ever 1000 is equal to 1 second, so play with that timer if you want. The first part of after() is for the time in milliseconds and the 2nd part is the function being called. In this case it calls itself to continue the loop until either the Toplevel window self.textWindow is closed or the self.alive variable is no longer True.
UPDATE: I have added a for loop to insert the list instead of directly imputing each value. This way we can retain the data if we want to reopen the Toplevel.
def timed_loop(self):
if self.alive == True and tk.Toplevel.winfo_exists(self.textWindow):
self.master.after(1000, self.timed_loop)
self.value += 1
self.list_for_toplevel.append(self.value)
self.textArea.delete(1.0, "end-1c")
for item in self.list_for_toplevel:
self.textArea.insert('end', "{}\n".format(item))
self.textArea.see('end')
else:
self.alive = False
This is the preferred way to start your class going in tkinter. As you can see we have created root as tk.Tk() and passed root into the the class guiapp(). Also note that I assigned this instance of the class to the variable name myapp. This will allow us to interact with the class from outside of the class if you ever need to. It does not make a difference in this case but I thought I would add it just the same.
if __name__ == "__main__":
root = tk.Tk()
myapp = guiapp(root)
root.mainloop()
Here is the copy paste version for you to use.
import tkinter as tk
class guiapp(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.value = 0.0
self.alive = True
self.list_for_toplevel = []
btn = tk.Button(self.master, text = "Click", command = self.TextWindow)
btn.pack()
def TextWindow(self):
self.textWindow = tk.Toplevel(self.master)
self.textFrame = tk.Frame(self.textWindow)
self.textFrame.pack()
self.textArea = tk.Text(self.textWindow, height = 10, width = 30)
self.textArea.pack(side = "left", fill = "y")
bar = tk.Scrollbar(self.textWindow)
bar.pack(side = "right", fill = "y")
bar.config(command = self.textArea.yview)
self.alive = True
self.add_list_first()
def add_list_first(self):
for item in self.list_for_toplevel:
self.textArea.insert('end', "{}\n".format(item))
self.textArea.see('end')
self.timed_loop()
def timed_loop(self):
if self.alive == True and tk.Toplevel.winfo_exists(self.textWindow):
self.master.after(1000, self.timed_loop)
self.value += 1
self.list_for_toplevel.append(self.value)
outputVal = str(self.value)
self.textArea.insert('end', "{0}\n".format(outputVal))
self.textArea.see('end')
else:
self.alive = False
if __name__ == "__main__":
root = tk.Tk()
myapp = guiapp(root)
root.mainloop()
The problem is that you are never giving control back to the Tkinter main loop. The code gets stuck executing in the while loop, meaning Tkinter never gets to refresh the display or process any other events. You could force update by calling root.update() right before time.sleep(0.1), but this is not really optimal and the display will be unresponsive while sleeping. Depending on what you are doing, it may be good enough.
See here for additional explanation
I seem to be hitting a dead end here. I have done a decent amount of research online and have not been able to reach a solution.
My issue is, i have an "optionmenu" (#1) in my GUI, when a certain option is chosen, a new "optionmenu" (#2) is created. The user can then make his choice in #2. Based on his choice in #2, entry widgets appear and are destroyed as the option is changed. My problem is here, when optionmenu #2 is displayed and the user decides to change optionmenu#1, i am able to destroy all the entry widgets from the #1 and #2 optionmenu; however, i am still left with the optionmenu#2 in the background.
I was only able to find online solutions for
Entry & Label
However, i was unable to find any solution for
OptionMenu
Any ideas on how to destroy the option menu? A snippet of the code is below, as it currently behaves as stated above.
from Tkinter import *
neper_tessellation_type={'hard-core':'1','centroid':'3','weight':'0'}
neper_weight_type={'dirac':'1','gaussian':'2','flat':'2','bernoulli':'3'}
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
#Setting up widgets onLoad
self.grid()
self.create_widgets()
# Tessellations Type Option Builder
def tessellation_type(self, req_dim):
global tess_container
global labels_container
global weight_container
for wid in tess_container:
wid.destroy() ## Destroy the OPTIONMENU1 ENTRY CONTAINER fields
for label in labels_container:
label.destroy() ## Supposed to destroy the OptionMenu2 ITSELF, but does not do as requried.
for lid in weight_container:
lid.destroy() ## Destroy the OPTIONMENU2 ENTRY CONTAINER fields
weight_container = []
labels_container = []
tess_container = []
for type, req_dim in neper_tessellation_type.iteritems():
self.s = StringVar()
choice = self.tess_type.get()
if type == self.tess_type.get() and choice != 'weight':
u = int(req_dim)
elif choice == 'weight': ## OPTIONMENU 2 - When weight is chosen a new drop down menu is made and the function command moves to weighttype
weight_dropdown = OptionMenu(self, self.s, *neper_weight_type, command=self.weight_type).grid(row=13, column=2)
u = 0
for b in range(u):
c = Entry(self)
c.grid(row=13, column=2 + b)
tess_container.append(c) # Append widget to container list
def weight_type(self, req_dim1):
global weight_container
for lid in weight_container:
lid.destroy()
weight_container = []
for type1, req_dim1 in neper_weight_type.iteritems():
if type1 == self.s.get():
u1 = int(req_dim1)
for bf in range(u1):
t = Entry(self)
t.grid(row=13, column=3 + bf)
weight_container.append(t) # Append widget to container list
# *** MAIN FRAMES ***
def create_widgets(self):
## OPTIONMENU 1
Label(self, text="Voronoi Type").grid(row=13, column=0)
self.tess_type = StringVar()
tess_type_dropdown = OptionMenu(self, self.tess_type, *neper_tessellation_type, command=self.tessellation_type).grid(row=13, column=1)
## Reset for containers of choice
tess_container = []
labels_container = []
weight_container = []
root = Tk()
app = Application(root)
root.mainloop()
Question amended after Bryan clarification.
Thanks to #BryanOakley hint of the variable and widget not being called on. By placing the .grid on a new line and calling on the widget and appending it seemed to resolve the issue.
...
elif choice == 'weight':
self.weight_dropdown = OptionMenu(self.tessframe, self.s, *neper_weight_type, command=self.weight_type)
self.weight_dropdown.grid(row=13, column=2)
labels_container.append(self.weight_dropdown)
u = 0
...
I am an amateur python programer with 2 months of experience. I am trying to write a GUI to-do list through tkinter. The actual placement of the buttons are not important. I can play around with those after. I need some help with displaying the appended item to the list. In the program, it updates well on the digit, but it won't print onto the list. I double checked it on the console and it says "tkinter.StringVar object at 0x102fa4048" but didn't update the actual list. What I need help is how can I update the list Main_Q on my the label column? Much appreciate some direction and coding help. Thanks.
Main_Q =["read","clean dishes", "wash car"]
from tkinter import*
root=Tk(className="total tasks in the Q")
#formula
def update():
global Main_Q
a=len(Main_Q)
num.set(a)
def add2list():
Main_Q.append(name)
a=len(Main_Q)
num.set(a)
print (Main_Q)
#output
num=StringVar()
y=Label(root, textvariable=num).grid(row=0, column=1)
#input
name=StringVar()
b=Entry(root, textvariable=name).grid(row=7,column=0)
#buttons
z=Button(root, text="update", command=update).grid(row=7, column=2)
add2list=Button(root,text="add", command=add2list).grid(row=7,
column=1)
r = 0
for c in Main_Q:
Label(text=c, relief=RIDGE,width=15).grid(row=r,column=0)
r = r + 1
root.mainloop()
Your problem is that your for loop which build up your labels doesnt get called after each time you have entered a new "task". To easily fix this you can move this loop into your update function.
If you want to prevent of looping through widget everytime you can create a new list with all widgets which already have been created:
createdWidgets = []
widgetsQueue = []
In your update function you than have to iterate through the widgetsQueue (widgetsQueue.pop() for instance), create the widgets and append the widget to the createdWidgetes list.
def update():
global Main_Q
r = 0
for c in Main_Q:
Label(text=c, relief=RIDGE,width=15).grid(row=r,column=0)
r += 1 # shorthand for r = r + 1
Some addition notes:
for the entry it is easier to seperate the definition and placement:
b = Entry(root)
b.grid(row=7,column=0)
because than Entry() returns its instance and you can use it to get the text:
b.get()
if you go shopping do you throw everything into one bag ?
from tkinter import *
does axactly that(in this case the globals() variable would be the bag).If you want to read more about that Importing Python Modules. To prevent that and shorten the amount of letters to type:
import tkinter as t # or tk
root = t.Tk()
*But for sure, if you just want a small program its okay.
Design:
To resolve your problem, you need to design this simple solution:
retrieve the text of the Tkinter.Entry widget using get() method.
add the text you got in 1 to Main_Q using append() method.
bind the button that updates on click both Main_Q and your GUI using command method.
create a new Tkinter.Label widget, set its text to the value you got in 1 and increment its corresponding row in the GUI.
I prefer to organize your code within a class that contains a constructor where Main_Q is initialized so that we call initialize_user_interface() to initialize the GUI with its three elements:
def __init__(self, parent):
Tkinter.Frame.__init__(self, parent)
self.parent = parent
self.Main_Q = ["read", "clean dishes", "wash car"]
self.r = 0 # position of the row of each label
self.initialize_user_interface()
The method initialize_user_interface() does what its name says. We mainly bind the function update_gui() that inserts a new label with the text set to what the user types in Tkinter.Entry widget using command = self.update_gui
ef initialize_user_interface(self):
self.parent.title("Update GUI")
self.parent.grid_rowconfigure(0, weight = 1)
self.parent.grid_columnconfigure(0, weight = 1)
for e in self.Main_Q:
Tkinter.Label(self.parent, anchor = Tkinter.W, text = e).grid(row = self.r, sticky = Tkinter.W)
self.r+=1
self.entry_text = Tkinter.Entry(self.parent)
self.entry_text.grid(row = 0, column = 1)
self.button_update = Tkinter.Button(self.parent, text = "Update", command = self.update_gui).grid(row = 1, column = 1, sticky = Tkinter.E)
Finally, nothing is simpler than update_gui() function:
def update_gui(self):
self.r+=1 # increment the row reserved to the new label
self.Main_Q.append(self.entry_text.get())
Tkinter.Label(self.parent, anchor = Tkinter.W, text = self.entry_text.get()).grid(row = self.r, sticky = Tkinter.W)
Programming the application:
Here is the full program:
'''
Created on Mar 11, 2016
#author: Bill BEGUERADJ
'''
import Tkinter
class Begueradj(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, parent)
self.parent = parent
self.main_queue = ["read", "clean dishes", "wash car"]
self.r = 0
self.initialize_user_interface()
def initialize_user_interface(self):
self.parent.title("Update GUI")
self.parent.grid_rowconfigure(0, weight = 1)
self.parent.grid_columnconfigure(0, weight = 1)
for e in self.main_queue:
Tkinter.Label(self.parent, anchor = Tkinter.W, text = e).grid(row = self.r, sticky = Tkinter.W)
self.r+=1
self.entry_text = Tkinter.Entry(self.parent)
self.entry_text.grid(row = 0, column = 1)
self.button_update = Tkinter.Button(self.parent, text = "Update", command = self.update_gui).grid(row = 1, column = 1, sticky = Tkinter.E)
def update_gui(self):
self.r+=1
self.main_queue.append(self.entry_text.get())
Tkinter.Label(self.parent, anchor = Tkinter.W, text = self.entry_text.get()).grid(row = self.r, sticky = Tkinter.W)
def main():
root = Tkinter.Tk()
b = Begueradj(root)
root.mainloop()
if __name__ == "__main__":
main()
Demo:
Here is a screenshot of the running program:
Note:
I coded the previous program using Python 2.7, so if you want to test it, please change Tkinter to tkinter. Everything else remains the same.