Skip to main content
 首页 » 编程设计

Python/Tkinter 列表框问题

2025年05月04日10lexus

我发布了一个问题 here我被建议重组代码。现在已经足够不同了,我觉得有理由提出一个新问题。

无论如何,我正在尝试向列表框添加拖放功能,但我认为第一步是让事件绑定(bind)正常工作。目前,当我单击列表时,单击列表框会出现以下错误。出现列表框窗口,但是当我单击它时出现错误。

 "AttributeError: make_list instance has no attribute 'nearest'. 

此外,当我在 build_listbox 方法中打印列表框时,会打印以下小数点 .40720520L。这不应该打印列表框中的值吗?毕竟,它是用同样的方法。列表框是否未正确创建?

from Tkinter import * 
import Tkinter 
 
class make_list: 
 
    def move_mouse(self, event): 
        self.curIndex = event.nearest(event.y) 
        print self.curIndex 
 
    def click_button(self, event): 
        w= event.widget 
        self.curIndex = int(w.curselection()[0]) 
        #print self.curIndex 
        value = w.get(self.curIndex) 
        print value 
 
    def build_main_window(self): 
        self.build_listbox() 
 
    def build_listbox(self): 
        listbox = Listbox() 
        listbox.bind('<<ListboxSelect>>', self.click_button) 
        listbox.bind('<B1-Motion>', self.move_mouse) 
        for item in ["one", "two", "three", "four"]: 
            listbox.insert(END, item)     
        listbox.insert(END, "a list entry") 
        listbox.pack() 
        print listbox 
        return 
 
if __name__ == '__main__': 
    start = make_list() 
    start.build_main_window() 
    mainloop() 

请您参考如下方法:

在 Tkinter 小部件上执行 print 时获得的值在很大程度上与用户无关,它只是为创建的 Tcl 变量的名称你。

现在,由于显然您的代码正在运行(通过快速浏览问题中的注释),我建议以不同的方式执行拖放功能。例如,如果我们有一个与 Listbox 中的值相关联的值列表,那么如果我们可以更新此列表然后它会反射(reflect)在Listbox 显示,对吗?可惜我们在 Python 中没有这样的东西,但现在考虑以下代码:

import Tkinter 
 
def list_click(event): 
    w = event.widget 
    index = w.nearest(event.y) 
    w._selection = index 
 
def list_motion(event): 
    w = event.widget 
    if w._selection is None: 
        return 
    index = w.curselection()[0] 
    w._var.swap(index, w._selection) 
    w._selection = index 
 
def list_clear(event): 
    event.widget._selection = None 
 
root = Tkinter.Tk() 
 
v = ListVar(values=('one', 'two', 'three', 'four')) 
v.append('a list entry') 
 
listbox = Tkinter.Listbox(listvar=v) 
listbox.pack() 
 
listbox._selection = None 
listbox._var = v 
listbox.bind('<1>', list_click) 
listbox.bind('<B1-Motion>', list_motion) 
listbox.bind('<ButtonRelease-1>', list_clear) 
 
root.mainloop() 

此代码以下列方式工作:当在列表框中单击鼠标时,它会将最近的项目标记为“选中”,当您移动鼠标时,它会交换项目并更新选择,当您释放鼠标按钮时,它会清除选择。缺少的是这个 ListVar 东西。在这里:

class ListVar(Tkinter.Variable): 
    def __init__(self, master=None, name=None, **kwargs): 
        Tkinter.Variable.__init__(self, master, kwargs.get('values'), name) 
 
    def set(self, values): 
        self._tk.call('set', self._name, values) 
 
    def set_index(self, index, value): 
        self._tk.call('lset', self._name, index, value) 
 
    def get_index(self, index): 
        return self._tk.eval('lindex $%s %d' % (self._name, index)) 
 
    def get(self, start=None, end=None): 
        if start is None and end is None: 
            res = self._tk.eval('lrange $%s 0 end' % self._name) 
        elif end is None: 
            res = self._tk.eval('lrange $%s %d end' % (self._name, start)) 
        else: 
            res = self._tk.eval('lrange $%s %d %d' % (self._name, start, end)) 
        return self._tk.splitlist(res) 
 
    def swap(self, a, b): 
        if a != b: 
            tmp = self.get_index(a) 
            self.set_index(a, self.get_index(b)) 
            self.set_index(b, tmp) 
 
    def append(self, value): 
        self._tk.eval('lappend %s {%s}' % (self._name, value)) 

它很粗糙,如果你传递一个像“hello{”之类的值会失败。这可以通过很多方式改进。