Tkinter入门
前页 | Chapter 31. The Listbox Widget | 后页

# Patterns

When you first create the listbox, it is empty. The first thing to do is usually to insert one or more lines of text. The `insert` method takes an index and a string to insert. The index is usually an item number (0 for the first item in the list), but you can also use some special indexes, including `ACTIVE`, which refers to the "active" item (set when you click on an item, or by the arrow keys), and `END`, which is used to append items to the list.

        listbox = Listbox(master)

        listbox.insert(END, "a list entry")

        for item in ["one", "two", "three", "four"]:
            listbox.insert(END, item)

To remove items from the list, use the `delete` method. The most common operation is to delete all items in the list (something you often need to do when updating the list).

        listbox.delete(0, END)
        listbox.insert(END, newitem)

You can also delete individual items. In the following example, a separate button is used to delete the `ACTIVE` item from a list.

        lb = Listbox(master)
        b = Button(master, text="Delete",
                   command=lambda lb=lb: lb.delete(ANCHOR))

The listbox offers four different selection modes through the `selectmode` option. These are `SINGLE` (just a single choice), `BROWSE` (same, but the selection can be moved using the mouse), `MULTIPLE` (multiple item can be choosen, by clicking at them one at a time), or `EXTENDED` (multiple ranges of items can be chosen, using the Shift and Control keyboard modifiers). The default is `BROWSE`. Use `MULTIPLE` to get "checklist" behavior, and `EXTENDED` when the user would usually pick only one item, but sometimes would like to select one or more ranges of items.

        lb = Listbox(selectmode=EXTENDED)

To query the selection, use `curselection` method. It returns a list of item indexes, but a bug in Tkinter 1.101 (Python 1.5.1) and earlier versions causes this list to be returned as a list of strings, instead of integers. This will most likely be fixed in later versions of Tkinter, so you should make sure that your code is written to handle either case. Here's one way to do that:

        items = list.curselection()
        try:
            items = map(int, items)
        except ValueError: pass

In versions before Python 1.5, use `string.atoi` of `int`.

Use the `get` method to get the list item corresponding to a given index.

You can also use a listbox to represent arbitrary Python objects. In the next example, we assume that the input data is represented as a list of tuples, where the first item in each tuple is the string to display in the list. For example, you could display a dictionary by using the `items` method to get such a list.

        self.lb.delete(0, END) # clear
        for key, value in data:
            self.lb.insert(END, key)
        self.data = data

When querying the list, simply fetch the items indexed by the selection list:

        items = self.lb.curselection()
        try:
            items = map(string.atoi, items)
        except ValueError: pass
        items = map(lambda i,d=self.data: d[i], items)

Unfortunately, the listbox doesn't provide a `command` option allowing you to track changes to the selection. The standard solution is to bind a double-click event to the same callback as the OK (or Select, or whatever) button. This allows the user to either select an alternative as usual, and click OK to carry out the operation, or to select and carry out the operation in one go by double-clicking on an alternative. This solution works best in `BROWSE` and `EXTENDED` modes.

        lb.bind("<Double-Button-1>", self.ok)

If you wish to track arbitrary changes to the selection, you can either rebind the whole bunch of selection related events (see the Tk manual pages for a complete list of Listbox event bindings), or, much easier, poll the list using a timer:

        def __init__(self, master):
            self.list = Listbox(selectmode=EXTENDED)
            self.list.pack()
            self.current = None
            self.poll() # start polling the list

        def poll(self):
            now = self.list.curselection()
            if now != self.current:
                self.list_has_changed(now)
                self.current = now
            self.after(250, self.poll)

By default, the selection is exported via the X selection mechanism (or the clipboard, on Windows). If you have more than one listbox on the screen, this really messes things up for the poor user. If she selects something in one listbox, and then selects something in another, the original selection disappears. It is usually a good idea to disable this mechanism in such cases. In the following example, three listboxes are used in the same dialog:

        b1 = Listbox(exportselection=0)
        for item in families:
            b1.insert(END, item)

        b2 = Listbox(exportselection=0)
        for item in fonts:
            b2.insert(END, item)

        b3 = Listbox(exportselection=0)
        for item in styles:
            b3.insert(END, item)

The listbox itself doesn't include a scrollbar. Attaching a scrollbar is pretty straightforward. Simply set the `xscrollcommand` and `yscrollcommand` options of the listbox to the `set` method of the corresponding scrollbar, and the `command` options of the scrollbars to the corresponding `xview` and `yview` methods in the listbox. Also remember to pack the scrollbars before the listbox. In the following example, only a vertical scrollbar is used. For more examples, see pattern section in the `Scrollbar` description.

        frame = Frame(master)
        scrollbar = Scrollbar(frame, orient=VERTICAL)
        listbox = Listbox(frame, yscrollcommand=scrollbar.set)
        scrollbar.config(command=listbox.yview)
        scrollbar.pack(side=RIGHT, fill=Y)
        listbox.pack(side=LEFT, fill=BOTH, expand=1)

With some more trickery, you can use a single vertical scrollbar to scroll several lists in parallel. This assumes that all lists have the same number of items. Also note how the widgets are packed in the following example.

        def __init__(self, master):
            scrollbar = Scrollbar(master, orient=VERTICAL)
            self.b1 = Listbox(master, yscrollcommand=scrollbar.set)
            self.b2 = Listbox(master, yscrollcommand=scrollbar.set)
            scrollbar.config(command=self.yview)
            scrollbar.pack(side=RIGHT, fill=Y)
            self.b1.pack(side=LEFT, fill=BOTH, expand=1)
            self.b2.pack(side=LEFT, fill=BOTH, expand=1)

        def yview(self, *args):
            apply(self.b1.yview, args)
            apply(self.b2.yview, args)

前页 | Home | 后页
The Listbox Widget | Up | Methods