Chapter 30. The Listbox Widget

Table of Contents
When to use the Listbox Widget(リストボックス・ウィジットを使う場面)
Patterns(パターン)
Methods(メソッド)
Options(オプション)
The Listbox widget is a standard Tkinter widget used to display a list of alternatives. The listbox can only contain text items, and all items must have the same font and color. Depending on the widget configuration, the user can choose one or more alternatives from the list.
標準的なTkinterのウィジットである、リストボックス・ウィジットは選択可能なリストを表示するために利用される。リストボックスにはテキストで書かれた項目のみを含めることが出来き、全ての項目には同じ色とフォントしか使うことはできない。ウィジットの設定によって、ユーザーは1つかあるいは複数の項目の選択を行うことが出来る。

When to use the Listbox Widget
リストボックス・ウィジットを使う場面

Listboxes are used to select from a group of textual items. Depending on how the listbox is configured, the user can select one or many items from that list.
リストボックスはテキストで書かれた項目のグループから選択する時に使われる。 リストボックスの設定によって、ユーザーが項目リストから同時に1つか複数の項目を選択することが出来る。
-------------------------------------------------------------------------------------- 

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.
最初にリストボックスを生成した時点ではリストボックスは空の状態になっている。 そのため、通常は最初に最低でも一行、あるいは数行のテキストを挿入しなければならない。insertメソッドはインデックスと、挿入する文字列を引き受ける。通常なら、インデックスは項目番号となるが(そのリストの最初の項目が0になる)それだけでなく、アクティブ状態(矢印キーやマウスクリックで選択された状態のこと)になっている項目を表す"ACTIVE"やリストに追記されていく"END"を含んだいくつかのスペシャル・インデックスを使うことも出来る。
    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).
リストから項目を削除するにはdeleteメソッドを使用します。 そのもっともありふれた使い方はリストから全ての項目を削除することだろう。 (リストを更新するときにも必要になるはずだ)
    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.
リストボックスはslectmodeオプションによって4つの異なる選択モードを提供する。 "SINGLE"(項目を1つだけ選択)
"BROWSE"(SINGLEと同じだが、選択個所を動かすことができる)
"MULTIPLE"(選びたい項目をクリックすることで、複数の項目を選択できる。)
"EXTENDED" (複数の項目の範囲を「SHIFTキー」や「Ctrlキー」を使って選択することが出来る。)
デフォルトの選択モードは"BROWSE"である。 チェックリストのような動作をさせるには、"MULTIPLE"を使い、ユーザーが通常ならたった1つの項目を選び、たまに1つないしそれ以上の項目の範囲を選びたいような時には”EXTENDED"を使う。

*訳者注:原文を訳す限りこの辺の説明はうまくないかもしれない。以下のような説明のほうがすっきりするはず。

"SINGLE” 常に1つの項目だけマウスの左ボタンで選択できる。
"BROWSE" 常に1つの項目だけマウスの左ボタンで選択できる。ただし、マウスの左ボタンを押しながら選択個所を移動できる。
"MULTIPLE" 複数の項目をマウスの左ボタンで選択できる。
"EXTENDED" 複数の項目をマウスの左ボタンで選択できる。項目を選択した後、「SHIFTキー」+マウスの左ボタンで他の項目を選択すると、最初に選択した項目との間を全て選択状態に出来る。「Ctrlキー」+マウスの左ボタンでMULTIPLEと同じように選択できる。

    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:
選択内容の問い合わせ(クエリ)をするにはcurselectionメソッドを使う。 このメソッドは項目番号のリストを返すが、Tkinter1.101(Python 1.5.1)以前のバージョンにはバグがあり、このリストが整数型ではなく、文字列のリストとして返されます。 これはTkinterの最新のバージョンではほとんどが適切に改善されているが,どちらの場合にも対応するような安全なコードを書くように設計するべきだろう。これはその一例である。
    items = list.curselection()
    try:
        items = map(int, items)
    except ValueError: pass
In versions before Python 1.5, use string.atoi of int.
python 1.5以前のバージョンではstring.atoi関数を使って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.
取得した項目番号に対応する項目のリストを得るにはgetメソッドを使います。 バラバラに配置されたパイソンオブジェクトを表現するためにリストボックスを使うこともできる。次の例では、タプルのリストとして表現されたデータを入力するものと考えて、リストの中のタプルの最初の項目に位置する文字列がどこかを表示します。 この例では,そのようなリストを得るためにitemメソッドを使い、ディクショナリを表示可能にした。

    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.
不幸なことに、リストボックスには選択に応じて任意に対応を変更するようなcommandオプションが用意されていない。その一般的な解決法はOKボタンと同じようにdoulbe-clickイベントを応答にバインドすることだ。 この方法は、OKをクリックした時に実行される操作や、選択肢をダブルクリックすることで実行される操作といった選択肢をユーザーに提供する。 この解決法はBROWSEモードとEXTENDEDモードの中で使うのが最適である。
    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:
もし、選択に応じて任意に対応を変更させたいなら、一つずつイベントに関連付けた選択の分岐をバインドしなおすか、より簡単なタイマーを利用したリストの登録をすればよい(リストボックスの完全なバインディングのリストについてはTkのマニュアル・ページを参照せよ)
    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:
デフォルトでは、この選択はXセレクションメカニズム(あるいは、ウィンドゥズではクリップボード)を経由して出力されます。もし、スクリーンに一つ以上のリストボックスを作っ場合、これは実にごく少数のユーザーでも混乱してしまう。 一つのリストボックスの中で何かを選択したら、その後、他のリストボックスの中にある何かが選択されてしまい、オリジナルの選択は破棄されます。 このようなケースではこのメカニズムを無効化しておくことは通常は良いアイディアです。次の例の中では、同じダイアログの中で3つのリストボックスを使割れています。
    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.
リストボックスそのものはスロールバーを含みません。スクロールバーをアタッチするのは非常に簡単です。単純に、リストボックスのオプションであるxscrollcommandオプションとyscrollcommandオプションにスクロールバーのsetメソッドの指定し、スクロールバーのcommandオプションにリストボックスのxviewメソッドとyviewメソッドを指定するだけですが、リストボックスよりも前にスクロールバーをpackすることもわすれないように。次の例のでは垂直のスクロールバーを使っています。さらに多くの例が欲しい場合はスクロールバーのパターンセクションを参照すること。
    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.
いくつかのさらにトリッキーな方法を使うことで、並列的に数個のリストをスクロールするために同一のスクロールバーを使うことも出来ます。これは全てのリストの項目数が同じだと仮定しています。 次の例の中でどんあウィジットがpackされているかにも注意してみてください。
    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)
.......... -------------------------------------------------------------------------------