2015-06-22 5 views
1

У меня возникла проблема с модификацией существующей версии MultiListBox, чтобы я мог выбрать несколько элементов, используя ключ shift. Конструктор класса:Tkinter: выберите несколько элементов в MultiListBox

class MultiListbox(Frame): 
    def __init__(self, master, lists): 
     Frame.__init__(self, master) 
     self.lists=[] 
     for l,w in lists: 
      frame = Frame(self); frame.pack(side=LEFT, expand=YES, fill=BOTH) 
      Label(frame, text=l, borderwidth=1, relief=RAISED).pack(fill=X) 
      lb = Listbox(frame, width=w, borderwidth=0, selectborderwidth=0, 
       relief=FLAT, exportselection=FALSE, selectmode=EXTENDED) 
      lb.pack(expand=YES, fill=BOTH) 
      self.lists.append(lb) 
      lb.bind('<B1-Motion>', lambda e, s=self: s._select(e.y)) 
      lb.bind('<Button-1>', lambda e, s=self: s._select(e.y)) 
      lb.bind('<Leave>', lambda e: 'break') 
      lb.bind('<B2-Motion>', lambda e, s=self: s._b2motion(e.x, e.y)) 
      lb.bind('<Button-2>', lambda e, s=self: s._button2(e.x, e.y)) 
     frame = Frame(self); frame.pack(side=LEFT, fill=Y) 
     Label(frame, borderwidth=1, relief=RAISED).pack(fill=X) 
     sb = Scrollbar(frame, orient=VERTICAL, command=self._scroll) 
     sb.pack(expand=YES, fill=Y) 

     self.lists[0]['yscrollcommand']=sb.set 

Даже если я установил selectmode=EXTENDED, нет расширенного выбора.

Какую функцию мне нужно реализовать для многолистников, чтобы поддерживать расширенный выбор?

Вы можете увидеть всю реализацию multilistbox here.

ответ

1

Я предпочитаю метод vegaseat с использованием ttk.TreeView, потому что все столбцы связаны со строкой, что упрощает работу. Эта небольшая модификация его примера выводит идентификатор, когда выбран любой столбец в строке. Вы хотите проверить/распечатать идентификатор, так как вам придется преобразовать идентификатор в смещение номера строки/списка, т. Е. Захватить возврат из self.tree.insert. Сегодня вечером мы рассмотрим несколько вариантов выбора. И попробуйте использовать клавиши вместо кнопки.

import sys 
if sys.version_info[0] < 3: 
    import Tkinter as tk ## Python 2.x 
    import tkFont 
    import ttk 
else: 
    import tkinter as tk ## Python 3.x 
    import tkinter.font as tkFont 
    import tkinter.ttk as ttk 

''' 

ttk_multicolumn_listbox2.py 

Python31 includes the Tkinter Tile extension ttk. 

Ttk comes with 17 widgets, 11 of which already exist in Tkinter: 
Button, Checkbutton, Entry, Frame, Label, LabelFrame, Menubutton, 
PanedWindow, Radiobutton, Scale and Scrollbar 

he 6 new widget classes are: 
Combobox, Notebook, Progressbar, Separator, Sizegrip and Treeview 

Here the TreeView widget is configured as a multi-column listbox 
with adjustable column width and column-header-click sorting. 

Tested with Python 3.1.1 and Tkinter 8.5 
''' 

