X-Mann
X-Mann

Reputation: 327

Python Tkinter: how to get text from ScrolledText widget on <Destroy> event callback?

I understand ScrolledText is constructed as a Text object (but has a scrollbar attached together in a frame). But the following code throws an error when the window is closed and the printText() method is called:

import Tkinter as tk
import ttk
import ScrolledText as st
class tkGui(object):
    def printText(self, event):
        print "It works!"
        self.mText.get("1.0", 'end-1c')

    def __init__(self, window):
        # create widgets
        self.frame=tk.Frame(window)
        self.mText = st.ScrolledText(self.frame)
        self.mText.bind('<Destroy>',self.printText)
        # place widgets
        self.frame.pack()
        self.mText.pack()

window = tk.Tk()
app = tkGui(window)
window.mainloop()

The error:

[...]
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 3077, in get
  return self.tk.call(self._w, 'get', index1, index2)
TclError: invalid command name ".140506094171344.140506094172280.140506094172496"

What am I doing wrong?

Upvotes: 0

Views: 2783

Answers (2)

saulspatz
saulspatz

Reputation: 5261

Once you destroy the main window, all its sub-widgets are destroyed, and you can't access them. (This is not technically correct, as Bryan Oakley's answer points out, but it's how I think about it. Trying to work with the widgets after destruction is problematical, at best.)

You need to use wm_protocol

http://nullege.com/codes/search/Tkinter.Tk.wm_protocol

import Tkinter as tk
import ttk
import ScrolledText as st
class tkGui(object):
    def printText(self):
        print "It works!"
        self.mText.get("1.0", 'end-1c')
        self.window.destroy()

    def __init__(self, window):
        # create widgets
        self.window = window
        self.frame=tk.Frame(window)
        self.mText = st.ScrolledText(self.frame)
        #self.mText.bind('<Destroy>',self.printText)
        window.wm_protocol("WM_DELETE_WINDOW", self.printText)
        # place widgets
        self.frame.pack()
        self.mText.pack()

window = tk.Tk()
app = tkGui(window)
window.mainloop()

There are a couple of changes here. I removed the event parameter from printText and added a call to self.window.destroy. Note that I had to add the self.window attribute to make this call. The basic change is using wm_protocol instead of binding to the event; the others are necessary consequences.

Upvotes: 2

Bryan Oakley
Bryan Oakley

Reputation: 385950

You should not assume you can get data out of a widget when handling the <Destroy> event for that widget.

From the official documentation:

When the Destroy event is delivered to a widget, it is in a “half-dead” state: the widget still exists, but most operations on it will fail.

Upvotes: 2

Related Questions