2013-04-20 76 views
-2

我有一個對象的數據庫,您可以在列表框中查看數據庫中的項目,並且有一個按鈕可以刪除項目並創建項目。打開項目類的對話窗口,然後將項目的數據存儲在數據庫中。我通過非常簡單的設置複製了該問題(請參閱下面的代碼)。tkinter listbox插入錯誤「無效的命令名」.50054760.50055432「

每當我添加一個新的項,添加成功(下次打開數據庫對話框),但列表框不插入項目,並且當我關閉數據庫對話框時,出現以下錯誤:

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"

如果我只是嘗試創建對象並填充其值而不調用其輸入GUI(這對於將事物插入到我的數據庫中是必需的),則不會出現同樣的問題。我在另一個線程中看到了類似的錯誤(對不起,但我似乎無法再找到它),問題出在多線程。我不知道我正在做什麼線程,不想下載另一個包來處理tkinter線程。有任何想法嗎?解決方法?如果有幫助,我正在使用Python v3.3和64位Windows 7。

這裏是我的簡單的數據庫代碼:

import tkinter 
import traceback 

# Test ========================================================================= 
class Test: 
    def __init__(self): 
     """A database of objects' IDs and values.""" 

     self.data = {1: 'a', 2: 'b', 3: 'c'} 

    #--------------------------------------------------------------------------- 
    def addRecord(self): 
     """Opens up a new item for editing and saves that ability to the 
     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 from the 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 a tkinter frame with a scrollbar to 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 
     for ID in self.data: 
      listbox.insert(tkinter.END, self.formatItem(ID)) 

     return (frame, listbox, scrollbar) 

    #--------------------------------------------------------------------------- 
    def destroyLB(self, e): 
     for line in traceback.format_stack(): 
      print(line.strip()) 

    #--------------------------------------------------------------------------- 
    def formatItem(self, ID): 
     """Creates a nice string representation of an item in the database.""" 

     return '{0}:{1}'.format(ID, self.data[ID]) 

    #--------------------------------------------------------------------------- 
    def listboxSelect(self, e): 
     """Manages events when the selection changes in the 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 with an ID and value.""" 

    def __init__ (self): 
     self.ID = 0 
     self.value = '' 

    #--------------------------------------------------------------------------- 
    def create(self, master=None): 
     """open a dialog for the user to entry a new object ID and 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 ================================================================== 

在此先感謝

回答

0

布賴恩·奧克利引導我,我是遇到了確切的問題:

(1)我創建了我的OtherObject類第二Tk的對象。

(2)我在我的OtherObject類中調用了mainloop。

只有一個Tk對象應該存在,並且主循環只應該被調用一次,無論要顯示多少個窗口。

0

您正在創建的Tk多個實例。 Tkinter的設計並非如此,你會得到意想不到的行爲。您需要重構代碼,以便只創建一個Tk的實例。如果您需要多個窗口,請創建Toplevel的實例。

...時間的流逝......在問題的代碼被更新...

在你的問題的更新版本,現在正在創建的Tk一個實例,然後實例Toplevel。這很好。但是,您也不止一次地致電mainloop,這是一個問題。更糟糕的是,你正在重新定義self.root,這無疑是問題的一部分。您必須在整個程序中撥打mainloop一次。

+0

我只是嘗試將OtherObject更改爲Toplevel(在這個笨拙的代碼和我的主代碼中),它顯示/像以前一樣工作,但我仍然有同樣的問題和錯誤。我也試圖讓測試中的一個(「主」窗口)也是一個Toplevel小部件,這給了我同樣的錯誤,但也打開了一個我在開始時並不需要的額外窗口。 – Breez 2013-04-20 16:59:52

+0

我只是再次嘗試,將我的主「根」小部件(使其成爲self.root)傳遞給OtherObject,並使OtherObject的Toplevel小部件使用Test的根作爲它的主。現在它在同一位置(列表框)給我一個錯誤,但是出現以下錯誤: _tkinter.TclError:invalid command name「.49660480。48661896「 – Breez 2013-04-20 18:01:54

+0

@Breez:在mainloop存在後的任何代碼都無法訪問任何與Tkinter(小部件,StringVars,IntVars等)有關的任何東西,因爲那時所有的Tkinter對象都將被銷燬。 – 2013-04-20 19:16:34