Search code examples
pythonpython-3.xtkinterglobal-variablestkinter-text

how to get input from a tkinter text widget when its inside a function


relatively new to coding and currently I am playing with tkinter in python, I am using a text widget within a function and want to send the input from the text box to another function. My global variable says undefined at module level, so How could I make it defined at a module level if its within a function?

When I press the send email button I get this error message "NameError: name 'user_message_entry' is not defined"

Any suggestions? Many thanks!

minimum reproduction:

import tkinter as tk

root = tk.Tk()
root.geometry("500x500")


def send_email():
    global user_message_entry
    subject = ":)"
    body = user_message_entry.get("1.0", "end")
    message = f"subject: {subject}\n\n {body}"
    print(message)


def feedback():
    feedback_window = tk.Toplevel()
    feedback_window.geometry("690x650")

    message_frame = tk.Frame(feedback_window)
    message_frame.grid(row=0, column=0, columnspan=3)
    user_message_entry = tk.Text(message_frame, height=10, width=60)
    user_message_entry.grid(row=0, column=0)

    send_email_button = tk.Button(feedback_window, command=send_email,
                                  height=20, width=20, bg="yellow", text="send email")
    send_email_button.grid(row=1, column=0)


open_feedback_button = tk.Button(root, command=feedback, height=20, width=20, bg="yellow", text="open feedback window")
open_feedback_button.grid(row=1, column=0)

root.mainloop()

Solution

  • You can use Object orient methodology to make access sympler, another option also you can use globals() to make variable global

    One way

    globals()['user_message_entry'] = tk.Text(message_frame, height=10, width=60)
    
    .... 
    

    and from another function you can call

    body = globals()['user_message_entry'].get("1.0", "end")
    

    Second way

    Object oriented programming is good for every type of problem solving, so you can use class as well

    import tkinter as tk
    
    class CBased:
        def __init__(self, master, *args, **kwargs):
            super(CBased, self).__init__(*args, *kwargs)
            self.master = master
            master.geometry("500x500")
    
            self.open_feedback_button = tk.Button(master, command=self.feedback, height=20, width=20, bg="yellow", text="open feedback window")
            self.open_feedback_button.grid(row=1, column=0)
    
        def send_email(self):
            subject = ":)"
            body = self.user_message_entry.get("1.0", "end")
            message = f"subject: {subject}\n\n {body}"
            print(message)
    
    
        def feedback(self):
            self.feedback_window = tk.Toplevel()
            self.feedback_window.geometry("690x650")
    
            self.message_frame = tk.Frame(self.feedback_window)
            self.message_frame.grid(row=0, column=0, columnspan=3)
            self.user_message_entry = tk.Text(self.message_frame, height=10, width=60)
            self.user_message_entry.grid(row=0, column=0)
    
            self.send_email_button = tk.Button(self.feedback_window, command=send_email,
                                      height=20, width=20, bg="yellow", text="send email")
            self.send_email_button.grid(row=1, column=0)
    
    def main():
        root        = Tk()
        myobj       = CBased(root)
        root.mainloop()
    
    if __name__ == "__main__":main()
    

    In this way you can call every single item by self.xyz