2

I am trying to use a tkinter Toplevel window with a Text box to post to a Text box in the main window, but I keep getting the following error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\someone\ouch\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "<ipython-input-14-df46ff30dac4>", line 21, in GetFromDIALOG
    X = littletext.get("1.0","end")
NameError: name 'littletext' is not defined

In my script below, I call the Text widget in the Toplevel "littletext" and the Text widget in the main window "BIGTEXT". I also tried setting the Text boxes as StringVars, as most tutorials and scripts seem to suggest is right, but StringVars seem to work more on Entry (not Text) boxes.

I am wondering if I should use a custom class instead of a Toplevel, although I am not sure how I would handle that would work either.

My code is below.

import tkinter as tk

def openDIALOG(window):

    DIALOG = tk.Toplevel(window)
    DIALOG.title("DIALOG")
    DIALOG.geometry("400x300+100+100")

    littletext = tk.Text(DIALOG, height=15)
    littletext.pack()

    btn1 = tk.Button(DIALOG, text ="POST TO MAIN WINDOW", command=GetFromDIALOG)
    btn1.pack(side="left")

    btn2 = tk.Button(DIALOG, text ="EXIT", command = DIALOG.destroy)
    btn2.pack(side="left")


def GetFromDIALOG ():

    X = littletext.get("1.0","end")
    print(X)


window = tk.Tk()
window.title("main")

menubar = tk.Menu(window)
filemenu = tk.Menu(menubar, tearoff=0)
filemenu.add_command(label="RUN A DIALOG", command=lambda:openDIALOG(window))
filemenu.add_command(label="Exit", command=window.destroy)
menubar.add_cascade(label="FILE", menu=filemenu)
window.config(menu=menubar)

BIGTEXT = tk.Text(window)
BIGTEXT.pack()

BUTTON = tk.Button(window, text="Post", command=openDIALOG)
BUTTON.pack()

window.mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301
egghead jr
  • 91
  • 10
  • The problem is `littletext` is a local variable defined in the `openDIALOG()` function, so doesn't exist in the `GetFromDIALOG()` function. You need to either make it a `global` variable so both function can access it, or better yet, create a `class` to encapsulate it. – martineau Sep 05 '21 at 00:22
  • Thank you both (martineau and Derek). I was a bit worried about using a Global, but at least it works now. I am not sure of how to implement it as a class yet, as I am not good at OOP, but I am always willing to learn if someone wants to explain it! :) Thank you again! – egghead jr Sep 05 '21 at 00:50

2 Answers2

0

One way to fix the NameError, which is due it it being a local variable in the openDIALOG() function in your code, is to make it an attribute of instances of the class. This is better than using a global variable, which is another option, but global variables are bad.

Stackoverflow is not intended to replace existing tutorials or documentation, so I'll describe only very briefly what the demo code below it doing. This topic would be covered much more thoroughly in most of the Python tutorials that are available online, if you took time to for them.

So, here's how that might be done based on the code in your question. Notice how littletext is now self.littletext. This is because it has been turned into a class attribute of the class MY_DIALOG that's been defined, so it can be access through the self argument which will automatically be passed as the first argument of all the class' functions (which are know as class "methods").

import tkinter as tk
from tkinter.constants import *


class MyDialog:
    def __init__(self, window):
        DIALOG = tk.Toplevel(window)
        DIALOG.title("DIALOG")
        DIALOG.geometry("400x300+100+100")

        self.littletext = tk.Text(DIALOG, height=15)
        self.littletext.pack()

        btn1 = tk.Button(DIALOG, text="POST TO MAIN WINDOW", command=self.GetFromDIALOG)
        btn1.pack(side="left")

        btn2 = tk.Button(DIALOG, text="EXIT", command=DIALOG.destroy)
        btn2.pack(side="left")

    def GetFromDIALOG(self):
        X = self.littletext.get("1.0", END)
        print(X)


if __name__ == '__main__':
    window = tk.Tk()
    window.title("main")

    menubar = tk.Menu(window)
    filemenu = tk.Menu(menubar, tearoff=0)
    filemenu.add_command(label="RUN A DIALOG", command=lambda: MyDialog(window))
    filemenu.add_command(label="Exit", command=window.destroy)
    menubar.add_cascade(label="FILE", menu=filemenu)
    window.config(menu=menubar)

    BIGTEXT = tk.Text(window)
    BIGTEXT.pack()

    BUTTON = tk.Button(window, text="Post", command=lambda: MyDialog(window))
    BUTTON.pack()

    window.mainloop()

martineau
  • 119,623
  • 25
  • 170
  • 301
0

Thanks martineau! :)

There was a few small problems I cleaned up.

The dialog you coded didnt post back to BIGTEXT in the main window, so I completed the callback aspect of it.

The BUTTON in the footer of the main window was actually a mistake on my part. I accidentally forgot to delete it in the original post, so I deleted it here and let the menu work the call.

Final code is below.

import tkinter as tk
from tkinter.constants import *


class MY_DIALOG:
    
    def __init__(self, window):
        DIALOG = tk.Toplevel(window)
        DIALOG.title("DIALOG")
        DIALOG.geometry("400x300+100+100")

        self.littletext = tk.Text(DIALOG, height=15)
        self.littletext.pack()

        btn1 = tk.Button(DIALOG, text="POST TO MAIN WINDOW", command=self.GetFromDIALOG)
        btn1.pack(side="left")

        btn2 = tk.Button(DIALOG, text="EXIT", command=DIALOG.destroy)
        btn2.pack(side="left")

    def GetFromDIALOG(self):

        X = self.littletext.get("1.0","end")
        BIGTEXT.insert("end", X)
        self.littletext.delete("1.0","end")


if __name__ == '__main__':
    window = tk.Tk()
    window.title("main")

    menubar = tk.Menu(window)
    filemenu = tk.Menu(menubar, tearoff=0)
    filemenu.add_command(label="RUN A DIALOG", command=lambda: MY_DIALOG(window))
    filemenu.add_command(label="Exit", command=window.destroy)
    menubar.add_cascade(label="FILE", menu=filemenu)
    window.config(menu=menubar)

    BIGTEXT = tk.Text(window)
    BIGTEXT.pack()

    window.mainloop()
egghead jr
  • 91
  • 10
  • It looks to me like you're using my answer with some fixes/clean-up partially due to stuff left out of your question — so I think you should change the accepted answer of your question to mine. – martineau Sep 05 '21 at 18:04
  • I just sat down to start programming today, and have a few things to do, but I will review what you suggested (and - given your level of experience - probably make the changes sure enough). One sidebar question worth noting is, I dont know how to "officiate" the changes per stackoverflow's requirements. Is there a forum for how a human can get along with stackoverflow? I dont know where to post my social concerns? – egghead jr Sep 05 '21 at 18:18