pandas学习打卡_task2 pandas基础

本文介绍了pandas库中文件的读取与写入,包括csv、excel和txt格式,详细讲解了read_csv等函数的常用参数。此外,文章还探讨了Series和DataFrame两种基本数据结构,以及数据框的属性和操作。接着,作者阐述了常见的基本函数,如汇总、统计、排序和apply方法。最后,提到了窗口对象的应用,并提供了两个练习案例。

学习目标:

一个月掌握 pandas 入门知识

学习目录:

一、文件的读取与写入
1.文件读取
2.数据写入
二、基本数据结构
1.series
2.dataFrame
三、常用基本函数
1.汇总函数
2.特征统计函数
3.唯一值函数
4.替换函数
5.排序函数
6.apply方法
四、窗口对象
1.滑窗对象
2.扩张窗口
五、练习
1.Ex1 口袋妖怪数据集
2.Ex2:指数加权窗口

打卡内容:

一、文件的读取与写入

1.文件读取

pandas 可以读取的文件格式有很多,这里主要介绍读取 csv, excel, txt 文件。

csv:

df_csv = pd.read_csv('xxx.csv')

excel:

df_excel = pd.read_excel('xxx.xlsx')

txt:

df_txt = pd.read_table('xxx.txt')

他们都有一些常用的参数

  • header=None: 表示第一行不作为列名
  • index_col: 表示把某一列或几列作为索引
  • usecols :表示读取列的集合,默认读取所有的列
  • parse_dates :表示需要转化为时间的列
  • nrows 表示读取的数据行数。

在读取 txt 文件时,经常遇到分隔符非空格的情况, read_table 有一个分割参数 sep ,它使得用户可以自定义分割符号,进行 txt 数据的读取。
例如:

在这里插入图片描述

2.数据写入

1.去除索引列
最常用的操作是把 index 设置为 False,特别当索引没有特殊意义的时候,这样的行为能把索引在保存的时候去除。

df_csv.to_csv('data/my_csv_saved.csv', index=False)

df_excel.to_excel('data/my_excel_saved.xlsx', index=False)

2.保存为txt格式
pandas 中没有定义 to_table 函数,但是 to_csv 可以保存为 txt 文件,并且允许自定义分隔符,常用制表符 \t 分割:

df_txt.to_csv('data/my_txt_saved.txt', sep='\t', index=False)

3.将表格保存为 markdown 和 latex 语言
使用to_markdown 和 to_latex 函数,此处需要安装 tabulate 包。

在这里插入图片描述

二、基本数据结构

1.series(存储一维 values)

Series 一般由四个部分组成:

  • 序列的值 data
  • 索引 index
  • 存储类型 dtype
  • 序列的名字 name

其中,索引也可以指定它的名字,默认为空

 s = pd.Series(data = [100, 'a', {'dic1':5}],
              index = pd.Index(['id1', 20, 'third'], name='my_idx'),
              dtype = 'object',
              name = 'my_name')
 s
#output:
my_idx
id1              100
20                 a
third    {'dic1': 5}
Name: my_name, dtype: object

object 代表了一种混合类型,正如上面的例子中存储了整数、字符串以及 Python 的字典数据结构。此外,目前 pandas 把纯字符串序列也默认认为是一种 object 类型的序列,但它也可以用 string 类型存储,文本序列的内容会在第八章中讨论。

1)获取序列属性
对于这些属性,可以通过 . 的方式来获取:

s.values
#Output: array([100, 'a', {'dic1': 5}], dtype=object)

s.index
#Output: Index(['id1', 20, 'third'], dtype='object', name='my_idx')

s.dtype
#Output:dtype('O')

s.name
#Output:'my_name'

2)获取序列长度

利用 .shape 可以获取序列的长度:

s.shape
#Output: (3,)

3)获取单个对应的索引值
如果想要取出单个索引对应的值,可以通过 [index_item] 可以取出。

 s['third']
Out[29]: {'dic1': 5}

2.dataFrame(存储二维 values)

DataFrame 在 Series 的基础上增加了列索引,一个数据框可以由二维的 data 与行列索引来构造:

data = [[1, 'a', 1.2], [2, 'b', 2.2], [3, 'c', 3.2]]
df = pd.DataFrame(data = data,
				index = ['row_%d'%i for i in range(3)],
				columns=['col_0', 'col_1', 'col_2'])
df
#output:
 
       col_0 col_1  col_2
