| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- import tkinter as tk
- from tkinter import ttk, scrolledtext
- import pyautogui
- import pyperclip
- import time
- import threading
- import csv
- import os
- import re
- from datetime import datetime
- class AutoClickerApp:
- def __init__(self, root):
- self.root = root
- self.root.title("自动点击采集工具")
- self.root.geometry("900x700")
-
- # 状态变量
- self.is_running = False
- self.thread = None
- self.stop_event = threading.Event()
-
- # 数据存储
- self.coord_data = [] # 存储CSV数据
- self.last_coords = [] # 存储每次采集到的坐标 (用于去重)
-
- self.setup_ui()
- self.load_csv_data()
-
- def setup_ui(self):
- # 控制按钮框架
- control_frame = tk.Frame(self.root)
- control_frame.pack(pady=10)
-
- self.start_btn = tk.Button(control_frame, text="开始", command=self.start_action,
- bg="green", fg="white", font=("Arial", 12), width=10)
- self.start_btn.pack(side=tk.LEFT, padx=5)
-
- self.stop_btn = tk.Button(control_frame, text="停止", command=self.stop_action,
- bg="red", fg="white", font=("Arial", 12), width=10)
- self.stop_btn.pack(side=tk.LEFT, padx=5)
-
- # 表格框架
- table_frame = tk.Frame(self.root)
- table_frame.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)
-
- # 创建表格
- self.tree = ttk.Treeview(table_frame, columns=('x_range', 'y_range', 'collect_time'), show='headings', height=15)
-
- # 设置列
- self.tree.heading('x_range', text='X坐标范围')
- self.tree.heading('y_range', text='Y坐标范围')
- self.tree.heading('collect_time', text='采集时间')
-
- self.tree.column('x_range', width=150, anchor='center')
- self.tree.column('y_range', width=150, anchor='center')
- self.tree.column('collect_time', width=250, anchor='center')
-
- # 添加滚动条
- scrollbar = ttk.Scrollbar(table_frame, orient=tk.VERTICAL, command=self.tree.yview)
- self.tree.configure(yscrollcommand=scrollbar.set)
-
- self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
- scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
-
- # 日志框架
- log_frame = tk.Frame(self.root)
- log_frame.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)
-
- tk.Label(log_frame, text="日志:", font=("Arial", 10, "bold")).pack(anchor='w')
-
- self.log_text = scrolledtext.ScrolledText(log_frame, height=10, wrap=tk.WORD)
- self.log_text.pack(fill=tk.BOTH, expand=True)
-
- def load_csv_data(self):
- """加载CSV文件数据"""
- csv_file = "coordinates.csv"
-
- if not os.path.exists(csv_file):
- self.log_message(f"未找到 {csv_file} 文件,请创建示例文件")
- self.create_sample_csv()
- return
-
- try:
- with open(csv_file, 'r', encoding='utf-8') as file:
- csv_reader = csv.reader(file)
- self.coord_data = list(csv_reader)
-
- # 清空表格
- for item in self.tree.get_children():
- self.tree.delete(item)
-
- # 填充表格
- for row in self.coord_data:
- if len(row) >= 3:
- self.tree.insert('', 'end', values=(row[0], row[1], row[2]))
-
- self.log_message(f"成功加载 {len(self.coord_data)} 条坐标数据")
-
- except Exception as e:
- self.log_message(f"加载CSV文件失败: {str(e)}")
-
- def create_sample_csv(self):
- """创建示例CSV文件"""
- sample_data = [
- ['62-42', '225-73', ''],
- ['240-300', '100-150', ''],
- ['180-220', '50-90', '']
- ]
-
- try:
- with open('coordinates.csv', 'w', newline='', encoding='utf-8') as file:
- writer = csv.writer(file)
- writer.writerows(sample_data)
- self.log_message("已创建示例CSV文件: coordinates.csv")
- self.load_csv_data()
- except Exception as e:
- self.log_message(f"创建示例CSV文件失败: {str(e)}")
-
- def log_message(self, message):
- """添加日志消息"""
- timestamp = datetime.now().strftime("%H:%M:%S")
- self.log_text.insert(tk.END, f"[{timestamp}] {message}\n")
- self.log_text.see(tk.END)
-
- def update_table_time(self, x, y):
- """根据坐标更新表格中的时间"""
- try:
- x_float = float(x)
- y_float = float(y)
-
- # 从最后一行开始向前匹配(只匹配最新的)
- for i in range(len(self.coord_data) - 1, -1, -1):
- row = self.coord_data[i]
- if len(row) >= 2:
- # 解析X范围
- x_range = row[0].strip()
- if '-' in x_range:
- x_start, x_end = x_range.split('-')
- try:
- x_start = float(x_start.strip())
- x_end = float(x_end.strip())
-
- if x_start <= x_float <= x_end:
- # 解析Y范围
- y_range = row[1].strip()
- if '-' in y_range:
- y_start, y_end = y_range.split('-')
- y_start = float(y_start.strip())
- y_end = float(y_end.strip())
-
- if y_start <= y_float <= y_end:
- # 匹配成功,更新时间
- current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- row[2] = current_time
-
- # 更新表格显示
- children = self.tree.get_children()
- if i < len(children):
- self.tree.delete(children[i])
- self.tree.insert('', i, values=(row[0], row[1], row[2]))
-
- self.log_message(f"坐标 ({x_float}, {y_float}) 匹配成功,时间已更新为 {current_time}")
- return True
- except ValueError:
- continue
-
- self.log_message(f"坐标 ({x_float}, {y_float}) 未匹配到任何范围")
- return False
-
- except ValueError:
- self.log_message(f"坐标格式错误: {x}, {y}")
- return False
-
- def parse_clipboard_content(self, content):
- """解析剪贴板内容,提取坐标"""
- lines = content.strip().split('\n')
- found_coords = None
-
- # 查找"发现真武矿采集物坐标"的行
- for i, line in enumerate(lines):
- if '发现真武矿采集物坐标' in line:
- # 检查前一行是否包含"挖着了"
- if i > 0 and '挖着了' in lines[i-1]:
- # 提取坐标
- match = re.search(r'发现真武矿采集物坐标:([\d.]+),([\d.]+)', line)
- if match:
- x = match.group(1)
- y = match.group(2)
- found_coords = (x, y)
- self.log_message(f"发现有效坐标: {x}, {y}")
- break
-
- if found_coords:
- x, y = found_coords
- # 检查是否与上次采集的坐标相同(去重)
- if (x, y) not in self.last_coords:
- self.last_coords.append((x, y))
- # 只保留最近10条记录
- if len(self.last_coords) > 10:
- self.last_coords.pop(0)
- self.update_table_time(x, y)
- else:
- self.log_message(f"坐标 ({x}, {y}) 已存在,跳过重复更新")
- else:
- self.log_message("未找到有效的采集坐标")
-
- def perform_actions(self):
- """执行主要操作"""
- self.log_message("开始执行操作序列...")
-
- try:
- # 1. 右键点击指定位置
- pyautogui.click(1730, 300, button='right')
- self.log_message("已右键点击 (1730, 300)")
- time.sleep(0.5)
-
- # 2. 按键 A
- pyautogui.press('a')
- self.log_message("已按键 A")
- time.sleep(0.5)
-
- # 3. 按键 Ctrl+C
- pyautogui.hotkey('ctrl', 'c')
- self.log_message("已执行 Ctrl+C")
- time.sleep(0.5)
-
- # 4. 获取剪贴板内容
- clipboard_content = pyperclip.paste()
- if clipboard_content:
- self.log_message("成功获取剪贴板内容")
- self.parse_clipboard_content(clipboard_content)
- else:
- self.log_message("剪贴板内容为空")
-
- except Exception as e:
- self.log_message(f"操作执行失败: {str(e)}")
-
- def worker(self):
- """工作线程函数"""
- self.log_message("程序已启动,每10秒执行一次操作")
-
- while not self.stop_event.is_set():
- if not self.is_running:
- break
-
- self.perform_actions()
-
- # 等待10秒,但每秒检查一次停止信号
- for _ in range(10):
- if self.stop_event.is_set() or not self.is_running:
- break
- time.sleep(1)
-
- self.log_message("操作线程已停止")
-
- def start_action(self):
- """启动按钮回调"""
- if self.is_running:
- self.log_message("程序已在运行中")
- return
-
- # 清空上次的坐标记录
- self.last_coords = []
- self.stop_event.clear()
- self.is_running = True
-
- self.start_btn.config(state=tk.DISABLED)
- self.stop_btn.config(state=tk.NORMAL)
-
- self.thread = threading.Thread(target=self.worker, daemon=True)
- self.thread.start()
-
- def stop_action(self):
- """停止按钮回调"""
- if not self.is_running:
- return
-
- self.log_message("正在停止程序...")
- self.is_running = False
- self.stop_event.set()
-
- self.start_btn.config(state=tk.NORMAL)
- self.stop_btn.config(state=tk.DISABLED)
- def main():
- root = tk.Tk()
- app = AutoClickerApp(root)
- root.mainloop()
- if __name__ == "__main__":
- main()
|