You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为基于Tkinter+Treeview+SQLite3的库存CRUD程序添加搜索功能

实现Treeview搜索功能的解决方案

我来帮你搞定这个搜索功能!下面是具体的修改步骤和完整代码,你只需要把这些内容整合到你的现有程序里就行:

1. 添加搜索UI组件

首先我们在界面上添加一个搜索框和搜索按钮,放在消息提示区和Treeview之间,这样用户操作起来很直观。

新增一个create_search_bar方法:

def create_search_bar(self):
    # 创建搜索框架
    search_frame = LabelFrame(self.root, text='Search Items', bg='sky blue', font='helvetica 10')
    search_frame.grid(row=4, column=0, columnspan=3, padx=8, pady=8, sticky='ew')
    
    # 搜索标签和输入框
    Label(search_frame, text='Item Name:', bg='sky blue', fg='black').grid(row=0, column=0, sticky=W, pady=2, padx=15)
    self.search_entry = Entry(search_frame, width=30)
    self.search_entry.grid(row=0, column=1, sticky=W, padx=5, pady=2)
    
    # 搜索按钮,绑定搜索函数
    Button(search_frame, text='Search', command=self.search_items, fg='black').grid(row=0, column=2, sticky=E, padx=5, pady=2)
    
    # 清空搜索按钮,恢复显示所有物品
    Button(search_frame, text='Show All', command=self.view_items, fg='black').grid(row=0, column=3, sticky=E, padx=5, pady=2)

然后在create_gui方法里调用这个方法,位置放在create_message_area之后:

def create_gui(self):
    self.create_left_icon()
    self.create_label_frame()
    self.create_message_area()
    self.create_search_bar()  # 新增这一行
    self.create_tree_view()
    self.create_scrollbar()
    self.create_bottom_buttons()
    self.view_items()

2. 实现搜索逻辑

接下来编写search_items方法,它会:

  • 获取搜索框的输入内容
  • 遍历数据库中所有物品,匹配名称(支持模糊匹配)
  • 在Treeview中只显示匹配的物品,并自动选中第一个匹配项
  • 如果没有匹配项,显示提示消息
def search_items(self):
    self.message['text'] = ''
    search_term = self.search_entry.get().strip()
    
    if not search_term:
        self.message['text'] = 'Please enter an item name to search'
        return
    
    # 清空Treeview现有内容
    items = self.tree.get_children()
    for item in items:
        self.tree.delete(item)
    
    # 执行模糊搜索的SQL查询
    query = 'SELECT * FROM items_list WHERE TipeBarang LIKE ? ORDER BY TipeBarang'
    parameters = ('%' + search_term + '%',)
    item_entries = self.execute_db_query(query, parameters)
    
    matched_items = []
    for row in item_entries:
        item_id = self.tree.insert('', 0, text=row[1], values=(row[2], row[3]))
        matched_items.append(item_id)
    
    if matched_items:
        # 选中第一个匹配项
        self.tree.selection_set(matched_items[0])
        # 滚动到选中项
        self.tree.see(matched_items[0])
        self.message['text'] = f'Found {len(matched_items)} matching item(s)'
    else:
        self.message['text'] = 'No items found matching your search'

完整修改后的代码

把上面的新增内容整合到你的原代码中,完整代码如下:

from tkinter import Tk, Button, PhotoImage, Label, LabelFrame, W, E, N, S, Entry, END, StringVar, Scrollbar, Toplevel
from tkinter import ttk
import sqlite3

