Tkinter对destroy()的奇怪行为

时间:2016-08-12 16:04:20

标签: python-2.7 tkinter

我正在开发一个关于Tkinter,Python 2.7的应用程序。 在我的一个进程中,我使用26个小部件构建了一部分窗口(根):     23个标签,2个按钮和1个入口。 在构建它们时,我不断将它们的名称添加到列表中以进一步销毁 当他们的使用完成。为此,我按下其中一个按钮(“完成”) 读取创建的列表并在“for”循环内destroy()它们。 小部件被不正常地销毁,而不是列表中的顺序。我需要 按几下按钮即可完成。 我发现,如果列表被反转(),我会发现沮丧,而不是洞察力 “for”循环在第一次尝试中都被“摧毁”。 这是预期的行为吗?非常令人费解! 我准备用奇怪的行为发布我的应用程序的部分 除非有人已经知道它的原因,否则我会删除不必要的代码。 我仍在用Python破坏我的排骨而不准备使用Classes ...... 谢谢!

我包括我的计划的相关部分。我编辑了原件以减小尺寸。测试了编辑后的版本,它具有相同的行为。我评论了一些代码,以显示纠正的位置。 奥克利先生对此感兴趣。我不确定是否在转录我的代码时,正确的缩进没有受到影响。

我的代码:

# testdestroy.py
from Tkinter import *
root = Tk()
root.title('Information container')
root.geometry('1160x900+650+50')

global todestroy, screen, font1, lbl1txt, lbl2txt
global col, row, colincr, rowincr, bxincr, entries

todestroy = []
screen = ''
col = 10
row = 10
font1 = 'verdana 12 bold '
colincr = 370
rowincr = 40
bxincr = 145

entries = {' Last updated: ' : '11/08/2016 at 11:55',
            ' Login id: ' : 'calfucura',
            ' Password: ': 'munafuca',
            'card number' : '1234567890',
            'check number': '445',
            'expiry' : '12/06/2018',
            'PIN' : '9890', 
            'Tel:' : '1-800-234-5678',
            'emergency' : 'entry nine',
            'use for' : 'gas, groceries'}

def position(col, row, what):       # returns the position for the place command
    colincr = 370
    rowincr = 40
    bxincr = 145
    if what == 'down':
        row += rowincr
        col -= colincr
    if what == 'side':
        col += colincr
    if what == 'button1':
        row += rowincr
        col += colincr - bxincr
    if what == 'button':
        col -= bxincr
    if what == 'reset':
        col = col
        row = row
    return col, row

def done(event):                        #  Button "Done"
    print 'Done pressed'
    for name in todestroy:     # DOES NOT WORK!!!!
                               # THIS WORKS in the previous line: 
                               # for name in reversed(todestroy):
        name.destroy()
        todestroy.remove(name)

def accept(event):                      # Button "Accept"
    print 'Name to show: ', entry1.get()
    scr2d1(entries)

def scr2d():                            # Name to show
    lbl1txt = 'Enter name to show: '
    screen = 'scr2d'
    scr2(lbl1txt)
#    scr2d1(entries)

def scr2(lbl1txt):
    global todestroy, col, row, entry1
    lbl1 = Label(root, text = lbl1txt, anchor = E, width = 25, font = font1)
    entry1 = Entry(root, width = 25, show = '*', font = font1)
    Accept = Button(root, text = 'Accept', font = font1, bg = 'green', width = 9)
    cmd = eval('Accept'.lower())
    Accept.bind('<ButtonRelease-1>', cmd)
    col, row = position(200, 200, 'reset')
    lbl1.place(x = col, y = row)
    col, row = position(col, row, 'side')
    entry1.place(x = col , y = row )
    col, row = position(col, row, 'button1')
    Accept.place(x = col, y = row)
    todestroy = []
    todestroy.extend([lbl1, entry1, Accept])

def scr2d1(entries):                # show entries
    global todestroy, col, row
    lblup = 1
    lbl = 'lbl' + str(lblup)
    lbl = Label(root, text = 'Entry', font = font1, width = 20 )
    row = rowincr * 7
    col = 600
    col, row = position(col, row, 'down')
    lbl.place(x = col, y = row)
    todestroy.append(lbl)
    lblup += 1
    lbl = 'lbl' + str(lblup)
    lbl = Label(root, text = 'Contents', font = font1, width = 20)
    col, row = position(col, row, 'side')
    lbl.place (x = col, y = row)
    todestroy.append(lbl)
    for name in sorted(entries):
        lblup += 1
        lbl = 'lbl' + str(lblup)
        lbl = Label(root, text = name, bg = 'yellow', font = font1, width = 25, anchor = E)
        col, row = position(col, row, 'down')
        lbl.place(x = col, y = row)
        todestroy.append(lbl)
        lblup += 1
        lbl = 'lbl' + str(lblup)
        lbl = Label(root, text = entries[name], bg = 'yellow', font = font1, width = 25, anchor = W)
        col, row = position(col, row, 'side')
        lbl.place(x = col , y = row)
        todestroy.append(lbl)
    cmd = eval('done')
    Done = Button(root, text = 'Done', font = font1, bg = 'green', width = 9)
    Done.bind('<ButtonRelease-1>', cmd)
    col, row = position(col, row, 'button1')
    Done.place(x = col, y = row)
    todestroy.append(Done)

scr2d()

root.mainloop()       

1 个答案:

答案 0 :(得分:1)

问题是你在迭代它时改变列表,这不是你应该做的事情。它与reversed一起使用的原因是因为您正在迭代原始列表的副本。如果使用for name in todestroy[:],则会得到相同的结果,def done(event): global todestroy for name in todestroy: name.destroy() todestroy = [] 也会迭代列表的副本。

最快的解决方案是不从列表中删除任何内容,只需在删除所有内容后重置列表:

Frame

更好的解决方案是将您计划销毁的所有小部件放入HRESULT GetString(BSTR* p_bstrResult, unsigned long* ulErrCode) { HRESULT hr = S_OK; try { System::String ^systemstring = gcnew System::String(""); DotNetObject::o = gcnew DotNetObject:: DotNetObjectComponent(); *ulErrCode = (unsigned long)o->GetString(systemstring); pin_ptr<const wchar_t> wch = PtrToStringChars(systemstring); _bstr_t bstrt(wch); *p_bstrResult = bstrt.GetBSTR(); // native client babysits delete systemstring; } catch(Exception ^ ex) { } return hr; } 。然后,您可以销毁该帧,它将销毁其所有子窗口小部件。