row_0      1     a    1.2
row_1      2     b    2.2
row_2      3     c    3.2

但一般而言,更多的时候会采用从列索引名到数据的映射来构造数据框,同时再加上行索引:

df = pd.DataFrame(data = {'col_0': [1,2,3], 'col_1':list('abc'),
                           'col_2': [1.2, 2.2, 3.2]},
                     index = ['row_%d'%i for i in range(3)])
df

在这里插入图片描述
在 DataFrame 中可以用 [col_name] 与 [col_list] 来取出相应的列与由多个列组成的表,结果分别为 Series 和 DataFrame :

df['col_0']

在这里插入图片描述

df[['col_0', 'col_1']]

在这里插入图片描述与 Series 类似,在数据框中同样可以取出相应的属性:
通过 .T 可以把 DataFrame 进行转置:

 df.T

在这里插入图片描述

三、常用基本函数

使用表格前7列

df = df[df.columns[:7]]

1.汇总函数

1)head, tail 函数分别表示返回表或者序列的前 n 行和后 n 行,其中 n 默认为5
在这里插入图片描述2)info, describe 分别返回表的 信息概况 和表中 数值列对应的主要统计量
在这里插入图片描述

info, describe 只能实现较少信息的展示,如果想要对一份数据集进行全面且有效的观察,特别是在列较多的情况下,推荐使用 pandas-profiling 包,它将在第十一章被再次提到。

2.特征统计函数

在 Series 和 DataFrame 上定义了许多统计函数,最常见的是 sum, mean, median, var, std, max, min 。例如,选出身高和体重列进行演示:
在这里插入图片描述此外,需要介绍的是 quantile, count, idxmax 这三个函数,它们分别返回的是分位数、非缺失值个数、最大值对应的索引:
在这里插入图片描述上面这些所有的函数,由于操作后返回的是标量,所以又称为聚合函数,它们有一个公共参数 axis ,默认为0代表逐列聚合,如果设置为1则表示逐行聚合:
在这里插入图片描述

3.唯一值函数

对序列使用 uniquenunique 可以分别得到其唯一值组成的列表和唯一值的个数:
在这里插入图片描述value_counts 可以得到唯一值和其对应出现的频数:

在这里插入图片描述

4.替换函数

5.排序函数

6.apply方法

四、窗口对象

1.滑窗对象

2.扩张窗口

五、练习

1.Ex1 口袋妖怪数据集

2.Ex2:指数加权窗口