class McListBox(object): 
    """use a ttk.TreeView as a multicolumn ListBox""" 
    def __init__(self, root): 
     self.root=root 
     self.tree = None 
     self._setup_widgets() 
     self._build_tree() 
     ttk.Button(self.root, text='Exit', 
        command=self.root.quit).grid(row=20) 

    def _setup_widgets(self): 
     # create a treeview with dual scrollbars 
     container = ttk.Frame(self.root) 
     container.grid(sticky="nsew") 

     self.tree = ttk.Treeview(columns=car_header, show="headings") 
     vsb = ttk.Scrollbar(orient="vertical", 
      command=self.tree.yview) 
     hsb = ttk.Scrollbar(orient="horizontal", 
      command=self.tree.xview) 
     self.tree.configure(yscrollcommand=vsb.set, 
      xscrollcommand=hsb.set) 
     self.tree.grid(column=0, row=0, sticky='nsew', in_=container) 
     vsb.grid(column=1, row=0, sticky='ns', in_=container) 
     hsb.grid(column=0, row=1, sticky='ew', in_=container) 

     container.grid_columnconfigure(0, weight=1) 
     container.grid_rowconfigure(0, weight=1) 
     self.tree.bind("<Button1-Motion>", self.selection) 

    def _build_tree(self): 
     for col in car_header: 
      self.tree.heading(col, text=col.title()) 
      # adjust the column's width to the header string 
      self.tree.column(col, 
       width=tkFont.Font().measure(col.title())) 

     for item in car_list: 
      print self.tree.insert('', 'end', values=item) 
      # adjust column's width if necessary to fit each value 
      for ix, val in enumerate(item): 
       col_w = tkFont.Font().measure(val) 
       if self.tree.column(car_header[ix],width=None)<col_w: 
        self.tree.column(car_header[ix], width=col_w) 


    def selection(self, event): 
     """ gets selected item id and prints them 
     """ 
     id = self.tree.identify_row(event.y) 
     print "selection", id 


# the test data ... 
car_header = ['car', 'repair'] 
car_list = [ 
('Hyundai', 'brakes') , 
('Honda', 'light') , 
('Lexus', 'battery') , 
('Benz', 'wiper') , 
('Ford', 'tire') , 
('Chevy', 'air') , 
('Chrysler', 'piston') , 
('Toyota', 'brake pedal') , 
('BMW', 'seat'), 
('Audi', 'starter'), 
('Fiat', 'shocks'), 
('Porsche', 'fuel pump') 
] 

root = tk.Tk() 
root.wm_title("multicolumn ListBox") 
mc_listbox = McListBox(root) 
root.mainloop() 
+0

Вы упоминаете «vegaseat» - кто или что это? –

+0

