[Tkinter] Update value in Entry widget - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: [Tkinter] Update value in Entry widget (/thread-2576.html) |
Update value in Entry widget - dannyH - Mar-25-2017 I'm very new to tkinter. How do I get a value to display every time it changes? The code below only shows the last entry in the Entry widget, but print shows all the values (python 3.6.0) from tkinter import * def start(): for n in range(1000000): if n%100000 == 0: v.set(str(n)) def makeWindow () : global v win = Tk() frame1 = Frame(win) frame1.pack() Label(frame1, text="Number").grid(row=0, column=0, sticky=W) v = StringVar() m = Label(frame1, textvariable=v) m.grid(row=0, column=1, sticky=W) frame2 = Frame(win) frame2.pack() b1 = Button(frame2,text=" Start ",command=start) b1.pack(side=LEFT) return win win = makeWindow() win.mainloop() RE: Update value in Entry widget - metulburr - Mar-26-2017 it doesnt look like the problem is with GUI, it looks like your problem is with your programming. Quote:def start(): for n in range(1000000): if n%100000 == 0: v.set(str(n)) Every time you hit the button you execute start(). This function sets the string var (v) to every 100K (0-900000) in a split second. The last value 900000 gets seen as the label because its the last iteration and the completion of the function. Thus you will not see any other number in the label like you would with the print function...assuming this is what you wanted to do? EDIT: Do you mean something like this? I would suggest to use classes instead of global keywords. from tkinter import * class Values: def __init__(self): self.vals = [] self.index = 0 self.assign() def assign(self): '''get our values''' for n in range(1000000): if n%100000 == 0: self.vals.append(n) def reset(self): '''what do we do when we iterate all values? Start at 0''' if self.index > len(self.vals)-1: self.index = 0 def callback(self): '''execute when button gets pressed''' self.reset() v.set(self.vals[self.index]) self.index += 1 win = Tk() v = StringVar() obj = Values() frame1 = Frame(win) frame1.pack() Label(frame1, text="Number").grid(row=0, column=0, sticky=W) m = Label(frame1, textvariable=v) m.grid(row=0, column=1, sticky=W) frame2 = Frame(win) frame2.pack() b1 = Button(frame2,text=" Start ",command=obj.callback) b1.pack(side=LEFT) #win = makeWindow() win.mainloop() RE: Update value in Entry widget - dannyH - Mar-26-2017 Hi metulburr. Thanks for the quick reply. Your solution is not quite what I want. I have been "programming" in python for quite a few years as a means of solving some cryptographic puzzles, but without using classes. I just use python as a type of programmable calculator to manipulate text to find solutions to problems. Now I have retired I thought I would try to make my programs look a bit smarter. Some of the programs I write take days to execute, and I have been using print to show me that the program is still running and to give me an idea of how far it has progressed. I was trying to use tkinter to display the results on screen every time that a particular variable changed without me having to press the "start" button each time. The example I posted was just a simple program that I hoped would show me the count updating in the Entry box each time it changed, as it does on the console if I put a "print(n)" statement in the loop. RE: Update value in Entry widget - Barrowman - Mar-31-2017 A metulburr said you code is updating so fast the eye cannot register the changes so you only see the last one. If you import time and changed your example code to this def start(): for n in range(1000000): if n%100000 == 0: v.set(str(n)) time.sleep(0.5)you would see the values changing. RE: Update value in Entry widget - metulburr - Mar-31-2017 (Mar-31-2017, 04:38 PM)Barrowman Wrote: A metulburr said you code is updating so fast the eye cannot register the changes so you only see the last one. But because of it being tkinter you cant use time sleep on any GUI as it blocks the execution, you have to use after RE: Update value in Entry widget - dannyH - Mar-31-2017 Hi Barrowman. Thanks for the reply. I'll have a look at the after method and see if I can get it to work. RE: Update value in Entry widget - wuf - Apr-01-2017 Hi dannyH I assume you want to update the value of a Label not Entry? If you use a Label to display a changing value the following script may help you: (Use of threading and after()) #!/usr/bin/env python # -*- coding: utf-8 -*- import threading try: # Tkinter for Python 2.xx import Tkinter as tk import Queue as qu except ImportError: # Tkinter for Python 3.xx import tkinter as tk import queue as qu APP_TITLE = "Update Label Display" APP_XPOS = 100 APP_YPOS = 100 APP_WIDTH = 300 APP_HEIGHT = 200 UPDATE_TIME = 500 # Milliseconds QUEUE_SIZE = 10 POLLING_TIME = 500 # Milliseconds class AppThread(threading.Thread): def __init__(self, queue=None, max_number=0, modulo=0): self.queue = queue self.max_number = max_number self.modulo = modulo threading.Thread.__init__(self) self.start() def run(self): num_count = 0 while num_count < self.max_number: if num_count%self.modulo == 0: self.update_queue(num_count) num_count += 1 def update_queue(self, num_count): self.queue.put(num_count) self.queue.join() class Application(tk.Frame): def __init__(self, master): self.master = master self.master.protocol("WM_DELETE_WINDOW", self.close) tk.Frame.__init__(self, master) self.max_number = 1000000 self.modulo = 100000 self.app_thread = None self.control_frame = tk.Frame(self) self.control_frame.pack(expand=True) tk.Label(self.control_frame, text="Number:").pack(fill='x', pady=(0,1)) self.var = tk.StringVar() tk.Label(self.control_frame, relief='sunken', bg='white', width=10, textvariable=self.var).pack(fill='x', pady=(0,10)) tk.Button(self.control_frame, text=" Start ", command=self.start_thread).pack(fill='x') self.queue = qu.Queue(QUEUE_SIZE) self.queue_polling() def start_thread(self): if self.app_thread == None: self.app_thread = AppThread( self.queue, self.max_number, self.modulo) else: if not self.app_thread.isAlive(): self.app_thread = AppThread( self.queue, self.max_number, self.modulo) def queue_polling(self): if self.queue.qsize(): try: data = self.queue.get() self.var.set(str(data)) self.queue.task_done() except qu.Empty: pass self.after(POLLING_TIME, self.queue_polling) def close(self): print("Application-Shutdown") self.app_thread.join() self.master.destroy() def main(): app_win = tk.Tk() app_win.title(APP_TITLE) app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS)) app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT)) app = Application(app_win).pack(fill='both', expand=True) app_win.mainloop() if __name__ == '__main__': main()wuf RE: Update value in Entry widget - dannyH - Apr-02-2017 Many thanks. That is the functionality I was looking for, although the code is a bit more complicated than I am used to writing. Now that I have more free time I will investigate tkinter, classes and threading and hopefully write better python programs in the future. The problem with the original code was not speed - I slowed it down by a factor of 100 so that it took 32 seconds to run, but still the only value that appeared in the window was the last one to be calculated. |