0

I'm writing a small program in python that consists of a backend that processes some data, and a frontend using tkinter. To process the data, the backend may sometimes need userinput. My idea was to call the backend data processing function from the frontend, giving it as input a function from the frontend that opens a pop-up window asking for input and returns it once the user clicks a "Submit" button. However, I'm having trouble returning only once the button is clicked. The following is a dummy example of what I've tried.

import tkinter as tk

def backend_function(func):
    #some data processing function
    user_input = func()
    print(user_input)
    
def pop_up(master):
    #opens pop-up window asking for inout and return the input once "submit" is clicked
    top = tk.Toplevel(master=master)
    entry = tk.Entry(top)
    entry.pack()
    
    submit = tk.Button(top, text='Submit', command = None)
    submit.pack()
    
    return entry.get() #should return only on click...
    

root = tk.Tk()

#start data processing from interface
call_backend = tk.Button(root, text = 'Backend',
                         command = lambda: backend_function(lambda: pop_up(master=root)))
call_backend.pack()

root.mainloop()

The problem is, that I'd like to have the return statement of pop_up as a command of the button, which is not possible. I thought about setting a nested function as command of the button, but then again, the nested function can't give a return value of the original function either.

Is it even possible to solve the problem this way, or would I have to delve deeper into tkinter defining some new Toplevel class or what not? Still fairly new to tkinter. Thanks!

  • I think you should use a OOP aproach to tkinter. Take a look at [this](https://stackoverflow.com/questions/17466561/best-way-to-structure-a-tkinter-application) for starting – DonPre Dec 05 '22 at 12:28
  • Thanks, indeed I have structured the rest of the interface in a similar way. However, I could not think of a way a new class for the pop-up would help me return the desired value to the backend. – green_bird Dec 05 '22 at 13:05
  • If you just want a dialog for asking something, try using [`simpledialog.askstring()`](https://docs.python.org/3/library/dialog.html#tkinter.simpledialog.askstring). – acw1668 Dec 05 '22 at 15:42

3 Answers3

0

You should create a new function for this and assign it to the "Submit" button and make the entry.get() value a variable.

Like this:

def backend_function(func):
    global user_input
    user_input = func() 
    print(user_input)

def return_text():
    global user_input
    return user_input


def pop_up(master):
    global user_input

    top = tk.Toplevel(master=master)
    entry = tk.Entry(top)
    entry.pack()
    
    user_input = entry.get()

    submit = tk.Button(top, text='Submit', command = return_text)
    submit.pack()
  • Thanks, however the pop_up function still has no return statment in itself, so when I would use user_input = func() in the backend with func given as the pop_up function, it's still None instead of the entry text. – green_bird Dec 05 '22 at 13:08
  • Here. This should also add `user_input` to `backend_function`. –  Dec 05 '22 at 13:34
  • Had the same idea, just that execution of `func` is still missing in your `backend_function`. The Problem is, this just prints an empty string, because the `backend_function` doesn't wait until the button is clicked to continue. – green_bird Dec 05 '22 at 14:59
  • Now backend function calls the desired function and user_input gets a value in the called function –  Dec 05 '22 at 15:50
  • That's just what I meant. Now `backend_function` will print an empty string because it does not wait for `func()` to finish. – green_bird Dec 05 '22 at 21:45
  • Now it should save the returned value in the variable. If you wish to remove any return statements, go ahead –  Dec 06 '22 at 06:24
0
import tkinter as tk

def backend_function(func):
    #some data processing function
    user_input = func
    print(user_input)


def get_value():
    backend_function(entry.get())

def pop_up(master):
    global entry
    #opens pop-up window asking for inout and return the input once "submit" is clicked
    top = tk.Toplevel(master=master)
    entry = tk.Entry(top)
    entry.pack()
    submit = tk.Button(top, text='Submit', command = get_value)
    submit.pack()
    

root = tk.Tk()

#start data processing from interface
call_backend = tk.Button(root, text = 'Backend',
                         command = lambda master_=root :pop_up(master=master_))
call_backend.pack()

root.mainloop()
Thisal
  • 64
  • 4
  • Unfortunately, what your code is doing is the wrong way around. You go from frontend, to pop-up, to backend with one specific user input. What I need is to call backend and then process various data sets and for various I may need user input for the backend function before it continues with the next data set. I guess this "waiting for input" is kindof what is causing problems. – green_bird Dec 05 '22 at 21:43
0

You can use top.wait_window() to wait for the closing of the toplevel window and then get the input value via a StringVar associated with entry:

def pop_up(master):
    #opens pop-up window asking for inout and return the input once "submit" is clicked
    top = tk.Toplevel(master=master)

    my_var = tk.StringVar() # used to return the input value
    entry = tk.Entry(top, textvariable=my_var)
    entry.pack()

    submit = tk.Button(top, text='Submit', command=top.destroy) # close top when clicked
    submit.pack()

    top.grab_set() # grab the input focus
    top.wait_window() # wait for the window close

    # use my_var.get() instead of entry.get() because entry is destroyed
    return my_var.get() #should return only on click...

If you just want to open a dialog to input something, simply use simpledialog.askstring():

...
from tkinter.simpledialog import askstring
...
def pop_up(master):
    return askstring(title="Input", prompt="Enter something", parent=master)
acw1668
  • 40,144
  • 5
  • 22
  • 34
  • Thanks a ton! With `top.wait_window()` it works perfectly! Now the `backend_function` indeed waits for the pop-up to close and assigns the input in the backend correctly. Also thanks for the tip about `simpledialog`, I'll keep it in mind. In this case, in the actual program I need input from a drop-down menu and an entry, so the top window will be easier than modifying `simpledialog`. – green_bird Dec 06 '22 at 08:15