I have a Tkinter GUI that is composed of two widgets, the first is a widget class with an entry field and a button and the second is a scrollable text widget class. I have combined these two widget classes to make a single GUI. Each of these widget classes works correctly as individuals.

The text field of the GUI is being used to display the contents of a specific index of a list.I want to be able to enter an index number in the entry field and upon pressing the button the text in the text field is re-configured to show the contents of the list for the specified index. The indivdual widgets communicate properly with one another, by which I mean the value of the index entered into the entry field is properly recognized by the update_text method. However when I press the button I get the following error message:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1470, in __call__
    return self.func(*args)
  File "/Users/BioASys/BioasysDB/simpletestgui.py", line 56, in fetch_update_text
    self.parent.update_text(article_index)
  File "/Users/BioASys/BioasysDB/simpletestgui.py", line 112, in update_text
    self.top_right.configure(text=text_list[index])
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1262, in configure
    return self._configure('configure', cnf, kw)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1253, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
TclError: unknown option "-text"

When I initialize (mainloop) the GUI I have the text widget set to display the 0 index of the list.

I have written simplified code that exhibits my problem. My original code is too complex to sensibly
post here. Because of the layout of all the individual widgets in my original code it was necessary
to combine multiple widget classes to achieve my desired widget layout.

The problem I am experiencing is caused by the code which rewrites the text within the existing top_right text widget.
This code is: "self.top_right.configure(text=text_list[index])"
which is contained in the update_text method of the article_review_widget_assembled class.

I thought that performing a text.configure for the text in the text field would perform the desired text rewrite and
if that didn't work then I could use text.delete and text.insert methods to delete all the text and then insert the desired text,
allowing me to successfully rewrite the text. Unfortunately neither of these methods works.

If anybody knows how to change the text within the existing top_right text widget I would appreciate the assistance.

Here is my complete code:

# This list contains the sample text that is to be placed in the individual text widgets, referenced by index
text_list = [['text0AAAAAAA'], ['text1AAAAAAA'], ['text2AAAAAAA']]

# This class creates the widget that will be designated top_left in the article_review_widget_assembled widget
class article_review_entry_button_widget(Frame):
    def __init__(self, parent=None):
        self.parent = parent
        Frame.__init__(self, parent)
        self.pack(expand=YES, fill=BOTH)                # make me expandable
        self.index = 2
        self.makeWidgets()
    def handleList(self, event):
        index = self.listbox.curselection()
        label = self.listbox.get(index)
        self.runCommand(label)
    def fetch(self):                                    # This def gets the value placed in the entry field
        print 'Input => "%s"' % self.ent.get()
        article_index = self.ent.get()
        ###### 
    def fetch_update_text(self):                        #  This def gets the value placed in the entry field and also accesses the update_text def to update the text in the  top_right widget
        print 'Input => "%s"' % self.ent.get()
        article_index = int(self.ent.get())
        self.parent.update_text(article_index)




    def makeWidgets(self):
        self.ent = Entry(self)
        btn = Button(self, text='Next Article', command=self.fetch_update_text)
        self.ent.insert(0, 0)
        self.ent.pack(side=TOP, fill=BOTH)
        self.ent.focus()
        self.ent.bind('<Return>', (lambda event: self.fetch()))
        value = self.ent.get()
        btn.pack(side=TOP)



class ScrolledText(Frame):                      # This class creates a text widget that can be scrolled, I use this as the basis for the other text widgets in this GUI
    def __init__(self, parent=None, text='', file=None, width='', height=''):
        Frame.__init__(self, parent)
        self.pack(expand=YES, fill=BOTH)                # make me expandable
        self.width = width
        self.height = height
        self.makewidgets()
        self.settext(text, file)
    def makewidgets(self):
        sbar = Scrollbar(self)
        text = Text(self, relief=SUNKEN, width=self.width, height=self.height)
        sbar.config(command=text.yview)                  # xlink sbar and text
        text.config(yscrollcommand=sbar.set)             # move one moves other
        sbar.pack(side=RIGHT, fill=Y)                    # pack first=clip last
        text.pack(side=LEFT, expand=YES, fill=BOTH)      # text clipped first
        self.text = text
    def settext(self, text='', file=None):
        self.text.delete('1.0', END)                     # delete current text
        self.text.insert('1.0', text)                    # add at line 1, col 0
        self.text.mark_set(INSERT, '1.0')                # set insert cursor
        self.text.focus()                                # save user a click
    def gettext(self):                                   # returns a string
        return self.text.get('1.0', END+'-1c')           # first through last





