使用很简单看图说话

源代码

import tkinter as tk
from tkinter import messagebox, ttk
import pyautogui
import time
import threading
from datetime import datetime, timedelta
from pynput import keyboard
 
class MouseAutoClicker:
    def __init__(self, root):
        self.root = root
        self.root.title("鼠标自动点击器")
        self.root.geometry("650x450")  # 增加窗口高度
        self.root.resizable(False, False)
         
        # 确保中文显示正常
        self.style = ttk.Style()
        self.style.configure("TLabel", font=("SimHei", 10))
        self.style.configure("TButton", font=("SimHei", 10))
        self.style.configure("TCheckbutton", font=("SimHei", 10))
         
        # 设置变量
        self.hour_var = tk.StringVar(value="15")
        self.minute_var = tk.StringVar(value="40")
        self.second_var = tk.StringVar(value="59")
        self.millisecond_var = tk.StringVar(value="300")
         
        self.x_pos = tk.StringVar(value="0")
        self.y_pos = tk.StringVar(value="0")
         
        self.click_type = tk.StringVar(value="左键")
        self.click_count = tk.StringVar(value="1")
        self.click_interval = tk.StringVar(value="0.1")  # 新增:点击间隔(秒)
         
        self.is_running = False
        self.click_thread = None
        self.position_set = False
         
        # 创建键盘监听器
        self.key_listener = keyboard.Listener(on_press=self.on_key_press)
        self.key_listener.start()
         
        # 创建界面
        self.create_widgets()
     
    def create_widgets(self):
        # 时间设置框架
        time_frame = ttk.LabelFrame(self.root, text="设置点击时间")
        time_frame.pack(fill="x", padx=15, pady=10)
         
        ttk.Label(time_frame, text="小时:").grid(row=0, column=0, padx=5, pady=5)
        self.hour_combo = ttk.Combobox(time_frame, textvariable=self.hour_var, width=5)
        self.hour_combo['values'] = tuple(f"{i:02d}" for i in range(24))
        self.hour_combo.grid(row=0, column=1, padx=5, pady=5)
        self.hour_combo.bind('<FocusOut>', self.validate_time_input)
         
        ttk.Label(time_frame, text="分钟:").grid(row=0, column=2, padx=5, pady=5)
        self.minute_combo = ttk.Combobox(time_frame, textvariable=self.minute_var, width=5)
        self.minute_combo['values'] = tuple(f"{i:02d}" for i in range(60))
        self.minute_combo.grid(row=0, column=3, padx=5, pady=5)
        self.minute_combo.bind('<FocusOut>', self.validate_time_input)
         
        ttk.Label(time_frame, text="秒:").grid(row=0, column=4, padx=5, pady=5)
        self.second_combo = ttk.Combobox(time_frame, textvariable=self.second_var, width=5)
        self.second_combo['values'] = tuple(f"{i:02d}" for i in range(60))
        self.second_combo.grid(row=0, column=5, padx=5, pady=5)
        self.second_combo.bind('<FocusOut>', self.validate_time_input)
         
        ttk.Label(time_frame, text="毫秒:").grid(row=0, column=6, padx=5, pady=5)
        self.millisecond_combo = ttk.Combobox(time_frame, textvariable=self.millisecond_var, width=5)
        self.millisecond_combo['values'] = tuple(f"{i:03d}" for i in range(0, 1000, 50))
        self.millisecond_combo.grid(row=0, column=7, padx=5, pady=5)
        self.millisecond_combo.bind('<FocusOut>', self.validate_time_input)
         
        # 位置设置框架
        position_frame = ttk.LabelFrame(self.root, text="设置点击位置")
        position_frame.pack(fill="x", padx=15, pady=10)
         
        ttk.Label(position_frame, text="X坐标:").grid(row=0, column=0, padx=5, pady=5)
        x_entry = ttk.Entry(position_frame, textvariable=self.x_pos, width=10)
        x_entry.grid(row=0, column=1, padx=5, pady=5)
        x_entry.bind('<FocusOut>', self.validate_position_input)
         
        ttk.Label(position_frame, text="Y坐标:").grid(row=0, column=2, padx=5, pady=5)
        y_entry = ttk.Entry(position_frame, textvariable=self.y_pos, width=10)
        y_entry.grid(row=0, column=3, padx=5, pady=5)
        y_entry.bind('<FocusOut>', self.validate_position_input)
         
        ttk.Label(position_frame, text="按F8记录当前鼠标位置").grid(row=0, column=4, padx=5, pady=5)
         
        # 点击设置框架
        click_frame = ttk.LabelFrame(self.root, text="点击设置")
        click_frame.pack(fill="x", padx=15, pady=10)
         
        ttk.Label(click_frame, text="点击类型:").grid(row=0, column=0, padx=5, pady=5)
        click_type_combo = ttk.Combobox(click_frame, textvariable=self.click_type, width=8, state="readonly")
        click_type_combo['values'] = ("左键", "右键", "中键")
        click_type_combo.grid(row=0, column=1, padx=5, pady=5)
         
        ttk.Label(click_frame, text="点击次数:").grid(row=0, column=2, padx=5, pady=5)
        click_count_combo = ttk.Combobox(click_frame, textvariable=self.click_count, width=5)
        click_count_combo['values'] = tuple(range(1, 11))
        click_count_combo.grid(row=0, column=3, padx=5, pady=5)
        click_count_combo.bind('<FocusOut>', self.validate_click_count)
         
        # 新增:点击间隔设置
        ttk.Label(click_frame, text="点击间隔(秒):").grid(row=1, column=0, padx=5, pady=5)
        interval_entry = ttk.Entry(click_frame, textvariable=self.click_interval, width=10)
        interval_entry.grid(row=1, column=1, padx=5, pady=5)
        interval_entry.bind('<FocusOut>', self.validate_interval)
         
        # 状态显示
        self.status_var = tk.StringVar(value="就绪")
        ttk.Label(self.root, textvariable=self.status_var).pack(pady=10)
         
        # 按钮框架
        button_frame = ttk.Frame(self.root)
        button_frame.pack(pady=20)
         
        self.start_button = ttk.Button(button_frame, text="开始", command=self.start_clicking, width=15)
        self.start_button.pack(side="left", padx=10)
         
        self.stop_button = ttk.Button(button_frame, text="停止", command=self.stop_clicking, width=15, state="disabled")
        self.stop_button.pack(side="left", padx=10)
         
        # 底部信息
        ttk.Label(self.root, text="提示: 程序运行时请不要移动鼠标").pack(side="bottom", pady=10)
     
    def on_key_press(self, key):
        """处理键盘按下事件"""
        try:
            if key == keyboard.Key.f8:
                self.root.after(0, self.get_mouse_position)
        except AttributeError:
            pass
     
    def get_mouse_position(self):
        """获取当前鼠标位置"""
        x, y = pyautogui.position()
        self.x_pos.set(str(x))
        self.y_pos.set(str(y))
        self.position_set = True
        self.status_var.set(f"已记录鼠标位置: ({x}, {y})")
     
    def validate_time_input(self, event):
        """验证并格式化时间输入"""
        widget = event.widget
         
        if widget == self.hour_combo:
            value = self.hour_var.get()
            try:
                num = int(value)
                if 0 <= num <= 23:
                    self.hour_var.set(f"{num:02d}")
                else:
                    self.hour_var.set("00")
                    messagebox.showerror("输入错误", "小时数必须在0-23之间")
            except ValueError:
                self.hour_var.set("00")
                messagebox.showerror("输入错误", "小时数必须是数字")
         
        elif widget == self.minute_combo:
            value = self.minute_var.get()
            try:
                num = int(value)
                if 0 <= num <= 59:
                    self.minute_var.set(f"{num:02d}")
                else:
                    self.minute_var.set("00")
                    messagebox.showerror("输入错误", "分钟数必须在0-59之间")
            except ValueError:
                self.minute_var.set("00")
                messagebox.showerror("输入错误", "分钟数必须是数字")
         
        elif widget == self.second_combo:
            value = self.second_var.get()
            try:
                num = int(value)
                if 0 <= num <= 59:
                    self.second_var.set(f"{num:02d}")
                else:
                    self.second_var.set("00")
                    messagebox.showerror("输入错误", "秒数必须在0-59之间")
            except ValueError:
                self.second_var.set("00")
                messagebox.showerror("输入错误", "秒数必须是数字")
         
        elif widget == self.millisecond_combo:
            value = self.millisecond_var.get()
            try:
                num = int(value)
                if 0 <= num <= 999:
                    self.millisecond_var.set(f"{num:03d}")
                else:
                    self.millisecond_var.set("000")
                    messagebox.showerror("输入错误", "毫秒数必须在0-999之间")
            except ValueError:
                self.millisecond_var.set("000")
                messagebox.showerror("输入错误", "毫秒数必须是数字")
     
    def validate_position_input(self, event):
        """验证并格式化坐标输入"""
        widget = event.widget
        var = self.x_pos if widget == event.widget.master.children['!entry'] else self.y_pos
         
        value = var.get()
        try:
            num = int(value)
            if num < 0:
                var.set("0")
                messagebox.showerror("输入错误", "坐标值不能为负数")
        except ValueError:
            var.set("0")
            messagebox.showerror("输入错误", "坐标值必须是数字")
     
    def validate_click_count(self, event):
        """验证点击次数输入"""
        value = self.click_count.get()
        try:
            num = int(value)
            if 1 <= num <= 10:
                self.click_count.set(str(num))
            else:
                self.click_count.set("1")
                messagebox.showerror("输入错误", "点击次数必须在1-10之间")
        except ValueError:
            self.click_count.set("1")
            messagebox.showerror("输入错误", "点击次数必须是数字")
     
    def validate_interval(self, event):
        """验证点击间隔输入"""
        value = self.click_interval.get()
        try:
            num = float(value)
            if num <= 0:
                self.click_interval.set("0.1")
                messagebox.showerror("输入错误", "点击间隔必须大于0")
            elif num > 10:
                self.click_interval.set("10.0")
                messagebox.showerror("输入错误", "点击间隔不宜超过10秒")
        except ValueError:
            self.click_interval.set("0.1")
            messagebox.showerror("输入错误", "点击间隔必须是数字")
     
    def calculate_time_difference(self):
        """计算当前时间与目标时间的差值"""
        try:
            hour = int(self.hour_var.get())
            minute = int(self.minute_var.get())
            second = int(self.second_var.get())
            millisecond = int(self.millisecond_var.get())
             
            # 获取今天的日期
            now = datetime.now()
            target_time = now.replace(
                hour=hour,
                minute=minute,
                second=second,
                microsecond=millisecond * 1000
            )
             
            # 如果目标时间已经过去,则设置为明天
            if target_time <= now:
                target_time += timedelta(days=1)
             
            # 计算时间差(秒)
            time_diff = (target_time - now).total_seconds()
            return time_diff
        except Exception as e:
            messagebox.showerror("错误", f"时间计算出错: {str(e)}")
            return -1
     
    def start_clicking(self):
        """开始点击任务"""
        # 检查是否已设置位置
        if not self.position_set:
            messagebox.showwarning("警告", "请先设置点击位置")
            return
         
        # 计算时间差
        time_diff = self.calculate_time_difference()
        if time_diff < 0:
            return
         
        # 更新状态
        self.is_running = True
        self.start_button.config(state="disabled")
        self.stop_button.config(state="normal")
         
        # 计算倒计时显示
        hours, remainder = divmod(int(time_diff), 3600)
        minutes, seconds = divmod(remainder, 60)
        milliseconds = int((time_diff - int(time_diff)) * 1000)
        countdown_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}.{milliseconds:03d}"
        self.status_var.set(f"倒计时: {countdown_str}")
         
        # 创建并启动线程
        self.click_thread = threading.Thread(target=self.perform_clicking, args=(time_diff,))
        self.click_thread.daemon = True
        self.click_thread.start()
     
    def perform_clicking(self, time_diff):
        """执行点击任务的线程函数"""
        start_time = time.time()
        target_time = start_time + time_diff
         
        # 倒计时循环
        while self.is_running and time.time() < target_time:
            remaining = target_time - time.time()
            if remaining < 0:
                remaining = 0
                 
            hours, remainder = divmod(int(remaining), 3600)
            minutes, seconds = divmod(remainder, 60)
            milliseconds = int((remaining - int(remaining)) * 1000)
            countdown_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}.{milliseconds:03d}"
             
            # 使用线程安全的方式更新UI
            self.root.after(0, lambda cs=countdown_str: self.status_var.set(f"倒计时: {cs}"))
            time.sleep(0.1)
         
        # 执行点击
        if self.is_running:
            try:
                x = int(self.x_pos.get())
                y = int(self.y_pos.get())
                count = int(self.click_count.get())
                interval = float(self.click_interval.get())
                 
                # 移动到指定位置
                pyautogui.moveTo(x, y)
                 
                # 根据选择的点击类型执行点击
                click_func = {
                    "左键": pyautogui.click,
                    "右键": pyautogui.rightClick,
                    "中键": pyautogui.middleClick
                }.get(self.click_type.get(), pyautogui.click)
                 
                for i in range(count):
                    if not self.is_running:
                        break
                    click_func()
                    if i < count - 1:  # 最后一次点击不需要等待
                        time.sleep(interval)
                        # 更新状态显示点击进度
                        self.root.after(0, lambda i=i+1: self.status_var.set(
                            f"正在执行点击 {i}/{count},间隔 {interval} 秒"))
                 
                self.root.after(0, lambda: self.status_var.set(
                    f"已完成所有点击: 在位置 ({x}, {y}) 执行 {count} 次{self.click_type.get()}点击,间隔 {interval} 秒"))
            except Exception as e:
                self.root.after(0, lambda: messagebox.showerror("错误", f"点击执行出错: {str(e)}"))
         
        # 重置状态但不关闭程序
        self.root.after(0, self.reset_after_complete)
     
    def reset_after_complete(self):
        """任务完成后重置状态"""
        self.is_running = False
        self.start_button.config(state="normal")
        self.stop_button.config(state="disabled")
        self.status_var.set("就绪 - 点击次数和间隔已完成")
     
    def stop_clicking(self):
        """停止点击任务"""
        self.is_running = False
        self.start_button.config(state="normal")
        self.stop_button.config(state="disabled")
        self.status_var.set("已停止")
     
    def on_close(self):
        """关闭应用时的清理工作"""
        self.is_running = False
        self.key_listener.stop()
        self.root.destroy()
 
if __name__ == "__main__":
    root = tk.Tk()
    app = MouseAutoClicker(root)
    root.protocol("WM_DELETE_WINDOW", app.on_close)
    root.mainloop()   

分享了「鼠标定时点击器 Rev1.exe」
链接:https://pan.quark.cn/s/abd00e979160

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