import pandas as pd
import pyodbc
from fuzzywuzzy import fuzz
import re
from typing import List, Dict, Any, Optional, Tuple
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import threading
import logging
import gc
from datetime import datetime
"""此版本优化了性能,美化了界面显示,增加按表头排序,导出结果功能"""
class ProductSearchApp:
def __init__(self, root):
self.root = root
self.root.title("物料品名匹配系统 v2.0")
self.root.geometry("1200x600")
# 初始化日志
logging.basicConfig(
filename='product_search.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
self.logger = logging.getLogger()
# 数据库配置
self.db_config = {
"server": "IP",
"database": "DB",
"username": "admin",
"password": "admin",
"table_name": "test",
"search_columns": ["test002", "test003"]
}
# 存储所有结果数据
self.all_results = []
self.last_clicked_column = None
self.create_widgets()
self.setup_bindings()
# 初始化样式
self.setup_styles()
# 记录启动时间
self.logger.info("应用程序启动")
def setup_styles(self):
"""设置界面样式"""
style = ttk.Style()
style.theme_use('clam')
# 配置Treeview样式
style.configure("Treeview",
rowheight=25,
font=('Microsoft YaHei', 10))
style.configure("Treeview.Heading",
font=('Microsoft YaHei', 10, 'bold'))
# 配置按钮样式
style.configure('TButton', padding=5, font=('Microsoft YaHei', 9))
# 配置进度条样式
style.configure("Horizontal.TProgressbar",
thickness=20,
troughcolor='#f0f0f0',
background='#4caf50')
def create_widgets(self):
"""创建界面组件"""
# 顶部框架 - 文件选择和数据库配置
top_frame = ttk.LabelFrame(self.root, text="配置", padding=10)
top_frame.pack(fill=tk.X, padx=10, pady=5)
# 文件选择
ttk.Label(top_frame, text="Excel文件:").grid(row=0, column=0, sticky=tk.W)
self.file_entry = ttk.Entry(top_frame, width=50)
self.file_entry.grid(row=0, column=1, padx=5)
ttk.Button(top_frame, text="浏览", command=self.browse_file).grid(row=0, column=2)
# 数据库配置
ttk.Label(top_frame, text="服务器:").grid(row=1, column=0, sticky=tk.W)
self.server_entry = ttk.Entry(top_frame)
self.server_entry.insert(0, self.db_config["server"])
self.server_entry.grid(row=1, column=1, padx=5, sticky=tk.W)
ttk.Label(top_frame, text="数据库:").grid(row=2, column=0, sticky=tk.W)
self.db_entry = ttk.Entry(top_frame)
self.db_entry.insert(0, self.db_config["database"])
self.db_entry.grid(row=2, column=1, padx=5, sticky=tk.W)
ttk.Label(top_frame, text="用户名:").grid(row=1, column=3, sticky=tk.W)
self.user_entry = ttk.Entry(top_frame)
self.user_entry.insert(0, self.db_config["username"])
self.user_entry.grid(row=1, column=4, padx=5, sticky=tk.W)
ttk.Label(top_frame, text="密码:").grid(row=2, column=3, sticky=tk.W)
self.pwd_entry = ttk.Entry(top_frame, show="*")
self.pwd_entry.insert(0, self.db_config["password"])
self.pwd_entry.grid(row=2, column=4, padx=5, sticky=tk.W)
# 进度条
self.progress = ttk.Progressbar(top_frame, orient=tk.HORIZONTAL,
length=200, mode='determinate',
style="Horizontal.TProgressbar")
self.progress.grid(row=3, column=0, columnspan=5, pady=5, sticky=tk.EW)
# 中间框架 - 操作按钮和搜索框
middle_frame = ttk.Frame(self.root)
middle_frame.pack(fill=tk.X, padx=10, pady=5)
# 操作按钮框架
btn_frame = ttk.Frame(middle_frame)
btn_frame.pack(side=tk.LEFT, fill=tk.X, expand=True)
ttk.Button(btn_frame, text="提取Excel数据", command=self.extract_data).pack(side=tk.LEFT, padx=5)
ttk.Button(btn_frame, text="精确匹配查询", command=self.run_normal_search).pack(side=tk.LEFT, padx=5)
ttk.Button(btn_frame, text="三字截断查询", command=self.run_truncated_search).pack(side=tk.LEFT, padx=5)
ttk.Button(btn_frame, text="导出结果", command=self.export_results).pack(side=tk.LEFT, padx=5)
ttk.Button(btn_frame, text="清除结果", command=self.clear_results).pack(side=tk.LEFT, padx=5)
# 结果搜索框架
search_frame = ttk.Frame(middle_frame)
search_frame.pack(side=tk.RIGHT, fill=tk.X, padx=5)
ttk.Label(search_frame, text="结果筛选:").pack(side=tk.LEFT)
self.result_search_entry = ttk.Entry(search_frame, width=30)
self.result_search_entry.pack(side=tk.LEFT, padx=5)
self.result_search_entry.bind("<Return>", lambda event: self.filter_results())
ttk.Button(search_frame, text="搜索", command=self.filter_results).pack(side=tk.LEFT)
# 底部框架 - 结果显示
result_frame = ttk.LabelFrame(self.root, text="结果", padding=10)
result_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
# 树状视图显示结果
self.tree = ttk.Treeview(result_frame, columns=(
"type", "code", "name", "spec", "color_code", "color_name",
"category_code", "category_name", "unit"), show="headings")
# 设置列标题和宽度
columns = [
("type", "匹配类型", 80),
("code", "品号", 80),
("name", "品名", 150),
("spec", "规格", 200),
("color_code", "颜色代号", 80),
("color_name", "颜色名称", 100),
("category_code", "分类代号", 80),
("category_name", "分类名称", 100),
("unit", "单位", 50)
]
for col_id, col_text, width in columns:
self.tree.heading(col_id, text=col_text,
command=lambda c=col_id: self.treeview_sort_column(c, False))
self.tree.column(col_id, width=width, anchor=tk.W)
# 添加滚动条
scrollbar = ttk.Scrollbar(result_frame, orient=tk.VERTICAL, command=self.tree.yview)
self.tree.configure(yscroll=scrollbar.set)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.tree.pack(fill=tk.BOTH, expand=True)
# 状态栏
self.status_var = tk.StringVar() # 状态栏文本变量
self.status_var.set("就绪")
ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN).pack(fill=tk.X, padx=10, pady=5)
一、类初始化方法 __init__
功能解析
1. 主窗口系统初始化
2. 日志系统配置
3. 数据服务层配置
4. 运行时状态管理
5. 界面构建流水线
6. 系统监控
二、样式
三、创建图形界面
区域 | 组件类型 | 布局方式 | 主要功能 |
---|---|---|---|
顶部框架 (top_frame ) | LabelFrame | pack | 文件选择和数据库配置 |
中间框架 (middle_frame ) | Frame | pack | 操作按钮和搜索框 |
底部框架 (result_frame ) | LabelFrame | pack | 结果展示区域 |
-
顶部框架 (
top_frame
)top_frame = ttk.LabelFrame(self.root, text="配置", padding=10) top_frame.pack(fill=tk.X, padx=10, pady=5)
-
文件选择组件
ttk.Label(top_frame, text="Excel文件:").grid(row=0, column=0, sticky=tk.W) self.file_entry = ttk.Entry(top_frame, width=50) self.file_entry.grid(row=0, column=1, padx=5) ttk.Button(top_frame, text="浏览", command=self.browse_file).grid(row=0, column=2)
-
标签(Label):显示 “Excel 文件:”,位于第 0 行第 0 列,左对齐(
sticky=tk.W
)。 -
输入框(Entry):
self.file_entry
用于输入文件路径,宽度 50,位于第 0 行第 1 列,左右边距padx=5
。 -
按钮(Button):“浏览” 按钮绑定
browse_file
方法,用于打开文件选择对话框,位于第 0 行第 2 列。
-
-
数据库配置组件
字段 输入框变量 安全措施 布局位置 服务器 server_entry
- row=1, column=1 数据库 db_entry
- row=2, column=1 用户名 user_entry
- row=1, column=4 密码 pwd_entry
show="*"
掩码输入row=2, column=4 -
进度条
self.progress = ttk.Progressbar(top_frame, orient=tk.HORIZONTAL, length=200, mode='determinate') self.progress.grid(row=3, column=0, columnspan=5, pady=5, sticky=tk.EW)
-
-
中间框架 (
middle_frame
)middle_frame = ttk.Frame(self.root) middle_frame.pack(fill=tk.X, padx=10, pady=5)
-
操作按钮组
按钮文本 绑定方法 功能描述 提取Excel数据 extract_data
从Excel读取数据 精确匹配查询 run_normal_search
执行精确查询 三字截断查询 run_truncated_search
执行模糊查询 导出结果 export_results
导出数据到文件 清除结果 clear_results
重置界面 -
搜索框组
self.result_search_entry = ttk.Entry(search_frame, width=30) self.result_search_entry.bind("<Return>", lambda e: self.filter_results())
-
-
底部框架 (
result_frame
)self.tree = ttk.Treeview(result_frame, columns=(...), show="headings")
-
表格列配置
列ID 显示文本 宽度 排序功能 type
匹配类型 80 treeview_sort_column
code
品号 80 treeview_sort_column
name
品名 150 treeview_sort_column
-
滚动条集成
scrollbar = ttk.Scrollbar(result_frame, orient=tk.VERTICAL) self.tree.configure(yscroll=scrollbar.set)
-
- 状态栏
self.status_var = tk.StringVar() # 状态栏文本变量 self.status_var.set("就绪") ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN).pack(fill=tk.X, padx=10, pady=5)
2.默认内容}
3.ttk.Label( self.root, # 放置在主窗口 textvariable=self.status_var, # 绑定动态文本变量 relief=tk.SUNKEN # 凹陷边框效果 ).pack( fill=tk.X, # 水平填充 padx=10, pady=5 # 外边距 )