Reputation: 13
I am pretty new to python and have been working with a program that was originally meant for the command line. As such, it uses the input() function quite a bit, especially in the middle of loops. Mostly, the original code would do something like this:
for item in list:
# some logic here
user_input - input("prompt")
# uses user_input
I've decided I want to make a GUI for it, but I also want to make it optional. I have a class called Viewer that decorates the original program, and I am struggling to figure out how to best to handle the calls to input().
My first thought was just to inject a new input function altogether so that way it looks for input in my GUI text box instead the sys.stdout. I found many Stack Overflow answers on how to print sys.stdout to a GUI element (like this), but not how to take input from one. All of my attempts either ended in freezing the GUI by creating a loop, or the program not pausing for input and simply grabbing what was in the box when the prompt was put forward.
Secondly, I tried to break apart my functions to better match the code examples for buttons. So, button 1 would trigger a function_part_1, which would go until it required an input. If the GUI flag was turned off, it would automatically go to an input function, otherwise it would return and a button press would trigger function_part_2:
def function_part_1(list):
item = list[0]
# do some logic on item 1
if GUI:
print("prompt")
return
# After this, the GUI waits for a button press, and then calls function_part_2
else:
function_input(list)
def function_input(list):
user_input = input("prompt")
function_part_2(user_input, list)
def function_part_2(user_input, list):
# uses user_input on item
list.remove(list[0])
if list:
function_part_1(list)
else:
return
However, this turned ugly really quickly. First, it broke apart many loops which would require a lot of refactoring to keep the logic in tact (Especially for the nested loops). It also requires that I pass all my local variables from function-part to function-part, which exploded the function headers. In order to have only a single input box for the user, the GUI has to have logic to know which function is executing and what function-part comes next. It made my functions harder to follow and hurt readability.
Is there a nicer way to do this?
I am using appJar for the GUI, which is based around Tkinter. I am willing to switch to pure Tkinter if that would make things easier.
Upvotes: 0
Views: 1288
Reputation: 43146
The easiest way is to overwrite the input
function. Here's a working example using tkinter:
import tkinter as tk
def input(prompt=''):
win= tk.Tk()
label= tk.Label(win, text=prompt)
label.pack()
userinput= tk.StringVar(win)
entry= tk.Entry(win, textvariable=userinput)
entry.pack()
# pressing the button should stop the mainloop
button= tk.Button(win, text="ok", command=win.quit)
button.pack()
# block execution until the user presses the OK button
win.mainloop()
# mainloop has ended. Read the value of the Entry, then destroy the GUI.
userinput= userinput.get()
win.destroy()
return userinput
print(input('foobar'))
Upvotes: 1