水题堆1.S Picture

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int n,m,i;
    while(scanf("%d%d",&n,&m)!=EOF){
        char a[80],b[80];
        a[0]='+';
        a[n+1]='+';
        a[n+2]='\0';
        for(i=1;i<=n;i++){
            a[i]='-';
        }
        b[0]='|';
        b[n+1]='|';
        b[n+2]='\0';
        for(i=1;i<=n;i++){
            b[i]=' ';
        }
        puts(a);
        while(m--)puts(b);
        puts(a);
        printf("\n");
    }
    return 0;
}

细心一点就行


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 from threading import Thread, Event 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.idle = Event() # 创建事件对象 self.idle.set() # 初始设置为空闲状态(允许采集) self.capture_thread = None self.cap = None # 设置输出目录 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)) # 员工照片和基本信息 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.open_search_window, 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": "技术部", "position": "高级工程师", "avatar": "avatar1.jpg"}, "1002": {"name": "李华", "dept": "市场部", "position": "市场经理", "avatar": "avatar2.jpg"}, "1003": {"name": "王芳", "dept": "财务部", "position": "会计", "avatar": "avatar3.jpg"}, "1004": {"name": "赵刚", "dept": "人力资源", "position": "招聘主管", "avatar": "avatar4.jpg"}, "1005": {"name": "陈晓", "dept": "产品部", "position": "产品经理", "avatar": "avatar5.jpg"}, } # 考勤记录 self.attendance_records = [] self.add_sample_records() # 初始化线程队列 self.gui_queue = queue.Queue() self.root.after(100, self.process_queue) 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.position_value.config(text=task["position"]) self.status_value.config(text=task["status"]) self.show_employee_avatar(task["avatar"]) self.clock_button.config(state=tk.NORMAL) 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 open_search_window(self): # """打开查找员工记录的弹窗""" search_window = tk.Toplevel(self.root) search_window.title("查找员工考勤记录") search_window.geometry("600x400") search_window.resizable(False, False) # 输入框 input_frame = ttk.Frame(search_window) input_frame.pack(pady=10, padx=10, fill=tk.X) ttk.Label(input_frame, text="姓名或工号:", width=12, anchor=tk.E).pack(side=tk.LEFT) search_entry = ttk.Entry(input_frame, width=30) search_entry.pack(side=tk.LEFT, padx=5) # 查询按钮 search_btn = ttk.Button(input_frame, text="查询", command=lambda: self.perform_search(search_entry, tree)) search_btn.pack(side=tk.LEFT) # 表格 tree_frame = ttk.Frame(search_window) tree_frame.pack(padx=10, pady=5, fill=tk.BOTH, expand=True) tree = ttk.Treeview(tree_frame, columns=("工号", "姓名", "部门","时间", "次数"), show="headings", height=15) tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) # 设置列标 for col in tree["columns"]: tree.heading(col, text=col) tree.column(col, width=100, anchor=tk.CENTER) # 滚动条 scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=tree.yview) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) tree.configure(yscrollcommand=scrollbar.set) # 提示信息 self.search_status_label = ttk.Label(search_window, text="", foreground="red") self.search_status_label.pack(pady=5) # 保存状态 self.current_search_tree = tree def perform_search(self, entry_widget, tree_widget): keyword = entry_widget.get().strip() if not keyword: print("//////////////") self.search_status_label.config(text="请输入姓名或工号") return try: conn = pymysql.connect( host='localhost', user='root', password='139800', database='employeeinfomation' ) print("**************") cursor = conn.cursor() print("**************") query = """ SELECT * FROM workcard WHERE NAME LIKE %s """ cursor.execute(query, (f"%{keyword}%")) results = cursor.fetchall() print(results) # 清空表格 for item in tree_widget.get_children(): tree_widget.delete(item) # 插入查询结果 for record in results: tree_widget.insert("", tk.END, values=record) if not results: self.search_status_label.config(text=f"未找到包含“{keyword}”的记录") else: self.search_status_label.config(text=f"找到 {len(results)} 条记录") conn.close() except Exception as e: self.search_status_label.config(text=f"查询失败:{str(e)}") 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 search_count(self, name): conn = pymysql.connect( host='localhost', user='root', password='139800', database='employeeinfomation' ) # 2. 使用 pandas 直接读取 SQL 查询结果 cursor = conn.cursor() query = "SELECT COUNT FROM workcard WHERE NAME LIKE %s " cursor.execute(query, (f"%{name}%")) count = cursor.fetchall() # 3. 关闭数据库连接 conn.close() return count 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() # 启动采集线程 self.capture_thread = Thread(target=self.capture_loop, daemon=True) self.capture_thread.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}") # # 将识别结果发送到GUI队列 # task = { # "type": "update_employee_info", # "name": emp_name, # "id": emp_id, # "dept": emp_dept, # "position": "未知", # "avatar": os.path.join(OUT_DIR, f"{stem}_face.jpg") # } # self.gui_queue.put(task) # # 添加示例记录 # count = self.search_count(emp_name) # if(count == 1): # self.add_new_records(task) # messagebox.showinfo("打卡成功", f"{emp_name} 已成功打卡!") # else: # messagebox.showinfo("Warnning!", f"{emp_name} 重复打卡!") # # time.sleep(10) # 控制识别频率 # cap.release() def capture_loop(self): # """视频采集主循环,使用事件控制采集频率""" self.cap = cv2.VideoCapture(self.url_entry.get().strip()) if not self.cap.isOpened(): print("[错误] 无法打开视频流") return # 加载预训练的人脸检测模型 face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') while self.stream_active: # 等待空闲状态(允许采集) self.idle.wait() # time.sleep(5) # 读取一帧 ret, frame = self.cap.read() if not ret: print("[调试信息] 无法读取视频帧") time.sleep(0.1) continue # 转为灰度图,提高检测效率 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 检测人脸 faces = face_cascade.detectMultiScale( gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30) ) if len(faces) > 0: print(f"[调试信息] 检测到 {len(faces)} 张人脸") # 立即设置为忙碌状态(禁止进一步采集) self.idle.clear() # 启动处理线程 Thread( target=self.process_frame, args=(frame.copy(),), # 复制帧以避免后续修改 daemon=True ).start() else: # 未检测到人脸时短暂休眠,控制抽帧频率 time.sleep(0.05) def process_frame(self, frame): # """处理检测到人脸的帧""" try: # 保存当前帧 temp_image_path = "temp_frame.jpg" cv2.imwrite(temp_image_path, frame) print(f"[调试信息] 图像已保存至 {temp_image_path}") # 调用main.py进行图像识别 print(f"[调试信息] 正在调用 main.py 处理 {temp_image_path}") subprocess.run(["python", "main.py", temp_image_path], check=True) print("[调试信息] main.py 执行完成") # 读取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") 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}") # 更新GUI img = Image.open(final_picture) self.update_avatar(final_picture) # 将识别结果发送到GUI队列 task = { "type": "update_employee_info", "name": emp_name, "id": emp_id, "dept": emp_dept, "position": "未知", "avatar": final_picture } self.gui_queue.put(task) # 检查打卡记录 count = self.search_count(emp_name) if count == 0: self.add_new_records(task) messagebox.showinfo("打卡成功", f"{emp_name} 已成功打卡!") else: messagebox.showinfo("警告", f"{emp_name} 重复打卡!") else: print(f"[错误] 未找到JSON文件: {final_json}") # 处理失败时也恢复采集 except subprocess.CalledProcessError as e: print(f"[错误] main.py 执行失败: {e}") except Exception as e: print(f"[错误] 处理过程中发生异常: {str(e)}") finally: # 无论处理成功与否,都恢复空闲状态 self.idle.set() def stop(self): # """停止采集和处理""" self.stream_active = False self.idle.set() # 确保线程可以退出 if self.cap and self.cap.isOpened(): self.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.clock_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.position_value.config(text="") self.status_value.config(text="未识别") self.show_default_avatar() 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) 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.clock_button.config(state=tk.DISABLED) self.record_tree.see(self.record_tree.get_children()[-1]) if __name__ == "__main__": root = tk.Tk() app = EmployeeClockSystem(root) root.mainloop() 为什么使用了event还是一直截取同一个时刻的照片,而不是隔一段时间再截图
08-26
1)普通用户端(全平台) 音乐播放核心体验: 个性化首页:基于 “听歌历史 + 收藏偏好” 展示 “推荐歌单(每日 30 首)、新歌速递、相似曲风推荐”,支持按 “场景(通勤 / 学习 / 运动)” 切换推荐维度。 播放页功能:支持 “无损音质切换、倍速播放(0.5x-2.0x)、定时关闭、歌词逐句滚动”,提供 “沉浸式全屏模式”(隐藏冗余控件,突出歌词与专辑封面)。 多端同步:自动同步 “播放进度、收藏列表、歌单” 至所有登录设备(如手机暂停后,电脑端打开可继续播放)。 音乐发现与管理: 智能搜索:支持 “歌曲名 / 歌手 / 歌词片段” 搜索,提供 “模糊匹配(如输入‘晴天’联想‘周杰伦 - 晴天’)、热门搜索词推荐”,结果按 “热度 / 匹配度” 排序。 歌单管理:创建 “公开 / 私有 / 加密” 歌单,支持 “批量添加歌曲、拖拽排序、一键分享到社交平台”,系统自动生成 “歌单封面(基于歌曲风格配色)”。 音乐分类浏览:按 “曲风(流行 / 摇滚 / 古典)、语言(国语 / 英语 / 日语)、年代(80 后经典 / 2023 新歌)” 分层浏览,每个分类页展示 “TOP50 榜单”。 社交互动功能: 动态广场:查看 “关注的用户 / 音乐人发布的动态(如‘分享新歌感受’)、好友正在听的歌曲”,支持 “点赞 / 评论 / 转发”,可直接点击动态中的歌曲播放。 听歌排行:个人页展示 “本周听歌 TOP10、累计听歌时长”,平台定期生成 “全球 / 好友榜”(如 “好友中你本周听歌时长排名第 3”)。 音乐圈:加入 “特定曲风圈子(如‘古典音乐爱好者’)”,参与 “话讨论(如‘你心中最经典的钢琴曲’)、线上歌单共创”。 (2)音乐人端(创作者中心) 作品管理: 音乐上传:支持 “无损音频(FLAC/WAV)+ 歌词文件(LRC)+ 专辑封面” 上传,填写 “歌曲信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值