class Inventory:
    db_filename = 'stock.db'
    def __init__(self, root):
        self.root = root
        self.create_gui()
        ttk.style = ttk.Style()
        ttk.style.configure('Treeview', font=('helvetica',10))
        ttk.style.configure('Treeview.Heading', font=('helvetica', 12, 'bold'))

    def execute_db_query(self, query, parameters=()):
        with sqlite3.connect(self.db_filename) as conn:
            cursor = conn.cursor()
            query_result = cursor.execute(query, parameters)
            conn.commit()
            return query_result

    def create_gui(self):
        self.create_left_icon()
        self.create_label_frame()
        self.create_message_area()
        self.create_search_bar()  # 新增搜索栏
        self.create_tree_view()
        self.create_scrollbar()
        self.create_bottom_buttons()
        self.view_items()

    def create_left_icon(self):
        photo = PhotoImage(file='./icons/logo.png')
        label = Label(image=photo)
        label.image = photo
        label.grid(row=0, column=0)

    def create_label_frame(self):
        labelframe = LabelFrame(self.root, text='Input New Items', bg='sky blue', font='helvetica 10')
        labelframe.grid(row=0, column=1, padx=8, pady=8, sticky='ew')
        Label(labelframe, text='Name of Item:', bg='sky blue', fg='black').grid(row=1, column=1, sticky=W, pady=2, padx=15)
        self.typefield = Entry(labelframe)
        self.typefield.grid(row=1, column=2, sticky=W, padx=5, pady=2)
        Label(labelframe, text='Stock Card ID:', bg='sky blue', fg='black').grid(row=2, column=1, sticky=W, pady=2, padx=15)
        self.cardfield = Entry(labelframe)
        self.cardfield.grid(row=2, column=2, sticky=W, padx=5, pady=2)
        Label(labelframe, text='Count:', bg='sky blue', fg='black').grid(row=3, column=1, sticky=W, pady=2, padx=15)
        self.countfield = Entry(labelframe)
        self.countfield.grid(row=3, column=2, sticky=W, padx=5, pady=2)
        Button(labelframe, text='Add', command=self.on_add_item_button_clicked, fg='black').grid(row=4, column=2, sticky=E, padx=5, pady=5)

    def create_message_area(self):
        self.message = Label(text='', fg='red')
        self.message.grid(row=3, column=1, sticky=W)

    # 新增的搜索栏创建方法
    def create_search_bar(self):
        search_frame = LabelFrame(self.root, text='Search Items', bg='sky blue', font='helvetica 10')
        search_frame.grid(row=4, column=0, columnspan=3, padx=8, pady=8, sticky='ew')
        
        Label(search_frame, text='Item Name:', bg='sky blue', fg='black').grid(row=0, column=0, sticky=W, pady=2, padx=15)
        self.search_entry = Entry(search_frame, width=30)
        self.search_entry.grid(row=0, column=1, sticky=W, padx=5, pady=2)
        
        Button(search_frame, text='Search', command=self.search_items, fg='black').grid(row=0, column=2, sticky=E, padx=5, pady=2)
        Button(search_frame, text='Show All', command=self.view_items, fg='black').grid(row=0, column=3, sticky=E, padx=5, pady=2)

    def create_tree_view(self):
        self.tree = ttk.Treeview(height=10, columns=('card', 'stock'), style='Treeview')
        self.tree.grid(row=6, column=0, columnspan=3)
        self.tree.heading('#0', text='Name of Item', anchor=W)
        self.tree.heading('card', text='Stock Card ID', anchor=W)
        self.tree.heading('stock', text='Count', anchor=W)

    def create_scrollbar(self):
        self.scrollbar = Scrollbar(orient='vertical', command=self.tree.yview)
        self.scrollbar.grid(row=6, column=3, rowspan=10, sticky='sn')
        # 绑定滚动条与Treeview同步
        self.tree.configure(yscrollcommand=self.scrollbar.set)

    def create_bottom_buttons(self):
        Button(text='Delete', command=self.on_delete_selected_button_clicked).grid(row=8, column=0, sticky=W, pady=10, padx=20)
        Button(text='Edit Stock', command=self.on_modify_selected_button_clicked).grid(row=8, column=1, sticky=W)

    def on_add_item_button_clicked(self):
        self.add_new_item()

    def on_delete_selected_button_clicked(self):
        self.message['text'] = ''
        try:
            self.tree.item(self.tree.selection())['values'][0]
        except IndexError as e:
            self.message['text'] = 'Select at least one item to be deleted'
            return
        self.delete_items()

    def on_modify_selected_button_clicked(self):
        self.message['text'] = ''
        try:
            self.tree.item(self.tree.selection())['values'][0]
        except:
            self.message['text'] = 'Select at least one item to be modified'
            return
        self.open_modify_window()

    def add_new_item(self):
        if self.new_items_validated():
            query = 'INSERT INTO items_list VALUES(NULL, ?, ?, ?)'
            parameters = (self.typefield.get(), self.cardfield.get(), self.countfield.get())
            self.execute_db_query(query, parameters)
            self.message['text'] = '{} has been added'.format(self.typefield.get())
            self.typefield.delete(0, END)
            self.cardfield.delete(0, END)
            self.countfield.delete(0, END)
            self.view_items()
        else:
            self.message['text'] = 'All entry field must be filled'
            self.view_items()

    def new_items_validated(self):
        return len(self.typefield.get()) !=0 and len(self.cardfield.get()) != 0 and len(self.countfield.get()) != 0

    def view_items(self):
        items = self.tree.get_children()
        for item in items:
            self.tree.delete(item)
        query = 'SELECT * FROM items_list ORDER BY TipeBarang'
        item_entries = self.execute_db_query(query)
        for row in item_entries:
            self.tree.insert('', 0, text=row[1], values=(row[2], row[3]))

    def delete_items(self):
        self.message['text']='' 
        name = self.tree.item(self.tree.selection())['text']
        query = 'DELETE FROM items_list WHERE TipeBarang = ?'
        self.execute_db_query(query, (name,))
        self.message['text'] = '{} has been deleted'.format(name)
        self.view_items()

    def open_modify_window(self):
        name = self.tree.item(self.tree.selection())['text']
        old_stock = self.tree.item(self.tree.selection())['values'][1]
        self.transient = Toplevel()
        self.transient.title('Update Stock')
        Label(self.transient, text='Name: ').grid(row=0, column=1)
        Entry(self.transient, textvariable=StringVar(self.transient, value=name), state='readonly').grid(row=0, column=2)
        Label(self.transient, text='Old Stock Count: ').grid(row=1, column=1)
        Entry(self.transient, textvariable=StringVar(self.transient, value=old_stock), state='readonly').grid(row=1, column=2)
        Label(self.transient, text='New Stock Count: ').grid(row=2, column=1)
        new_stock_number_entry_widget = Entry(self.transient)
        new_stock_number_entry_widget.grid(row=2, column=2)
        Button(self.transient, text='Update Item', command=lambda: self.update_stock(new_stock_number_entry_widget.get(), old_stock, name)).grid(row=3, column=2, sticky=E)
        self.transient.mainloop()

    def update_stock(self, newstock, old_stock, name):
        query = 'UPDATE items_list SET JumlahStok=? WHERE JumlahStok=? AND TipeBarang=?'
        parameters = (newstock, old_stock, name)
        self.execute_db_query(query, parameters)
        self.transient.destroy()
        self.message['text'] = '{} Stock Count has been updated'.format(name)
        self.view_items()

    # 新增的搜索方法
    def search_items(self):
        self.message['text'] = ''
        search_term = self.search_entry.get().strip()
        
        if not search_term:
            self.message['text'] = 'Please enter an item name to search'
            return
        
        # 清空现有Treeview内容
        items = self.tree.get_children()
        for item in items:
            self.tree.delete(item)
        
        # 模糊搜索SQL语句
        query = 'SELECT * FROM items_list WHERE TipeBarang LIKE ? ORDER BY TipeBarang'
        parameters = ('%' + search_term + '%',)
        item_entries = self.execute_db_query(query, parameters)
        
        matched_items = []
        for row in item_entries:
            item_id = self.tree.insert('', 0, text=row[1], values=(row[2], row[3]))
            matched_items.append(item_id)
        
        if matched_items:
            # 选中第一个匹配项并滚动到它
            self.tree.selection_set(matched_items[0])
            self.tree.see(matched_items[0])
            self.message['text'] = f'Found {len(matched_items)} matching item(s)'
        else:
            self.message['text'] = 'No items found matching your search'

if __name__ == "__main__":
    root = Tk()
    root.title("Inventory System")
    root.resizable(width=False, height=False)
    application = Inventory(root)
    root.mainloop()

额外优化说明

  • 我还给滚动条加了self.tree.configure(yscrollcommand=self.scrollbar.set),这样滚动条和Treeview能同步工作,之前的代码里漏掉了这一步。
  • 搜索支持模糊匹配,输入部分名称也能找到对应的物品,比如输入“pen”能找到“Pen”、“Pencil”等包含该字符串的物品。
  • 点击“Show All”按钮可以快速恢复显示所有库存物品。

这样修改后,你就可以在搜索框输入物品名称,点击搜索后,Treeview会只显示匹配的物品,并且自动选中第一个结果,方便你直接进行修改或删除操作啦!

内容的提问来源于stack exchange,提问作者Owenn Gimli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 11:33:11