使用组合框过滤列表框

时间:2014-03-29 20:47:18

标签: python python-2.7 combobox listbox tkinter

我尝试过滤列表框中显示的内容,具体取决于当前所选的组合框项目。我不确定如何实现这一点,我甚至没有在网上找到一个简单明了的例子。有任何想法吗?我真的很感激一些帮助。

以下是代码摘录。

列表框:

class MyListBox(object):
    def __init__(self, frame, listbox_header, listbox_list):

    self.tree = ttk.Treeview(frame, columns=listbox_header, show='headings')
    yScroll = ttk.Scrollbar(frame,orient='vertical', command=self.tree.yview)
    yScroll.pack(side=RIGHT, fill=Y)
    self.tree.config(yscrollcommand=yScroll.set)
    self.tree.pack(side=LEFT, fill=Y, expand=TRUE)
    for col in listbox_header:
        self.tree.heading(col, text=col.title(),command=lambda c=col: sortby(self.tree, c, 0))
    self.update_rows(listbox_list)
    self.tree.bind('<Double-1>', self.OnDoubleClick)

def update_rows(self, listbox_list):
    items = self.tree.get_children()
    for item in items:
        self.tree.delete(item)
    for item in listbox_list:
        self.tree.insert('', 'end', values=item)

def OnDoubleClick(self, event):
    item = self.tree.selection()[0]
    self.Info(self.tree.item(item, 'values'))

#Single student information window. Display all courses in student listbox
def Info(self, selected):
    info = Toplevel()
    info.title('Student Information: %s - %s - %s' % (selected[0], selected[1], selected[2]))
    info.geometry('%dx%d+%d+%d' % (WIDTH, HEIGHT, 50, 50))

    student = session.query(Student).filter_by(id=selected[0]).first()

    #Single student header label info
    Label(info, text='Total All Attempts: %s' % student.gpa).pack()
    Label(info, text='Total Best Attempts: %s' % student.best_gpa).pack()
    Label(info, text='Spec GPAs: %s' % student.rules_gpas).pack()
    Label(info, text='Spec GPAs Needed: %s' % student.rules_gpas_needed).pack()

    #Single Student course info list
    Label(info, text='\nAll Courses:').pack()
    current = session.query(Course.sid, Course.term, Course.subject, Course.number,
                            Course.title, Course.grade, Course.grade_val, Course.hours).\
        order_by(Course.term.desc(), Course.subject, Course.number, Course.grade_val.desc()).filter_by(sid=selected[0])
    course_header = ['ID', 'term', 'subject', 'number', 'title', 'grade', 'grade_val', 'hours']

    #setup listbox and scroll bars
    tree = ttk.Treeview(info, columns=course_header, show='headings')
    yScroll = ttk.Scrollbar(info, orient='vertical', command=tree.yview)
    yScroll.pack(side=RIGHT, fill=Y)
    tree.config(yscrollcommand=yScroll.set)
    tree.pack(side=LEFT, fill=BOTH, expand=TRUE)

    for col in course_header:
        tree.heading(col, text=col.title(), command=lambda c=col: sortby(tree, c, 0))
        tree.column(col, width=50, anchor='center')
    tree.column('title', width=150, anchor='w')
    for item in current:
        tree.insert('', 'end', values=item)

这是组合框:

# This creates the drop menu (combobox)
Label(top, text='View Concentration:').pack(side=LEFT)
box_value = StringVar()
box = ttk.Combobox(top, textvariable=box_value, state='readonly')
titles = []
titles.append('All')
for rule in rules:
    titles.append((rule.title))
box['values'] = titles
box.current(0)
box.pack(side=LEFT)

1 个答案:

答案 0 :(得分:1)

根据我的理解,每次组合框更改时,您要做的是清除并重新填充列表框。令人惊讶的是,它并不太难。

这是我的示例应用。它利用root.after来递归检查组合框是否已更改。请注意,可能有一种方法可以将更新功能绑定到StringVar.set命令,我只是不知道它是什么。您也可以使用StringVar进行子类化,但无论如何:

# Import
import Tkinter
import ttk

# Class
class App:

    # Init
    def __init__(self):
        self.options = ["All", "Odd", "Even"] # Combobox elements
        self.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # Treeview elements

        self.last_filter_mode = "" # Combobox change detector

        self.create()

    # Build GUI
    def create(self):
        self.root = Tkinter.Tk() # Can be substituted for Toplevel
        self.root.title("Filtered Listbox")

        self.frame = Tkinter.Frame(self.root)
        # I like to use pack because I like the aesthetic feel
        # pady is 5 so that the widgets in the frame are spaced evenly
        self.frame.pack(fill="both", padx=10, pady=5) 

        self.filter_mode = Tkinter.StringVar(); # Combobox StringVar
        # Set it to the initial value of combobox
        # Also consider using self.options[0] for uniformity
        self.filter_mode.set("All") 

        self.combobox = ttk.Combobox(
            self.frame, textvariable=self.filter_mode, state="readonly",
            values=self.options)
        self.combobox.pack(fill="x", pady=5)

        # So that the scroll bar can be packed nicely
        self.treeview_frame = Tkinter.Frame(self.frame)
        self.treeview_frame.pack(fill="x", pady=5)

        column_headings = ["A", "B", "C"] # These are just examples 
        self.treeview = ttk.Treeview(
            self.treeview_frame, columns=column_headings, show="headings")
        self.treeview.pack(fill="y", side="left")

        self.treeview_scroll = ttk.Scrollbar(
            self.treeview_frame, orient="vertical", command=self.treeview.yview)
        self.treeview_scroll.pack(fill="y", side="right")
        self.treeview.config(yscrollcommand=self.treeview_scroll.set)

    # Recursize update function called with root.after
    def update(self):
        filter_mode = self.filter_mode.get()

        # Check for change in the filter_mode
        if filter_mode != self.last_filter_mode: 

            items = self.treeview.get_children()
            for item in items:
                self.treeview.delete(item) # Clear the treeview

            # Combobox options
            if filter_mode == "All": 
                for element in self.values:
                    self.treeview.insert("", "end", values=(element))

            if filter_mode == "Odd":
                for element in filter(
                    lambda x: True if x % 2 != 0 else False, self.values):
                    self.treeview.insert("", "end", values=(element))

            if filter_mode == "Even":
                for element in filter(
                lambda x: True if x % 2 == 0 else False, self.values):
                    self.treeview.insert("", "end", values=(element))

            self.last_filter_mode = filter_mode # Update current filter mode

        self.root.after(100, self.update) # Call this function again

    def main(self):
        self.update() # Start the recursive update function
        self.root.mainloop() # Start the app

a = App()
a.main()

我知道它有点复杂,将它集成到您​​当前的代码中可能很困难,但如果您有任何问题可以随意提问!希望这有帮助!