import tkinter as tk from tkinter import ttk, messagebox, filedialog from PIL import Image, ImageTk, ImageDraw, ImageFont import vlc import os import cv2 import json import time import threading import queue import random import subprocess import sqlite3 from datetime import datetime import pandas as pd import pymysql OUT_DIR = "./output" class EmployeeClockSystem: def __init__(self, root): self.root = root self.root.title("员工工牌识别打卡系统") self.root.geometry("1200x700") self.root.configure(bg="#f0f0f0") # 设置输出目录 self.OUT_DIR = "./output" os.makedirs(self.OUT_DIR, exist_ok=True) # 创建样式 self.style = ttk.Style() self.style.configure("Title.TLabel", font=("微软雅黑", 18, "bold"), foreground="#2c3e50") self.style.configure("Subtitle.TLabel", font=("微软雅黑", 14), foreground="#34495e") self.style.configure("Info.TLabel", font=("微软雅黑", 12), foreground="#2c3e50") self.style.configure("Card.TFrame", background="#ffffff", borderwidth=1, relief="raised", padding=10) self.style.configure("Control.TFrame", background="#e0e0e0", borderwidth=1, relief="sunken", padding=10) # 主布局框架 - 使用PanedWindow实现可调整的分割 main_paned = tk.PanedWindow(root, orient=tk.HORIZONTAL, sashrelief=tk.RAISED, sashwidth=4) main_paned.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 左侧视频区域 (50%) left_frame = ttk.Frame(main_paned) main_paned.add(left_frame, stretch="always") # 右侧员工信息区域 (50%) right_frame = ttk.Frame(main_paned) main_paned.add(right_frame, stretch="always") # 视频流标题 ttk.Label(left_frame, text="实时视频监控", style="Title.TLabel").pack(pady=(0, 10), anchor=tk.W, padx=10) # 视频显示区域 video_card = ttk.Frame(left_frame, style="Card.TFrame") video_card.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10)) self.video_container = ttk.Frame(video_card) self.video_container.pack(fill=tk.BOTH, expand=True) # 视频控制面板 control_frame = ttk.Frame(left_frame, style="Control.TFrame") control_frame.pack(fill=tk.X, padx=10, pady=(0, 10)) # URL输入框 ttk.Label(control_frame, text="RTSP地址:").pack(side=tk.LEFT, padx=(0, 5)) self.url_entry = ttk.Entry(control_frame, width=40) self.url_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10)) self.url_entry.insert(0, "rtsp://192.168.1.101/stream1") # 连接按钮 self.connect_button = ttk.Button(control_frame, text="启动监控", command=self.toggle_stream, width=12) self.connect_button.pack(side=tk.LEFT, padx=(0, 5)) # 截图按钮 self.snapshot_button = ttk.Button(control_frame, text="抓拍", command=self.take_snapshot, width=8, state=tk.DISABLED) self.snapshot_button.pack(side=tk.LEFT) # 员工信息标题 ttk.Label(right_frame, text="员工信息识别", style="Title.TLabel").pack(pady=(0, 10), anchor=tk.W, padx=10) # 员工信息卡片 info_card = ttk.Frame(right_frame, style="Card.TFrame") info_card.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10)) #引用员工卡片 self.info_card = info_card # 员工照片和基本信息 info_frame = ttk.Frame(info_card) info_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 左侧员工照片区域 avatar_frame = ttk.Frame(info_frame, width=180, height=200) avatar_frame.pack(side=tk.LEFT, padx=(0, 20), fill=tk.Y) self.avatar_label = ttk.Label(avatar_frame) self.avatar_label.pack(fill=tk.BOTH, expand=True) # 默认头像 self.update_avatar() # 右侧员工详细信息 detail_frame = ttk.Frame(info_frame) detail_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) ttk.Label(detail_frame, text="员工基本信息", style="Subtitle.TLabel").pack(anchor=tk.W, pady=(0, 10)) # 信息标签 - 使用Grid布局更精确控制 label_frame = ttk.Frame(detail_frame) label_frame.pack(fill=tk.X, pady=5) ttk.Label(label_frame, text="姓名:", width=8, anchor=tk.E, style="Info.TLabel").grid(row=0, column=0, sticky="e", padx=5, pady=5) self.name_value = ttk.Label(label_frame, text="", width=20, anchor=tk.W, style="Info.TLabel") self.name_value.grid(row=0, column=1, sticky="w", padx=5, pady=5) ttk.Label(label_frame, text="工号:", width=8, anchor=tk.E, style="Info.TLabel").grid(row=1, column=0, sticky="e", padx=5, pady=5) self.id_value = ttk.Label(label_frame, text="", width=20, anchor=tk.W, style="Info.TLabel") self.id_value.grid(row=1, column=1, sticky="w", padx=5, pady=5) ttk.Label(label_frame, text="部门:", width=8, anchor=tk.E, style="Info.TLabel").grid(row=2, column=0, sticky="e", padx=5, pady=5) self.dept_value = ttk.Label(label_frame, text="", width=20, anchor=tk.W, style="Info.TLabel") self.dept_value.grid(row=2, column=1, sticky="w", padx=5, pady=5) ttk.Label(label_frame, text="打卡状态:", width=8, anchor=tk.E, style="Info.TLabel").grid(row=4, column=0, sticky="e", padx=5, pady=5) self.status_value = ttk.Label(label_frame, text="未识别", width=20, anchor=tk.W, style="Info.TLabel") self.status_value.grid(row=4, column=1, sticky="w", padx=5, pady=5) # 打卡按钮 button_frame = ttk.Frame(detail_frame) button_frame.pack(fill=tk.X, pady=10) self.clock_button = ttk.Button(button_frame, text="导出打卡EXCEL", command=self.export_attendance_to_excel, width=15) self.clock_button.pack(side=tk.RIGHT, padx=(0, 20)) self.search_button = ttk.Button(button_frame, text="查询", command=self.export_attendance_to_excel, width=15) self.search_button.pack(side=tk.RIGHT, padx=(0, 30)) # 考勤记录标题 ttk.Label(right_frame, text="今日考勤记录", style="Title.TLabel").pack(pady=(10, 10), anchor=tk.W, padx=10) # 考勤记录表格 record_card = ttk.Frame(right_frame, style="Card.TFrame") record_card.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10)) # 创建表格 columns = ("time", "id", "name", "dept", "status") self.record_tree = ttk.Treeview(record_card, columns=columns, show="headings", height=8) # 设置列标题 self.record_tree.heading("time", text="时间", anchor=tk.W) self.record_tree.heading("id", text="工号", anchor=tk.W) self.record_tree.heading("name", text="姓名", anchor=tk.W) self.record_tree.heading("dept", text="部门", anchor=tk.W) self.record_tree.heading("status", text="状态", anchor=tk.W) # 设置列宽 self.record_tree.column("time", width=150, anchor=tk.W) self.record_tree.column("id", width=100, anchor=tk.W) self.record_tree.column("name", width=100, anchor=tk.W) self.record_tree.column("dept", width=120, anchor=tk.W) self.record_tree.column("status", width=80, anchor=tk.W) # 添加滚动条 scrollbar = ttk.Scrollbar(record_card, orient="vertical", command=self.record_tree.yview) self.record_tree.configure(yscrollcommand=scrollbar.set) # 布局 self.record_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=10, pady=10) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 状态栏 self.status_var = tk.StringVar(value="系统就绪") status_bar = ttk.Label(root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W) status_bar.pack(side=tk.BOTTOM, fill=tk.X) # 初始化变量 self.stream_active = False self.instance = vlc.Instance("--no-xlib") self.player = self.instance.media_player_new() # 模拟员工数据库 self.employees = { "1001": {"name": "张明", "dept": "技术部", "avatar": "avatar1.jpg"}, "1002": {"name": "李华", "dept": "市场部", "avatar": "avatar2.jpg"}, "1003": {"name": "王芳", "dept": "财务部", "avatar": "avatar3.jpg"}, "1004": {"name": "赵刚", "dept": "人力资源", "avatar": "avatar4.jpg"}, "1005": {"name": "陈晓", "dept": "产品部", "avatar": "avatar5.jpg"}, } # 考勤记录 self.attendance_records = [] self.add_sample_records() # 初始化线程队列 self.gui_queue = queue.Queue() self.root.after(100, self.process_queue) print("导出按钮状态:", self.clock_button.cget('state')) def process_queue(self): """处理队列中的GUI更新任务""" while not self.gui_queue.empty(): try: task = self.gui_queue.get_nowait() if task["type"] == "update_employee_info": self.name_value.config(text=task["name"]) self.id_value.config(text=task["id"]) self.dept_value.config(text=task["dept"]) self.status_value.config(text=task["status"]) self.show_employee_avatar(task["avatar"]) elif task["type"] == "update_status": self.status_var.set(task["message"]) elif task["type"] == "clock_in": self.clock_in_task(task["emp_id"], task["emp_name"], task["emp_dept"]) except queue.Empty: pass self.root.after(100, self.process_queue) def update_avatar(self, image_path=None): if image_path and os.path.exists(image_path): try: # 尝试加载图片 print("opennnnnnnnnnnn") img = Image.open(image_path) print("opennnnnnnnnnnn") # 调整图片大小以适应显示区域 img = self.resize_image(img, target_width=180, target_height=200) # 转换为Tkinter PhotoImage photo = ImageTk.PhotoImage(img) # 更新显示 self.avatar_label.config(image=photo) self.avatar_label.image = photo # 保持引用 print(f"成功加载头像: {image_path}") return True except Exception as e: print(f"加载图片失败: {e}") # 加载失败时显示默认头像 self.show_default_avatar(error=True) return False else: # 没有提供图片路径或路径无效 self.show_default_avatar() return False def show_default_avatar(self): """显示默认头像""" default_img = Image.new('RGB', (180, 200), color='#3498db') draw = ImageDraw.Draw(default_img) try: font = ImageFont.truetype("arial.ttf", 24) except: font = ImageFont.load_default() draw.text((40, 85), "无数据", fill="white", font=font) default_photo = ImageTk.PhotoImage(default_img) self.avatar_label.config(image=default_photo) self.avatar_label.image = default_photo def resize_image(self, img, target_width, target_height): # """调整图片大小,保持宽高比并填充背景""" # 计算缩放比例 width, height = img.size scale = min(target_width / width, target_height / height) # 计算新尺寸 new_width = int(width * scale) new_height = int(height * scale) # 调整图片大小 img = img.resize((new_width, new_height), Image.LANCZOS) # 创建新图片并粘贴调整后的图片到中心 new_img = Image.new('RGB', (target_width, target_height), color='white') position = ( (target_width - new_width) // 2, (target_height - new_height) // 2 ) new_img.paste(img, position) return new_img def add_sample_records(self): """添加示例考勤记录""" records = [ ("09:00:24", "1001", "张明", "技术部", "正常"), ("09:01:35", "1002", "李华", "市场部", "迟到"), ("09:05:47", "1003", "王芳", "财务部", "正常"), ("12:01:15", "1001", "张明", "技术部", "外出"), ("13:30:08", "1004", "赵刚", "人力资源", "正常"), ] for record in records: self.attendance_records.append(record) self.record_tree.insert("", tk.END, values=record) def add_new_records(self, record): if (record.get('id') and record.get('name') and record.get('dept')): new_record = ( datetime.now().strftime("%H:%M:%S"), # 当前时间 record.get('id'), # 员工ID record.get('name'), # 姓名 record.get('dept'), # 部门 "正常" # 考勤状态 ) self.attendance_records.append(new_record) self.record_tree.insert("", tk.END, values=new_record) else: # 可选:添加错误处理(如日志记录或弹窗提示) print("错误:缺少必要的字段信息,记录未添加") def export_attendance_to_excel(self): """从本地数据库导出考勤记录到Excel文件""" # 弹出文件保存路径 file_path = filedialog.asksaveasfilename( defaultextension=".xlsx", filetypes=[("Excel 文件", "*.xlsx"), ("所有文件", "*.*")], title="保存考勤记录为Excel" ) if not file_path: return # 用户取消了保存 try: # 1. 连接 MySQL 数据库(根据你的实际配置填写) # conn = mysql.connector.connect( # host="localhost", # 数据库地址 # user="root", # 用户名 # password="yourpass", # 密码 # database="attendance_db" # 数据库名称 # ) conn = pymysql.connect( host='localhost', user='root', password='139800', database='employeeinfomation' ) # 2. 使用 pandas 直接读取 SQL 查询结果 query = "SELECT * FROM workcard" df = pd.read_sql_query(query, conn) # 3. 闭数据库连接 conn.close() # 4. 如果没有数据 if df.empty: messagebox.showwarning("导出失败", "数据库中没有可导出的考勤记录!") return # 5. 导出为 Excel 文件 df.to_excel(file_path, index=False) messagebox.showinfo("导出成功", f"考勤记录已成功导出到:\n{file_path}") except Exception as e: messagebox.showerror("导出失败", f"导出考勤记录时发生错误:\n{str(e)}") def toggle_stream(self): """切换视频流状态""" if self.stream_active: self.stop_stream() else: self.start_stream() def start_stream(self): """启动视频流""" url = self.url_entry.get().strip() if not url: messagebox.showerror("错误", "请输入有效的视频流URL") return try: media = self.instance.media_new(url) self.player.set_media(media) win_id = self.video_container.winfo_id() if os.name == 'nt': win_id = int(win_id) self.player.set_hwnd(win_id) else: self.player.set_xwindow(win_id) self.player.play() self.stream_active = True self.connect_button.config(text="停止监控") self.snapshot_button.config(state=tk.NORMAL) self.status_var.set(f"正在播放: {url}") # 启动视频流线程 threading.Thread(target=self.video_thread, daemon=True).start() # 启动识别线程 threading.Thread(target=self.recognition_thread, daemon=True).start() except Exception as e: messagebox.showerror("连接错误", f"无法连接到视频流: {str(e)}") self.status_var.set("连接失败") def video_thread(self): """视频流播放线程""" pass # 视频流由VLC内部处理,无需额外操作 def recognition_thread(self, out_dir: str = OUT_DIR): """使用实际工牌识别代码进行识别的线程""" cap = cv2.VideoCapture(self.url_entry.get().strip()) if not cap.isOpened(): print("[错误] 无法打开视频流") return # 加载预训练的人脸检测模型 face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') while self.stream_active: ret, frame = cap.read() if not ret: print("[调试信息] 无法读取视频帧") continue # 转为灰度图,提高检测效率 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = 0 # 检测人脸 faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)) if len(faces) > 0: print(f"[调试信息] 检测到 {len(faces)} 张人脸") # 保存当前帧供后续处理 temp_image_path = "temp_frame.jpg" cv2.imwrite(temp_image_path, frame) print(f"[调试信息] 图像已保存至 {temp_image_path}") # 调用main.py 进行图像识别 try: print(f"[调试信息] 正在调用 main.py 处理 {temp_image_path}") subprocess.run(["python", "main.py", temp_image_path], check=True) print("[调试信息] main.py 执行完成") except subprocess.CalledProcessError as e: print(f"[错误信息] main.py 执行失败: {e}") # 读取main.py 输出的JSON文件 stem = os.path.splitext(os.path.basename(temp_image_path))[0] final_json = os.path.join(OUT_DIR, f"{stem}_face_result.json") final_picture = os.path.join(OUT_DIR, f"{stem}_face.jpg") img = Image.open(final_picture) print(img) self.update_avatar(final_picture) if os.path.exists(final_json): print(f"[调试信息] JSON文件已找到: {final_json}") with open(final_json, "r", encoding="utf-8") as f: result = json.load(f) ocr_info = result.get("OCR", {}) emp_id = ocr_info.get("id") emp_name = ocr_info.get("name") emp_dept = ocr_info.get("department") # 打印识别结果 print(f"[调试信息] 识别结果: ID={emp_id}, 姓名={emp_name}, 部门={emp_dept}") if (emp_id == 0): status_task_input="未识别" else: status_task_input="已识别" # 将识别结果发送到GUI队列 task = { "type": "update_employee_info", "name": emp_name, "id": emp_id, "dept": emp_dept, "status": status_task_input, # 添加这个字段 "avatar": os.path.join(OUT_DIR, f"{stem}_face.jpg") } self.gui_queue.put(task) # 添加示例记录 self.add_new_records(task) # 弹窗提示打卡成功 messagebox.showinfo("打卡成功", f"{emp_name} 已成功打卡!") # time.sleep(10) # 控制识别频率 cap.release() def stop_stream(self): """停止视频流""" if self.player: self.player.stop() self.stream_active = False self.connect_button.config(text="启动监控") self.snapshot_button.config(state=tk.DISABLED) self.status_var.set("已停止视频流") # 清空员工信息 self.name_value.config(text="") self.id_value.config(text="") self.dept_value.config(text="") self.status_value.config(text="未识别") self.show_default_avatar() # 恢复边框样式 # self.style.configure("Card.TFrame", background="#ffffff", borderwidth=1, relief="raised", padding=10) # self.info_card.configure(style="Card.TFrame") def take_snapshot(self): """抓拍当前帧""" if self.stream_active: timestamp = time.strftime("%Y%m%d_%H%M%S") filename = f"snapshot_{timestamp}.png" self.player.video_take_snapshot(0, filename, 0, 0) messagebox.showinfo("抓拍成功", f"已保存截图: {filename}") self.status_var.set(f"截图已保存: {filename}") def show_employee_avatar(self, avatar_path): """显示员工头像""" try: colors = ["#3498db", "#2ecc71", "#e74c3c", "#f39c12", "#9b59b6"] color = random.choice(colors) img = Image.new('RGB', (180, 200), color=color) draw = ImageDraw.Draw(img) try: font = ImageFont.truetype("arial.ttf", 20) except: font = ImageFont.load_default() draw.text((40, 85), "员工照片", fill="white", font=font) photo = ImageTk.PhotoImage(img) self.avatar_label.config(image=photo) self.avatar_label.image = photo except Exception as e: print(f"头像加载错误: {e}") def clock_in(self): """员工打卡""" emp_id = self.id_value.cget("text") emp_name = self.name_value.cget("text") emp_dept = self.dept_value.cget("text") task = {"type": "clock_in", "emp_id": emp_id, "emp_name": emp_name, "emp_dept": emp_dept} self.gui_queue.put(task) # 打卡后恢复默认边框样式 # self.style.configure("Card.TFrame", background="#ffffff", borderwidth=1, relief="raised", padding=10) # self.info_card.configure(style="Card.TFrame") def clock_in_task(self, emp_id, emp_name, emp_dept): """执行打卡逻辑""" current_time = time.strftime("%H:%M:%S") hour = int(time.strftime("%H")) minute = int(time.strftime("%M")) status = "迟到" if (hour > 9 or (hour == 9 and minute > 0)) else "正常" record = (current_time, emp_id, emp_name, emp_dept, status) self.attendance_records.append(record) self.record_tree.insert("", tk.END, values=record) self.status_value.config(text=f"已打卡 ({status})") self.status_var.set(f"{emp_name} 打卡成功! 时间: {current_time}") self.record_tree.see(self.record_tree.get_children()[-1]) # 边框变色 - 成功打卡时变为绿色 # self.style.configure("Success.TFrame", background="#ffffff", borderwidth=2, relief="solid", padding=10) # self.info_card.configure(style="Success.TFrame") # 弹窗提示打卡成功 messagebox.showinfo("打卡成功", f"{emp_name} 已成功打卡!\n时间: {current_time}\n状态: {status}") if __name__ == "__main__": root = tk.Tk() app = EmployeeClockSystem(root) root.mainloop()这里面优势的边框变色的代码吗,请找出来,帮助我删掉,我只需要显示识别出来的图片杰克不需要边框变色
最新发布
08-26
你提到的“边框变色”功能在代码中是**被注释掉的**,并没有真正启用。不过你希望**彻底删除所有边框变色相的代码**,只保留显示识别图片的功能。 --- ## ✅ 涉及“边框变色”的代码位置如下: ### 1. 在 `clock_in_task` 方法中(用于打卡后变色): ```python # 边框变色 - 成功打卡时变为绿色 # self.style.configure("Success.TFrame", background="#ffffff", borderwidth=2, relief="solid", padding=10) # self.info_card.configure(style="Success.TFrame") ``` ### 2. 在 `stop_stream` 方法中(用于恢复默认边框): ```python # 恢复边框样式 # self.style.configure("Card.TFrame", background="#ffffff", borderwidth=1, relief="raised", padding=10) # self.info_card.configure(style="Card.TFrame") ``` ### 3. 在 `clock_in` 方法中(用于触发打卡后变色): ```python # 打卡后恢复默认边框样式 # self.style.configure("Card.TFrame", background="#ffffff", borderwidth=1, relief="raised", padding=10) # self.info_card.configure(style="Card.TFrame") ``` --- ## ✅ 删除或保留建议 你希望 **删除所有边框变色相的代码和注释**。下面是修改后的代码片段。 --- ### ✅ 修改后的代码 #### 1. 修改 `clock_in_task` 方法 ```python def clock_in_task(self, emp_id, emp_name, emp_dept): """执行打卡逻辑""" current_time = time.strftime("%H:%M:%S") hour = int(time.strftime("%H")) minute = int(time.strftime("%M")) status = "迟到" if (hour > 9 or (hour == 9 and minute > 0)) else "正常" record = (current_time, emp_id, emp_name, emp_dept, status) self.attendance_records.append(record) self.record_tree.insert("", tk.END, values=record) self.status_value.config(text=f"已打卡 ({status})") self.status_var.set(f"{emp_name} 打卡成功! 时间: {current_time}") self.record_tree.see(self.record_tree.get_children()[-1]) # 弹窗提示打卡成功 messagebox.showinfo("打卡成功", f"{emp_name} 已成功打卡!\n时间: {current_time}\n状态: {status}") ``` #### 2. 修改 `stop_stream` 方法 ```python def stop_stream(self): """停止视频流""" if self.player: self.player.stop() self.stream_active = False self.connect_button.config(text="启动监控") self.snapshot_button.config(state=tk.DISABLED) self.status_var.set("已停止视频流") # 清空员工信息 self.name_value.config(text="") self.id_value.config(text="") self.dept_value.config(text="") self.status_value.config(text="未识别") self.show_default_avatar() ``` #### 3. 修改 `clock_in` 方法 ```python def clock_in(self): """员工打卡""" emp_id = self.id_value.cget("text") emp_name = self.name_value.cget("text") emp_dept = self.dept_value.cget("text") task = {"type": "clock_in", "emp_id": emp_id, "emp_name": emp_name, "emp_dept": emp_dept} self.gui_queue.put(task) ``` --- ## ✅ 最终效果 - ✅ **所有边框变色相的代码和注释都已删除** - ✅ **仅保留识别图片的显示功能** - ✅ **界面恢复干净简洁,不再有变色逻辑干扰** --- ## ✅ 总结 | 操作 | 说明 | |------|------| | 删除注释代码 | `# self.style.configure(...)` 等 | | 删除恢复默认边框的代码 | `stop_stream` 中的恢复逻辑 | | 删除打卡后变色逻辑 | `clock_in_task` 中的变色逻辑 | | 保留功能 | 员工信息更新、图片显示、打卡记录插入等核心功能 | --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值