2

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()
Kevin Nisbet
  • 179
  • 1
  • 3
  • 14

1 Answers1

0

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

Nj Nafir
  • 570
  • 3
  • 13
  • Thanks alot, very helpful! Yeah after a while I thought it would be best if I used classes from the start but now there is so much to change :P Also to add to the window I would just have `globals()['user_message_entry'].grid(row=0, column=0)` , is this correct? – Kevin Nisbet May 07 '20 at 07:37
  • You can use, if it can fulfill your requirement. Happy codding! – Nj Nafir May 07 '20 at 07:48
  • So is there any way we can shorten globals()['user_message_entry'] ... when we use it elsewhere, for example a scroll bar? – Kevin Nisbet May 07 '20 at 07:51
  • There is no way but you have posibility in class via object oriented maner. like self.e1 = ..., and you can use self.e1 thousand of time mean infinity time – Nj Nafir May 07 '20 at 07:56