0

I have written some code primarily to be used with the console, but was asked to create a simple GUI for it for ease of use. In it, I am setting up the main frame with widgets, and using the widget command to call upon the function that I import. However, the imported functions and modules all write to the output console. Is there a means of returning the output string/console output to be updated in the GUI as the subprocess runs?

Example script:

import Tkinter as *
import myModule1

class MyGUI(Frame):
    def __init__(self):
    # Initialization stuff.
        self.initGUI()

    def initGUI(self):
        self.downloadButton = Button(text="Download data.")
        self.downloadButton["command"] = myModule1.function
        # This function from myModule1 will constantly print to the console as the process is performed - is there any way to have this displayed in the GUI as a ScrollBar? 

    .....

Alternatively, is there a way to make a dialog window show up while the process is running? I ask because I have embedded a lot of print statements in the myModule1 and its submodules that return what is going on to the console. It would be nice to display those for the users one the GUI is working and I convert it to a .exe for ease of use of those who will be using it.

Thank you.

EDIT: An example of what myModule1.function can look like:

import otherModule

def function1():

    log = otherModule.function2():
    if log == True:
        print "Function 2 worked."
    elif log == False:
        print "Function 2 did not work."

However, function2 in otherModule prints to console as it performs its calculations. That is not explicitly shown here, but the console output would essentially be a series of calculations followed by the example if/elif clause shown above.

kalle
  • 425
  • 1
  • 6
  • 17
  • 1
    I see you're still using Python 2. Does `myModule1` use `print` _statements_ or is it using `print` _function_ calls, which can be enabled in Python 2.6+ ? But anyway, you can probably do something by capturing `sys.stdout` and redirecting it to your GUI. – PM 2Ring May 27 '18 at 19:29
  • There are several existing questions on this topic that should assist you. Eg, https://stackoverflow.com/questions/36604900/redirect-stdout-to-tkinter-text-widget – PM 2Ring May 27 '18 at 19:39
  • I'm using print statements, not function calls. I will look at the link you have provided, thank you! – kalle May 27 '18 at 19:41
  • 1
    Bear in mind that there's more to this task than merely redirecting stdout to your GUI. You may need to use threading so that you can run functions in your commandline module without the GUI freezing up while the function is running. – PM 2Ring May 27 '18 at 20:00
  • It seems that threading will be necessary, as the command that the GUI button performs takes a bit of processing time (~20 minutes). Do you know any good resources on using threading with Tkinter? – kalle May 27 '18 at 20:30
  • Funny you should ask. ;) Here's an example I wrote a little while ago: https://stackoverflow.com/a/50542563/4014959 but there are lots of others you can find by do a Google search. – PM 2Ring May 27 '18 at 20:43

1 Answers1

0

It won't be extremely simple, but one way to do this is create a method or function in your GUI that writes to a text widget or some other widget whose content can be updated easily. I'll call it outputMethod. Then, pass this function or method to myModule1.function(outputMethod). Within the module1.function, replace print statements with the outputMethod call, providing the appropriate parameters to it. Without seeing module1.function, it's difficult to provide a complete example that would work. Added the following example once the OP posted myModule1 sample code.

from Tkinter import *
import myModule1

class MyGUI(Frame):

    def __init__(self, parent):
    # Initialization stuff.
        self.initGUI(parent)

    def initGUI(self, parent):
        Frame.__init__(self, parent)
        self.grid_rowconfigure(1, weight=1)
        self.grid_columnconfigure(1, weight=1)
        self.pack(expand='yes', fill='both')
        self.downloadButton = Button(self, text="Download data.")
        self.downloadButton["command"] = lambda m=self.outputMethod: myModule1.function(m)
        self.text = Text(self)
        self.downloadButton.grid(row=0, column=0)
    self.text.grid(row=1, column=0, sticky='news')
        self.sy = Scrollbar(self, command=self.text.yview)
        self.text['yscrollcommand'] = self.sy.set
        self.sy.grid(row=1, column=1, sticky='nsw')


    def outputMethod(self, the_output):
        self.text.insert('end', the_output + '\n')
        # Scroll to the last line in the text widget.
        self.text.see('end')

if __name__ == '__main__':
    # Makes the module runable from the command line.
    # At the command prompt type python gui_module_name.py
    root = Tk()
    app = MyGUI(root)
    # Cause the GUI to display and enter event loop
    root.mainloop()

Now for module1...

def function(log):
# Note that log is merely a pointer to 'outputMethod' in the GUI module.

log("Here is a string you should see in the GUI")
log("And this should appear after it.")
# Now demonstrate the autoscrolling set up in outputMethod...
for i in range(50):
    log("Inserted another row at line" + str(i + 2))
Ron Norris
  • 2,642
  • 1
  • 9
  • 13
  • That's alongside what I have been trying to attempt, but I am running into problems passing what you call `outputMethod` to `myModule1.function`. I will edit in a simple example of what `function1` can look like. – kalle May 27 '18 at 19:26