class article_review_widget_assembled(Frame):        # This class uses the previous classes to create the final assemnbeld GUI widget
    def __init__(self, parent=None):
        Frame.__init__(self, parent)
        self.pack(expand=YES, fill=BOTH)                # make me expandable
        self.text = text_list[0]
        self.makeWidgets()

    ###### This is the def that is called by the fetch_update_text def in the article_review_entry_button_widget class
        # and contains the line that is causing the error
    def update_text(self,index):
        print "The index is:", index
        self.top_right.configure(text=text_list[index])   # configure text but causes error
        #self.top_right.text.delete('1.0',END)          # delete current text   but causes error
        #self.top_right.insert('1.0',text_list[index])  # add at line 1, col 0   but causes error
        #self.top_right = ScrolledText(self, text= text_list[index], width=50, height=15).pack(side=LEFT)  # re packs the top_right widget





    def makeWidgets(self):
        self.top_left = article_review_entry_button_widget(self).pack(side=LEFT)
        #self.top_right = ScrolledText(self, text= self.text, width=50, height=15).pack(side=LEFT)
        self.top_right = ScrolledText(self, text= self.text, width=50, height=15)
        self.top_right.pack(side=LEFT)






if __name__ == '__main__':
    #article_review_entry_button_widget().mainloop()
    #ScrolledTextComposite().mainloop()
    article_review_widget_assembled().mainloop()

self.top_right = ScrolledText(self, text=self.text, width=50, height=15)
the instance you get refers to the Frame object and that does not have a 'text' argument.

The line
Frame.__init__(self, parent)
in class ScrolledText makes that the instance self

You can test it with
print(self.top_right.config()['class'])

Edited 1 Year Ago by vegaseat

OK, I'm not sure what to do with this. Since my Frame object does not have a 'text' argument, does that mean I have to somehow provide it with a 'text' argument. Thank you for your comment but I really have no idea what to do from here.

Your class is written "incorrectly", creating two instances via __init__() in the same class. Only the last instance (self) created is used.

Note:
Sorry, the class is written quite well. On closer inspection it has a method settext() to change the text in the Text() widget. Also Text() does not behave the way you thought (like a Label()).

Edited 1 Year Ago by vegaseat

Hello, Thank you for your response. Which class is written incorrectly, ScrolledText? ScrolledText seems to work correctly as it creates a scrolled text widget that works correctly as a stand alone widget. If my class is written incorrectly how do I correct it? Thanks again, George

Well, your class is okay, but the way it is written you can access the Text widget inside the class this way

self.top_right = ScrolledText(self, text=self.text, width=50, height=15)
text_widget = self.top_right.text

since you assigned text = Text() to self.text

The Text widget does not have an argument called 'text', to insert text you have to use insert() and you have already made a method called
settext(self, text='', file=None) in class ScrolledText, so use it.

self.top_right.settext('any string you want')

or in your case ...

        self.top_right.settext(text_list[index])
        # instead of self.top_right.config(text=text_list[index])

Edited 1 Year Ago by vegaseat

In hindsight, using class is excellent in this case, but you need to study up on the the class object and the meaning of instance 'self'.

Edited 1 Year Ago by vegaseat

Hello, Thank you very much for your response. You nailed it with the change to using the settext method. Thank you very much.

It took a little detective work, I saw the line
text = Text(self, relief=SUNKEN, width=self.width, height=self.height)
but the line
self.text = text
where you make text part of the instance came a few lines later.

Glad to have helped you.

This question has already been answered. Start a new discussion instead.