Отвечая на ваш почти 3-летний вопрос, Vegaseat является пользователем [DaniWeb] (http://www.daniweb.com), который дает много хороших ответов на вопросы Python и Tkinter. – Todd

1

К сожалению, похоже, что вам нужно катиться самостоятельно, по крайней мере, насколько я могу судить. Код ниже не является полным, так как он будет делать то же самое, что принимать один и тот же выбор дважды, но это все, на что у меня есть время. Нет кода со стрелкой вниз, но он по существу совпадает с кодом со стрелкой вверх. Я предполагаю, что вы хотите, чтобы кнопка нажала для отображения или использования выбранных элементов. Ниже они просто печатаются после закрытия Tkinter.

import sys 
if sys.version_info[0] < 3: 
    import Tkinter as tk ## Python 2.x 
    import tkFont 
    import ttk 
else: 
    import tkinter as tk ## Python 3.x 
    import tkinter.font as tkFont 
    import tkinter.ttk as ttk 

''' 

ttk_multicolumn_listbox2.py 

Python31 includes the Tkinter Tile extension ttk. 

Ttk comes with 17 widgets, 11 of which already exist in Tkinter: 
Button, Checkbutton, Entry, Frame, Label, LabelFrame, Menubutton, 
PanedWindow, Radiobutton, Scale and Scrollbar 

he 6 new widget classes are: 
Combobox, Notebook, Progressbar, Separator, Sizegrip and Treeview 

For additional info see the Python31 manual: 
http://gpolo.ath.cx:81/pydoc/library/ttk.html 

Here the TreeView widget is configured as a multi-column listbox 
with adjustable column width and column-header-click sorting. 

Tested with Python 3.1.1 and Tkinter 8.5 
''' 

class McListBox(object): 
    """use a ttk.TreeView as a multicolumn ListBox""" 
    def __init__(self, root): 
     self.root=root 
     self.tree = None 
     self._setup_widgets() 
     self._build_tree() 
     ttk.Button(self.root, text='Exit', 
        command=self.root.quit).grid(row=20) 
     self.selected_offsets=[] 

    def _setup_widgets(self): 
     container = ttk.Frame(self.root) 
     container.grid(sticky="nsew") 

     # create a treeview with dual scrollbars 
     self.tree = ttk.Treeview(columns=car_header, show="headings", 
           selectmode="extended") 
     vsb = ttk.Scrollbar(orient="vertical", 
      command=self.tree.yview) 
     hsb = ttk.Scrollbar(orient="horizontal", 
      command=self.tree.xview) 
     self.tree.configure(yscrollcommand=vsb.set, 
      xscrollcommand=hsb.set) 
     self.tree.grid(column=0, row=0, sticky='nsew', in_=container) 
     vsb.grid(column=1, row=0, sticky='ns', in_=container) 
     hsb.grid(column=0, row=1, sticky='ew', in_=container) 

     container.grid_columnconfigure(0, weight=1) 
     container.grid_rowconfigure(0, weight=1) 
     self.tree.bind("<Shift-Up>", self.shift_up_arrow) 
     self.tree.bind("<Up>", self.up_arrow) 

    def _build_tree(self): 
     for col in car_header: 
      self.tree.heading(col, text=col.title()) 
      # adjust the column's width to the header string 
      self.tree.column(col, 
       width=tkFont.Font().measure(col.title())) 

     self.item_id=[] 
     for item in car_list: 
      self.item_id.append(self.tree.insert('', 'end', values=item)) ## store tkinter id 
      # adjust column's width if necessary to fit each value 
      for ix, val in enumerate(item): 
       col_w = tkFont.Font().measure(val) 
       if self.tree.column(car_header[ix],width=None)<col_w: 
        self.tree.column(car_header[ix], width=col_w) 

     ## set the focus in the middle for testing 
     new_id=self.item_id[5] 
     self.tree.focus_set()  ## sets focus to the treeview 
     self.tree.selection_set((new_id, new_id)) ## updates background 
     self.tree.focus(new_id)  ## sets new id as focus 

    def shift_up_arrow(self, event): 
     """ gets selected item(s) and stores them in a list 
     """ 
     id_selected=self.tree.focus() 
     for offset, id in enumerate(self.item_id): 
##   print offset, id 
      if id==id_selected: 
       self.selected_offsets.append(offset)## save selection 
       print offset, car_list[offset] 

       ## change background color 
       ## you could also give each row a unique tag and 
       ## tag_configure the selected row's tag 
       self.tree.delete(id_selected) 
       self.tree.insert('', offset, id_selected, 
           values=car_list[offset], tags=("ABC",)) 
       self.tree.tag_configure("ABC", background='yellow') 

       new_id=self.item_id[0] 
       if offset > 0: 
        new_id=self.item_id[offset] 
       self.tree.focus_set()  ## sets focus to the treeview 
       self.tree.selection_set((new_id, new_id)) ## updates background 
       self.tree.focus(new_id)  ## sets new id as focus 
       return 

    def up_arrow(self, event): 
     id_selected=self.tree.focus() 
     for offset, id in enumerate(self.item_id): 
      if id==id_selected and offset > 0: 
       new_id=self.item_id[offset] 
       self.tree.focus_set()  ## sets focus to the treeview 
       self.tree.selection_set((new_id, new_id)) ## updates background 
       self.tree.focus(new_id)  ## sets new id as focus 

# the test data ... 
car_header = ['car', 'repair'] 
car_list = [ 
('Hyundai', 'brakes') , 
('Honda', 'light') , 
('Lexus', 'battery') , 
('Benz', 'wiper') , 
('Ford', 'tire') , 
('Chevy', 'air') , 
('Chrysler', 'piston') , 
('Toyota', 'brake pedal') , 
('BMW', 'seat'), 
('Audi', 'starter'), 
('Fiat', 'shocks'), 
('Porsche', 'fuel pump') 
] 

root = tk.Tk() 
root.wm_title("multicolumn ListBox") 
mc_listbox = McListBox(root) 
root.mainloop() 
## 
## print selected items 
print "Selections %s" % ("-"*50) 
for offset in mc_listbox.selected_offsets: 
    print offset, car_list[offset] 
Смежные вопросы