1

I want to make a GUI command line using the Text widget. For debugging purposes, I am trying to print whatever the user types into the separate GUI window to the system terminal. I know that it is frowned upon to mix GUI and Text Based commands into the same script, but I am just debugging, so forgive me Here is my code:

from Tkinter import *

main = Tk()
console = Text(main)
console.pack()


main.mainloop()

while True:
    text = console.get("1.0", "end-1c")

    print(text)

My current issue is that when the mainloop starts, (of course) the while loop doesn't. If I were to move the while loop in front of the mainloop call, it would never call mainloop. I really want it to continuously check for new text.

Is there a way to like "pause" the mainloop, or just carry out the command, maybe on a new thread or something?

I want to avoid using main.after(), but if that is the only way, then so be it. ¯\(°_o)/¯

General Nuisance
  • 211
  • 3
  • 16
  • Possible solution may be a duplicate of this: http://stackoverflow.com/questions/3567238/threaded-tkinter-script-crashes-when-creating-the-second-toplevel-widget – metatoaster Aug 04 '15 at 23:50
  • The answer to your title is "you don't, until the application is destroyed." My question to your statement of "I want to avoid using `main.after()`" is "why?" Because that's the exactly right way to do it. – TigerhawkT3 Aug 04 '15 at 23:50
  • @TigerhawkT3 Oh, fine. I see your point. main.after() it is! By the way, can you give me a reason that it's the "canonical" way to do things? You know, for future reference. – General Nuisance Aug 05 '15 at 00:54
  • Tkinter is an event-driven graphical interface, which means that it likes to use its own timing and hooks to get things done. The way most people discover this is by trying to implement delays with `time.sleep()` (spoiler: it doesn't work). `after()` is the designed, intended way to time events within a Tkinter GUI - it works, and works well. – TigerhawkT3 Aug 05 '15 at 00:58
  • @TigerhawkT3 Oh so true! Thank you for your timely response! – General Nuisance Aug 05 '15 at 16:24

2 Answers2

2

I recommend using main.after(), as it's the canonical way to do things like this in Tkinter. The following will also ensure that it only tries to print every second, instead of as fast as the console can handle it (as the while loop in your code would do if it worked).

def print_console():
    print(console.get("1.0", "end-1c"))
    main.after(1000, print_console)

print_console()

main.mainloop()
TigerhawkT3
  • 48,464
  • 6
  • 60
  • 97
1

You can also bind widgets to "Modified"

from Tkinter import *

class TextModified():
    def __init__(self):
        root = Tk()
        self.txt = Text(root)
        self.txt.pack()
        self.txt.focus_set()
        self.txt.bind('<<Modified>>', self.changed)
        Button(text='Exit', command=root.quit).pack()
        root.mainloop()

    def changed(self, value=None):
        flag = self.txt.edit_modified()
        if flag:     # prevent from getting called twice
            print "changed called", self.txt.get("1.0", "end-1c")
        ## reset so this will be called on the next change
        self.txt.edit_modified(False) 

TM=TextModified()