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

基于tkinter的30FPS鼠标活动检测程序问题求助

解决方案

先看修改后的完整代码:

from tkinter import *
from datetime import datetime

# 全局状态变量
is_touching = False
counter_id = None  # 保存after任务ID,用于取消重复任务
fps_interval = 1000 // 30  # 30FPS对应的时间间隔,约33ms

root = Tk()
root.geometry("500x500+0+0")
root.title("Mouse Activity")

def log_activity(activity_type):
    """统一日志记录逻辑,避免重复代码"""
    current_time = datetime.now().isoformat(sep=' ', timespec='milliseconds')
    print([[activity_type, current_time]], is_touching)

def idle_counter():
    """无鼠标活动时的定时检测"""
    global counter_id
    if not is_touching:
        log_activity(0)  # 0代表无活动
        counter_id = root.after(fps_interval, idle_counter)

def start_active_detection():
    """按住左键时启动30FPS的活动检测"""
    global is_touching, counter_id
    is_touching = True
    # 取消之前的无活动检测任务,避免重复执行
    if counter_id is not None:
        root.after_cancel(counter_id)
        counter_id = None
    # 立即记录一次,再启动循环检测
    log_activity(1)
    counter_id = root.after(fps_interval, active_loop)

def active_loop():
    """按住左键时的循环检测逻辑"""
    global is_touching, counter_id
    if is_touching:
        log_activity(1)  # 1代表按住/拖动活动
        counter_id = root.after(fps_interval, active_loop)

def stop_active_detection(e):
    """释放左键时停止活动检测,恢复无活动检测"""
    global is_touching, counter_id
    is_touching = False
    log_activity(2)  # 2代表释放按键
    # 重新启动无活动检测
    idle_counter()

canvas = Canvas(root, bd=10, highlightthickness=0, width=500, height=500, bg="#ABFFFA")
canvas.pack()

box1 = canvas.create_rectangle(100,100,400,400,fill='white')

# 绑定事件:按下左键启动活动检测,释放左键停止检测
canvas.tag_bind(box1, '<ButtonPress-1>', lambda e: start_active_detection())
canvas.tag_bind(box1, '<ButtonRelease-1>', stop_active_detection)

# 启动初始的无活动检测
idle_counter()

root.mainloop()

逐个问题解决说明

  1. 按住左键不动停止检测
    原代码依赖<B1-Motion>事件(仅鼠标移动时触发),按住不动不会触发回调。现在绑定<ButtonPress-1>事件,按下左键就启动active_loop定时循环,每隔33ms自动记录一次活动,实现按住不动时的持续检测。

  2. 按住未移动释放后帧率变快
    之前释放按键时会重复启动counter(),导致多个检测任务同时运行。现在通过counter_id保存定时任务的ID,启动新任务前用after_cancel取消旧任务,确保同一时间只有一个检测循环在执行,避免帧率翻倍。

  3. 启动时的线程错误
    手动启动的Thread(target=handler2, args=())完全多余,且handler2需要事件参数e,线程调用时未传入导致报错。tkinter事件回调无需手动用线程触发,直接通过tag_bind绑定即可,删掉这段线程代码即可解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 05:41:19