I'd like to distribute my program around the office so other people can use it when I'm not in
my code:
from tkinter import *
import os
top = Tk()
top.wm_title("testest")
top.minsize(width=300, height=150)
top.maxsize(width=300, height=150)
def runscript():
os.system('python test.py')
B = Tk.Button(top, text = 'Run test', command = runscript)
B.config(width=15, height=1)
B.pack()
top.mainloop()
Is there any way I can have my print functions in the .py file print out in a GUI text box instead of the command line?
Here's a crude demo that shows how to print text strings to a Label. Note that long strings are not wrapped. If you need that, you'll have to wrap the strings yourself by inserting \n newline characters, or use the wraplength option, as mentioned in the Label widget docs. Alternatively, you could use a Text widget instead of a Label to display the text.
My test function simulates the action of the code in your "test.py" script.
import tkinter as tk
from time import sleep
# A dummy `test` function
def test():
# Delay in seconds
delay = 2.0
sleep(delay)
print_to_gui('Files currently transferring')
sleep(delay)
print_to_gui('Currently merging all pdfs')
sleep(delay)
print_to_gui('PDFs have been merged')
sleep(delay)
print_to_gui('Finished!\nYou can click the "Run test"\n'
'button to run the test again.')
# Display a string in `out_label`
def print_to_gui(text_string):
out_label.config(text=text_string)
# Force the GUI to update
top.update()
# Build the GUI
top = tk.Tk()
top.wm_title("testest")
top.minsize(width=300, height=150)
top.maxsize(width=300, height=150)
b = tk.Button(top, text='Run test', command=test)
b.config(width=15, height=1)
b.pack()
# A Label to display output from the `test` function
out_label = tk.Label(text='Click button to start')
out_label.pack()
top.mainloop()
Note that we normally do not call time.sleep in a GUI program because it causes the whole program to freeze while the sleep is occurring. I've used it here to simulate the blocking delay that will occur when your real code is performing its processing.
The usual way to do delays in a Tkinter program that doesn't block normal GUI processing is to use the .after method.
You will notice that I replaced your from tkinter import * with import tkinter as tk. This means we need to type eg tk.Labelinstead of Label, but that makes the code easier to read, since we now know where all the different names come from. It also means we aren't flooding our namespace with all the names that tkinter defines. import tkinter as tk just adds 1 name to the namespace, from tkinter import * adds 136 names in the current version. Please see Why is “import *” bad? for further info on this important topic.
Here's a slightly fancier example that appends new text to the current Label text, with word wrapping. It also has a function clear_label to remove all the text from the Label. Rather than storing the text directly in the Label it uses a StringVar. This makes it easier to access the old text so that we can append to it.
import tkinter as tk
from time import sleep
# A Dummy `test` function
def test():
# Delay in seconds
delay = 1.0
clear_label()
print_to_label('Files currently transferring')
sleep(delay)
print_to_label('Currently merging all pdfs')
sleep(delay)
print_to_label('PDFs have been merged')
sleep(delay)
print_to_label('\nFinished!\nYou can click the "Run test" '
'button to run the test again. '
'This is a very long string to show off word wrapping.'
)
# Append `text_string` to `label_text`, which is displayed in `out_label`
def print_to_label(text_string):
label_text.set(label_text.get() + '\n' + text_string)
# Force the GUI to update
top.update()
def clear_label():
label_text.set('')
top.update()
# Build the GUI
top = tk.Tk()
top.wm_title("testest")
top.minsize(width=300, height=150)
top.maxsize(width=300, height=350)
b = tk.Button(top, text='Run test', command=test)
b.config(width=15, height=1)
b.pack()
# A Label to display output from the `test` function
label_text = tk.StringVar()
out_label = tk.Label(textvariable=label_text, wraplength=250)
label_text.set('Click button to start')
out_label.pack()
top.mainloop()
Related
I am trying to delete text inside a text box after waiting 5 seconds, but instead the program wont run and does sleep over everything else. Also is there a way for me to just make my textbox sleep so i can run other code while the text is frozen?
from time import time, sleep
from Tkinter import *
def empty_textbox():
textbox.insert(END, 'This is a test')
sleep(5)
textbox.delete("1.0", END)
root = Tk()
frame = Frame(root, width=300, height=100)
textbox = Text(frame)
frame.pack_propagate(0)
frame.pack()
textbox.pack()
empty_textbox()
root.mainloop()
You really should be using something like the Tkinter after method rather than time.sleep(...).
There's an example of using the after method at this other stackoverflow question.
Here's a modified version of your script that uses the after method:
from time import time, sleep
from Tkinter import *
def empty_textbox():
textbox.delete("1.0", END)
root = Tk()
frame = Frame(root, width=300, height=100)
textbox = Text(frame)
frame.pack_propagate(0)
frame.pack()
textbox.pack()
textbox.insert(END, 'This is a test')
textbox.after(5000, empty_textbox)
root.mainloop()
You can emulate time.sleep in tkinter. For this we still need to use the .after method to run our code alongside the mainloop, but we could add readability to our code with a sleep function. To add the desired behavior, tkinter provides another underestimated feature, wait_variable. wait_variable stops the codeblock till the variable is set and thus can be scheduled with after.
def tksleep(t):
'emulating time.sleep(seconds)'
ms = int(t*1000)
root = tk._get_default_root('sleep')
var = tk.IntVar(root)
root.after(ms, var.set, 1)
root.wait_variable(var)
Real world examples:
update a Label to display a clock while-loop
animated writing nested for-loops
Limitation:
tkinter does not quit while tksleep is used.
Make sure there is no pending tksleep by exiting the application.
Using tksleep casually can lead to unintended behavior
UPDATE
TheLizzard worked out something superior to the code above here. Instead of tkwait command he uses the mainloop and this overcomes the bug of not quitting the process as described above, but still can lead to unintended output, depending on what you expect:
import tkinter as tk
def tksleep(self, time:float) -> None:
"""
Emulating `time.sleep(seconds)`
Created by TheLizzard, inspired by Thingamabobs
"""
self.after(int(time*1000), self.quit)
self.mainloop()
tk.Misc.tksleep = tksleep
# Example
root = tk.Tk()
root.tksleep(2)
I am trying to delete text inside a text box after waiting 5 seconds, but instead the program wont run and does sleep over everything else. Also is there a way for me to just make my textbox sleep so i can run other code while the text is frozen?
from time import time, sleep
from Tkinter import *
def empty_textbox():
textbox.insert(END, 'This is a test')
sleep(5)
textbox.delete("1.0", END)
root = Tk()
frame = Frame(root, width=300, height=100)
textbox = Text(frame)
frame.pack_propagate(0)
frame.pack()
textbox.pack()
empty_textbox()
root.mainloop()
You really should be using something like the Tkinter after method rather than time.sleep(...).
There's an example of using the after method at this other stackoverflow question.
Here's a modified version of your script that uses the after method:
from time import time, sleep
from Tkinter import *
def empty_textbox():
textbox.delete("1.0", END)
root = Tk()
frame = Frame(root, width=300, height=100)
textbox = Text(frame)
frame.pack_propagate(0)
frame.pack()
textbox.pack()
textbox.insert(END, 'This is a test')
textbox.after(5000, empty_textbox)
root.mainloop()
You can emulate time.sleep in tkinter. For this we still need to use the .after method to run our code alongside the mainloop, but we could add readability to our code with a sleep function. To add the desired behavior, tkinter provides another underestimated feature, wait_variable. wait_variable stops the codeblock till the variable is set and thus can be scheduled with after.
def tksleep(t):
'emulating time.sleep(seconds)'
ms = int(t*1000)
root = tk._get_default_root('sleep')
var = tk.IntVar(root)
root.after(ms, var.set, 1)
root.wait_variable(var)
Real world examples:
update a Label to display a clock while-loop
animated writing nested for-loops
Limitation:
tkinter does not quit while tksleep is used.
Make sure there is no pending tksleep by exiting the application.
Using tksleep casually can lead to unintended behavior
UPDATE
TheLizzard worked out something superior to the code above here. Instead of tkwait command he uses the mainloop and this overcomes the bug of not quitting the process as described above, but still can lead to unintended output, depending on what you expect:
import tkinter as tk
def tksleep(self, time:float) -> None:
"""
Emulating `time.sleep(seconds)`
Created by TheLizzard, inspired by Thingamabobs
"""
self.after(int(time*1000), self.quit)
self.mainloop()
tk.Misc.tksleep = tksleep
# Example
root = tk.Tk()
root.tksleep(2)
I wrote a python 3.4.2 programme to get a user input from python IDLE, perform some processing on the input and display a few statements in the python IDLE using print().
Now I am in the process of converting this to use a GUI using tkinter. This is the simple tkinter code I wrote for the GUI.
from tkinter import *
root=Tk()
root.title("Post-fix solver")
root.geometry("500x500")
mainframe=Frame(root)
mainframe.grid(column=0, row=0)
inputval=StringVar()
inputentry=Entry(mainframe,textvariable=inputval).grid(column=1,row=1)
executebutton=Button(mainframe,text="Run",command=check_expression).grid(column=1,row=5)
outputtext=Text(mainframe).grid(column=1,row=5)
root.mainloop()
So far I was able to get the user input through the Entry widget named inputentry in the GUI and send it to a variable in the original code using inputval.get(). Then it performs the processing on the input and shows the outputs of print() statement in the python IDLE.
My question is how can I modify the programme to send all those print() statements to the Text widget named outputtext and display them in the GUI?
I would be glad if you could show me how to do this without using classes as I am a beginner in python
3 easy steps:
1) Get the content of your variable and put it to a variable that I'm gonna name varContent;
2) Clear your text widget, that is, if the name of your text widget is text, then run text.delete(0, END);
3) Insert the string you've got in your variable varContent into your text text widget, that is, do text.insert(END, varContent).
I would do my code like this:
from tkinter import *
def check_expression():
#Your code that checks the expression
varContent = inputentry.get() # get what's written in the inputentry entry widget
outputtext.delete('0', 'end-1c') # clear the outputtext text widget
outputtext.insert(varContent)
root = Tk()
root.title("Post-fix solver")
root.geometry("500x500")
mainframe = Frame(root)
mainframe.grid(column=0, row=0)
inputentry = Entry(mainframe)
inputentry.grid(column=1, row=1)
executebutton = Button(mainframe, text="Run", command=check_expression)
executebutton.grid(column=1, row=5)
outputtext = Text(mainframe)
outputtext.grid(column=1, row=5)
root.mainloop()
For Python 3.x
After creating the entry box with inputentry=Entry(mainframe).grid() you can get the typed entries with inputentry.get().
Do the following to put the typed entry in a variable and to print it in the text widget named outputtext:
entryvar=inputentry.get() # the variable entryvar contains the text widget content
outputtext.delete(1.0,tk.END) # clear the outputtext text widget. 1.0 and tk.END are neccessary. tk implies the tkinter module. If you just want to add text dont incude that line
outputtext.insert(tk.END,entryvar) # insert the entry widget contents in the text widget. tk.END is necessary.
If you're using Python 3.4+ to run the program too, you can use the contextlib.redirect_stdout to capture the print output for a duration of a few statements into a file, or even a string:
import io
from contextlib import redirect_stdout
...
file = io.StringIO()
with redirect_stdout(file):
# here be all the commands whose print output
# we want to capture.
output = file.getvalue()
# output is a `str` whose contents is everything that was
# printed within the above with block.
Otherwise a better though a bit more arduous way is to make a StringIO file and print to it, so you'd have
buffer = io.StringIO()
print("something", file=buffer)
print("something more", file=buffer)
output = buffer.getvalue()
text.insert(END, output)
I am trying to delete text inside a text box after waiting 5 seconds, but instead the program wont run and does sleep over everything else. Also is there a way for me to just make my textbox sleep so i can run other code while the text is frozen?
from time import time, sleep
from Tkinter import *
def empty_textbox():
textbox.insert(END, 'This is a test')
sleep(5)
textbox.delete("1.0", END)
root = Tk()
frame = Frame(root, width=300, height=100)
textbox = Text(frame)
frame.pack_propagate(0)
frame.pack()
textbox.pack()
empty_textbox()
root.mainloop()
You really should be using something like the Tkinter after method rather than time.sleep(...).
There's an example of using the after method at this other stackoverflow question.
Here's a modified version of your script that uses the after method:
from time import time, sleep
from Tkinter import *
def empty_textbox():
textbox.delete("1.0", END)
root = Tk()
frame = Frame(root, width=300, height=100)
textbox = Text(frame)
frame.pack_propagate(0)
frame.pack()
textbox.pack()
textbox.insert(END, 'This is a test')
textbox.after(5000, empty_textbox)
root.mainloop()
You can emulate time.sleep in tkinter. For this we still need to use the .after method to run our code alongside the mainloop, but we could add readability to our code with a sleep function. To add the desired behavior, tkinter provides another underestimated feature, wait_variable. wait_variable stops the codeblock till the variable is set and thus can be scheduled with after.
def tksleep(t):
'emulating time.sleep(seconds)'
ms = int(t*1000)
root = tk._get_default_root('sleep')
var = tk.IntVar(root)
root.after(ms, var.set, 1)
root.wait_variable(var)
Real world examples:
update a Label to display a clock while-loop
animated writing nested for-loops
Limitation:
tkinter does not quit while tksleep is used.
Make sure there is no pending tksleep by exiting the application.
Using tksleep casually can lead to unintended behavior
UPDATE
TheLizzard worked out something superior to the code above here. Instead of tkwait command he uses the mainloop and this overcomes the bug of not quitting the process as described above, but still can lead to unintended output, depending on what you expect:
import tkinter as tk
def tksleep(self, time:float) -> None:
"""
Emulating `time.sleep(seconds)`
Created by TheLizzard, inspired by Thingamabobs
"""
self.after(int(time*1000), self.quit)
self.mainloop()
tk.Misc.tksleep = tksleep
# Example
root = tk.Tk()
root.tksleep(2)
I am trying to delete text inside a text box after waiting 5 seconds, but instead the program wont run and does sleep over everything else. Also is there a way for me to just make my textbox sleep so i can run other code while the text is frozen?
from time import time, sleep
from Tkinter import *
def empty_textbox():
textbox.insert(END, 'This is a test')
sleep(5)
textbox.delete("1.0", END)
root = Tk()
frame = Frame(root, width=300, height=100)
textbox = Text(frame)
frame.pack_propagate(0)
frame.pack()
textbox.pack()
empty_textbox()
root.mainloop()
You really should be using something like the Tkinter after method rather than time.sleep(...).
There's an example of using the after method at this other stackoverflow question.
Here's a modified version of your script that uses the after method:
from time import time, sleep
from Tkinter import *
def empty_textbox():
textbox.delete("1.0", END)
root = Tk()
frame = Frame(root, width=300, height=100)
textbox = Text(frame)
frame.pack_propagate(0)
frame.pack()
textbox.pack()
textbox.insert(END, 'This is a test')
textbox.after(5000, empty_textbox)
root.mainloop()
You can emulate time.sleep in tkinter. For this we still need to use the .after method to run our code alongside the mainloop, but we could add readability to our code with a sleep function. To add the desired behavior, tkinter provides another underestimated feature, wait_variable. wait_variable stops the codeblock till the variable is set and thus can be scheduled with after.
def tksleep(t):
'emulating time.sleep(seconds)'
ms = int(t*1000)
root = tk._get_default_root('sleep')
var = tk.IntVar(root)
root.after(ms, var.set, 1)
root.wait_variable(var)
Real world examples:
update a Label to display a clock while-loop
animated writing nested for-loops
Limitation:
tkinter does not quit while tksleep is used.
Make sure there is no pending tksleep by exiting the application.
Using tksleep casually can lead to unintended behavior
UPDATE
TheLizzard worked out something superior to the code above here. Instead of tkwait command he uses the mainloop and this overcomes the bug of not quitting the process as described above, but still can lead to unintended output, depending on what you expect:
import tkinter as tk
def tksleep(self, time:float) -> None:
"""
Emulating `time.sleep(seconds)`
Created by TheLizzard, inspired by Thingamabobs
"""
self.after(int(time*1000), self.quit)
self.mainloop()
tk.Misc.tksleep = tksleep
# Example
root = tk.Tk()
root.tksleep(2)