0

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?

  • Yes, there is. But it would be _much_ better to modify "test.py" so that it can be imported into your Tkinter script rather than running it with `os.system`. – PM 2Ring Mar 13 '17 at 13:33
  • But to answer your question, see http://stackoverflow.com/questions/18517084/how-to-redirect-stdout-to-a-tkinter-text-widget and http://stackoverflow.com/questions/36604900/redirect-stdout-to-tkinter-text-widget – PM 2Ring Mar 13 '17 at 13:35
  • how difficult is it to modify? I'm not good with tkinter and this was a quick way to have a 'go' button to run my script which is set up forever. – uniqueusername42o Mar 13 '17 at 13:46
  • If test.py just has one `print` call then it's easy: instead of calling `print` you call a function that updates the text of your Tkinter widget (via its `.config` method). You can probably use a Label widget for that. – PM 2Ring Mar 13 '17 at 13:53
  • nope, i have several prints. 'files currently transferring', 'currently merging all pdfs', 'pdfs have been merged'.do you think it's easier to just leave it in the command line? – uniqueusername42o Mar 13 '17 at 14:06
  • You could easily put those messages into a single label. – PM 2Ring Mar 13 '17 at 14:11
  • Is your "test.py" written as a module? IOW, does it have its code in functions, with a `main()` function that runs the other stuff? – PM 2Ring Mar 13 '17 at 14:18
  • yes, i have one function which merges the files and another function which adds a watermark. – uniqueusername42o Mar 13 '17 at 15:23

1 Answers1

0

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()
Community
  • 1
  • 1
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
  • see, what i don't understand is how i print out my print statements when a function has actually completed. Adding in print_to_label('Currently merging all pdfs') isn't any help because I have no idea when that process is actually complete. – uniqueusername42o Mar 14 '17 at 09:12
  • @uniqueusername42o Sorry. I just noticed some of the information in my answer was a little misleading, so I've removed it. My `print_to_label` function isn't a perfect replacement for the `print` function because it only accepts a single string argument. But if your `print` calls in "test.py" just print a single string then you can replace them with calls to `print_to_label`. Earlier I said that you could import "test.py" into the Tkinter script, but on reflection, it's probably simpler to just create a new version of "test.py" that also includes my GUI code. – PM 2Ring Mar 14 '17 at 09:44
  • @uniqueusername42o If you're still not sure what to do please modify your question so it includes a dummy version of "test.py" and I'll show you how to add the GUI stuff to it. We don't need to see your complete "test.py", with all the PDF stuff, just a minimal version so you can see how to tie it together with the GUI code. – PM 2Ring Mar 14 '17 at 09:46