python 3.x - tkinter listbox insert error "invalid command name ".50054760.50055432" -
i have database of objects , can view items in database in listbox , there's button remove item , create item. creating item opens dialog window item class , item's data stored in database. have reproduced problem simple duplicate of set-up (see code below).
every time add new item, addition successful (it's there next time open database dialog), listbox doesn't insert item, , when close database dialog following error:
exception in tkinter callback traceback (most recent call last):
file "c:\python33\lib\tkinter__init__.py", line 1442, in call return self.func(*args) file "", line 21, in addrecord file "c:\python33\lib\tkinter__init__.py", line 2604, in insert self.tk.call((self._w, 'insert', index) + elements) _tkinter.tclerror: invalid command name ".50054760.50055432"
the same problem doesn't come if try create object , populate values without invoking inputs gui (which necessary process of inserting things database). i've seen similar error in thread (sorry, can't seem find again), problem multithreading. i'm not aware of threading i'm doing , don't want download yet package handle tkinter threading. ideas? workarounds? i'm using python v3.3 , 64-bit windows 7, if helps.
here's simplified database code:
import tkinter import traceback # test ========================================================================= class test: def __init__(self): """a database of objects' ids , values.""" self.data = {1: 'a', 2: 'b', 3: 'c'} #--------------------------------------------------------------------------- def addrecord(self): """opens new item editing , saves ability database.""" print('hi0') newitem = otherobject() newitem.create(self.root) print('hi1') self.data[newitem.id] = newitem.value print('hi2') self.listbox.insert(tkinter.end, self.formatitem(newitem.id)) print('hi3') #--------------------------------------------------------------------------- def delrecord(self): """removes selected item database.""" try: index = self.listbox.curselection()[0] selection = self.listbox.get(index) except: return id = int(selection.split(':')[0]) self.data.pop(id) self.listbox.delete(index) #--------------------------------------------------------------------------- def dataframe(self, master): """assembles tkinter frame scrollbar view database objects. (returns frame, scrollbar widget, listbox widget) master: (tk or toplevel) tkinter master widget.""" frame = tkinter.frame(master) # scrollbar scrollbar = tkinter.scrollbar(frame) scrollbar.pack(side=tkinter.left, fill=tkinter.y) # listbox listbox = tkinter.listbox(frame, yscrollcommand=scrollbar.set) listbox.pack(side=tkinter.left, fill=tkinter.both) # fill listbox id in self.data: listbox.insert(tkinter.end, self.formatitem(id)) return (frame, listbox, scrollbar) #--------------------------------------------------------------------------- def destroylb(self, e): line in traceback.format_stack(): print(line.strip()) #--------------------------------------------------------------------------- def formatitem(self, id): """creates nice string representation of item in database.""" return '{0}:{1}'.format(id, self.data[id]) #--------------------------------------------------------------------------- def listboxselect(self, e): """manages events when selection changes in database interface. e: (event) tkinter event.""" try: selection = self.listbox.get(self.listbox.curselection()[0]) except: return # set description label id = int(selection.split(':')[0]) self.lblstr.set(self.data[id]) #--------------------------------------------------------------------------- def view(self): """displays database interface.""" self.root = tkinter.tk() # listbox frame self.frame, self.listbox, self.scrollbar = self.dataframe(self.root) self.frame.grid(column=0, row=0) self.listbox.bind('<<listboxselect>>', self.listboxselect) self.listbox.bind('<destroy>', self.destroylb) # record display frame self.lblstr = tkinter.stringvar() self.lbl = tkinter.label(self.root, textvariable=self.lblstr) self.lbl.grid(column=1, row=0, sticky=tkinter.n) # buttons frame self.frame_btn = tkinter.frame(self.root) self.frame_btn.grid(row=1, columnspan=2, sticky=tkinter.e+tkinter.w) # 'create new' button self.btn_new = tkinter.button( self.frame_btn, text='+', command=self.addrecord) self.btn_new.grid(row=0, column=0) # 'delete record' button self.btn_del = tkinter.button( self.frame_btn, text='-', command=self.delrecord) self.btn_del.grid(row=0, column=1) # display self.root.mainloop() # test ========================================================================= # otherobject ================================================================== class otherobject: """an object id , value.""" def __init__ (self): self.id = 0 self.value = '' #--------------------------------------------------------------------------- def create(self, master=none): """open dialog user entry new object id , value. master: (tk or toplevel) tkinter master widget.""" self.stuff = tkinter.toplevel(master) # id tkinter.label(self.stuff, text='id: ').grid(row=0, column=0) self.idvar = tkinter.stringvar(self.stuff) self.idvar.set(self.id) idwidget = tkinter.entry(self.stuff, textvariable=self.idvar) idwidget.grid(row=0, column=1) # value tkinter.label(self.stuff, text='value: ').grid(row=1, column=0) self.valuevar = tkinter.stringvar(self.stuff) self.valuevar.set(self.value) valuewidget = tkinter.entry(self.stuff, textvariable=self.valuevar) valuewidget.grid(row=1, column=1) # ok button tkinter.button(self.stuff, text='ok', command=self.ok).grid(row=2) self.stuff.mainloop() #--------------------------------------------------------------------------- def ok(self): try: self.id = int(self.idvar.get()) except: self.id = 0 self.value = self.valuevar.get() self.stuff.destroy() # otherobject ==================================================================
thanks in advance
you creating more 1 instance of tk
. tkinter not designed work , unexpected behavior. need refactor code create instance of tk
once. if need multiple windows, create instances of toplevel
.
... time passes ... code in question gets updated ...
in updated version of question creating 1 instance of tk
, , instances of toplevel
. good. however, calling mainloop
more once problem. worse, you're redefining self.root
no doubt part of problem. must call mainloop
once on entirety of program.
Comments
Post a Comment