单独测试 pyautogui 的鼠标点击功能,确保它能够在当前环境中正常工作,鼠标自动点击的录制回放功能

感谢您提供的详细日志信息。根据您的反馈,问题可能出在 `pyautogui` 没有正确获取鼠标焦点或无法在预期的位置执行点击操作。我们将采取以下步骤来进一步诊断和解决这个问题:

1. **确保 `pyautogui` 正确执行点击操作**:
   - 我们将添加更多的调试信息来确认 `pyautogui` 是否真的尝试执行点击操作。
   - 使用 `pyautogui.position()` 来验证当前鼠标位置是否符合预期。

2. **检查权限和环境限制**:
   - 确保脚本有足够的权限来控制鼠标。
   - 检查是否有任何安全软件阻止了自动化操作。

3. **使用绝对坐标进行测试**:
   - 直接使用绝对坐标调用 `pyautogui.click()` 来确认是否可以执行点击操作。

4. **简化回放逻辑**:
   - 创建一个简单的回放函数,只包含基本的鼠标点击操作,以排除其他因素的影响。

### 第一步:确保 `pyautogui` 正确执行点击操作

我们将在 `_async_play_actions` 方法中添加更多调试信息,并使用 `pyautogui.position()` 来验证当前鼠标位置。

### 第二步:检查权限和环境限制

确保脚本有足够的权限来控制鼠标。您可以尝试以管理员身份运行脚本,或者检查系统设置中的安全性选项。

### 第三步:使用绝对坐标进行测试

直接使用绝对坐标调用 `pyautogui.click()` 来确认是否可以执行点击操作。

### 第四步:简化回放逻辑

创建一个简单的回放函数,只包含基本的鼠标点击操作,以排除其他因素的影响。

以下是更新后的代码,包含了上述改进措施:

### 主要修改点

1. **增加调试信息**:
   - 在 `_async_play_actions` 方法中,增加了对当前位置的验证,即在每次鼠标点击后打印当前鼠标的实际位置。
   - 例如,`current_position = pyautogui.position()` 和 `self.status_callback(f"当前位置: ({current_position.x}, {current_position.y})")`。

2. **使用绝对坐标进行点击**:
   - 在 `pyautogui.mouseDown` 和 `pyautogui.mouseUp` 中指定了具体的坐标位置,确保点击操作在正确的坐标上执行。

3. **其他改进**:
   - 添加了一些注释以便更好地理解代码逻辑。
   - 确保所有输入字段都有合理的默认值和提示。

### 运行代码

确保您的虚拟环境已经激活,然后运行脚本:

```sh
python 666.py
```

### 调试步骤

1. **录制和回放**:
   - 使用 `AutomaticClickerApp` 进行录制。
   - 查看状态面板中的输出,确认所有动作都被正确记录。
   - 开始回放,并再次查看状态面板中的输出,确认每个动作都被正确执行。
   - 特别注意每次鼠标点击后的“当前位置”信息,确认它与预期的点击位置一致。

2. **手动测试点击**:
   - 手动在终端或命令行中运行以下命令,确保 `pyautogui` 可以正确执行点击操作:
     ```sh
     python -c "import pyautogui; pyautogui.click(x=100, y=100)"
     ```
   - 观察屏幕上的鼠标点击行为,确认点击操作是否在预期的位置发生。

通过这些步骤,我们应该能够确定问题的具体原因。如果仍然存在问题,请提供更多的详细信息,例如录制的动作列表和回放时的状态面板输出,特别是“当前位置”的信息,以便进一步诊断问题。

import tkinter as tk
from tkinter import ttk, filedialog
import pyautogui
import time
import threading
from pynput import mouse, keyboardclass ActionManager:def __init__(self):self.actions = []def add_action(self, action):current_time = time.time()if self.actions:action["time"] = current_time - self.actions[-1]["timestamp"]else:action["time"] = 0action["timestamp"] = current_timeself.actions.append(action)def clear_actions(self):self.actions.clear()def get_actions(self):return self.actionsdef save_to_file(self, filepath):with open(filepath, 'w') as file:for action in self.actions:file.write(str(action) + '\n')def load_from_file(self, filepath):self.actions.clear()with open(filepath, 'r') as file:for line in file:action = eval(line.strip())self.actions.append(action)class EventListener:def __init__(self, action_manager, update_callback, f6_callback):self.action_manager = action_managerself.recording = Falseself.mouse_listener = Noneself.keyboard_listener = Noneself.update_callback = update_callbackself.f6_callback = f6_callbackdef start_recording(self):self.recording = Trueself.mouse_listener = mouse.Listener(on_click=self.on_mouse_click,on_scroll=self.on_mouse_scroll)self.keyboard_listener = keyboard.Listener(on_press=self.on_key_press)self.mouse_listener.start()self.keyboard_listener.start()def stop_recording(self):self.recording = Falseif self.mouse_listener:self.mouse_listener.stop()if self.keyboard_listener:self.keyboard_listener.stop()def on_mouse_click(self, x, y, button, pressed):if self.recording:action = self.action_manager.add_action({"type": "mouse_click","position": (x, y),"button": str(button).split('.')[1],"pressed": pressed})self.update_callback(action)def on_mouse_scroll(self, x, y, dx, dy):if self.recording:action = self.action_manager.add_action({"type": "mouse_scroll","position": (x, y),"dx": dx,"dy": dy})self.update_callback(action)def on_key_press(self, key):if self.recording:try:if hasattr(key, 'char'):action = self.action_manager.add_action({"type": "key_press", "key": key.char})else:action = self.action_manager.add_action({"type": "key_press", "key": f"{key}"})self.update_callback(action)except AttributeError:passelif key == keyboard.Key.f6:self.f6_callback()class Controller:def __init__(self, action_manager, event_listener, status_callback):self.action_manager = action_managerself.event_listener = event_listenerself.is_running = Falseself.play_thread = Noneself.status_callback = status_callbackdef start_playing(self, repeat_times, interval, delay):if not self.is_running and self.action_manager.get_actions():self.is_running = Trueself.status_callback("开始回放...")self.play_thread = threading.Thread(target=self._async_play_actions, args=(repeat_times, interval, delay))self.play_thread.start()def stop_playing(self):self.is_running = Falseself.status_callback("停止回放")if self.play_thread and self.play_thread is not threading.current_thread() and self.play_thread.is_alive():self.play_thread.join()def _async_play_actions(self, repeat_times, interval, delay):actions = self.action_manager.get_actions()time.sleep(delay / 1000)  # Convert ms to secondswhile self.is_running:start_time = time.time()for i, action in enumerate(actions):if not self.is_running:breaktime.sleep(max(0, action["time"]))if action["type"] == "key_press":pyautogui.press(action["key"])self.status_callback(f"按键: {action['key']} (索引: {i})")elif action["type"] == "mouse_click":if action["pressed"]:pyautogui.mouseDown(button=action["button"], x=action["position"][0], y=action["position"][1])else:pyautogui.mouseUp(button=action["button"], x=action["position"][0], y=action["position"][1])self.status_callback(f"鼠标点击 ({action['position'][0]}, {action['position'][1]}), 按钮: {action['button']}, 状态: {'按下' if action['pressed'] else '释放'} (索引: {i})")# 验证当前位置current_position = pyautogui.position()self.status_callback(f"当前位置: ({current_position.x}, {current_position.y})")elif action["type"] == "mouse_scroll":pyautogui.scroll(action["dy"], *action["position"])self.status_callback(f"鼠标滚轮 ({action['position'][0]}, {action['position'][1]}), 变量: ({action['dx']}, {action['dy']}) (索引: {i})")if repeat_times != 999:repeat_times -= 1if repeat_times <= 0:self.stop_playing()else:time.sleep(interval)class AutomaticClickerApp(tk.Tk):def __init__(self):super().__init__()self.title("增强版自动点击器")self.geometry("1200x800")self.interval = 1.0  # 默认间隔时间1秒self.repeat_times = 1  # 默认重复次数1次self.delay = 0  # 默认延迟为0msself.action_manager = ActionManager()self.event_listener = EventListener(self.action_manager, self.update_action_listbox, self.cycle_clicks)self.controller = Controller(self.action_manager, self.event_listener, self.update_status_panel)self.create_widgets()def create_widgets(self):# 设置主框架main_frame = ttk.Frame(self)main_frame.pack(fill=tk.BOTH, expand=True)# 录制和回放控制区control_frame = ttk.Frame(main_frame)control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10)# 每次鼠标点击的间隔时间interval_frame = ttk.Frame(control_frame)interval_label = ttk.Label(interval_frame, text="每次操作的间隔时间(秒):")self.interval_entry = ttk.Entry(interval_frame, width=5)self.interval_entry.insert(0, str(self.interval))  # 默认值1秒interval_label.grid(row=0, column=0, padx=(10, 0), pady=(10, 0))self.interval_entry.grid(row=0, column=1, padx=(0, 10), pady=(10, 0))interval_frame.pack(padx=10, fill=tk.X)# 重复次数repeat_times_frame = ttk.Frame(control_frame)repeat_times_label = ttk.Label(repeat_times_frame, text="重复次数:")self.repeat_times_entry = ttk.Entry(repeat_times_frame, width=5)self.repeat_times_entry.insert(0, str(self.repeat_times))  # 默认1次repeat_times_label.grid(row=0, column=0, padx=(10, 0), pady=(10, 0))self.repeat_times_entry.grid(row=0, column=1, padx=(0, 10), pady=(10, 0))repeat_times_frame.pack(padx=10, fill=tk.X)# 延迟delay_frame = ttk.Frame(control_frame)delay_label = ttk.Label(delay_frame, text="延迟(ms):")self.delay_entry = ttk.Entry(delay_frame, width=5)self.delay_entry.insert(0, str(self.delay))  # 默认0msdelay_label.grid(row=0, column=0, padx=(10, 0), pady=(10, 0))self.delay_entry.grid(row=0, column=1, padx=(0, 10), pady=(10, 0))delay_frame.pack(padx=10, fill=tk.X)# 录制按钮record_button = ttk.Button(control_frame, text="开始/停止录制", command=self.toggle_recording)record_button.pack(pady=(10, 0))# 清除录制按钮clear_button = ttk.Button(control_frame, text="清除录制", command=self.clear_recorded_actions)clear_button.pack(pady=(10, 0))# 回放按钮play_button = ttk.Button(control_frame, text="开始回放", command=self.start_playing)play_button.pack(pady=(10, 0))# 保存录制的动作到文件save_button = ttk.Button(control_frame, text="保存录制的动作", command=self.save_recorded_actions)save_button.pack(pady=(10, 0))# 加载录制的动作从文件load_button = ttk.Button(control_frame, text="加载录制的动作", command=self.load_recorded_actions)load_button.pack(pady=(10, 0))# 停止按钮self.stop_button = ttk.Button(control_frame, text="停止", command=self.stop_playing, state=tk.DISABLED)self.stop_button.pack(padx=10, pady=(10, 0))# 状态面板status_frame = ttk.Frame(main_frame)status_frame.pack(side=tk.BOTTOM, fill=tk.X, padx=10, pady=10)self.status_text = tk.Text(status_frame, wrap=tk.WORD, height=10, width=100)self.status_text.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)# 记录的动作列表self.action_listbox = tk.Listbox(main_frame, height=30, width=100)self.action_listbox.pack(pady=(10, 0), fill=tk.BOTH, expand=True)def toggle_recording(self):if self.event_listener.recording:self.event_listener.stop_recording()self.update_action_listbox()self.update_status_panel("录制已停止")else:self.event_listener.start_recording()self.update_status_panel("正在录制... 按 F7 结束录制")def update_action_listbox(self, action=None):self.action_listbox.delete(0, tk.END)for action in self.action_manager.get_actions():formatted_action = self.format_action(action)self.action_listbox.insert(tk.END, formatted_action)def format_action(self, action):if action["type"] == "mouse_click":press_state = "按下" if action["pressed"] else "释放"return f"鼠标点击 ({action['position'][0]}, {action['position'][1]}), 按钮: {action['button']}, 状态: {press_state}"elif action["type"] == "mouse_scroll":return f"鼠标滚轮 ({action['position'][0]}, {action['position'][1]}), 变量: ({action['dx']}, {action['dy']})"elif action["type"] == "key_press":return f"按键: {action['key']}"return ""def start_playing(self):try:interval = float(self.interval_entry.get())repeat_times = int(self.repeat_times_entry.get())delay = int(self.delay_entry.get())except ValueError:self.update_status_panel("请输入有效的数值。")returnself.controller.start_playing(repeat_times, interval, delay)self.stop_button["state"] = tk.NORMALdef stop_playing(self):self.controller.stop_playing()self.stop_button["state"] = tk.DISABLEDdef save_recorded_actions(self):file_path = filedialog.asksaveasfilename(defaultextension=".txt",filetypes=[("文本文件", "*.txt"),("所有文件", "*.*")])if file_path:self.action_manager.save_to_file(file_path)self.update_status_panel(f"动作已保存到 {file_path}")def load_recorded_actions(self):file_path = filedialog.askopenfilename(filetypes=[("文本文件", "*.txt"),("所有文件", "*.*")])if file_path:self.action_manager.load_from_file(file_path)self.update_action_listbox()self.update_status_panel(f"动作已从 {file_path} 加载")def cycle_clicks(self):if self.action_manager.get_actions():self.controller.start_playing(999, 0, 0)  # 循环点击,无间隔,无延迟self.update_status_panel("循环点击启动")def clear_recorded_actions(self):self.action_manager.clear_actions()self.update_action_listbox()self.update_status_panel("录制已清除")def update_status_panel(self, message):current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())self.status_text.insert(tk.END, f"[{current_time}] {message}\n")self.status_text.see(tk.END)if __name__ == "__main__":app = AutomaticClickerApp()app.mainloop()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/63779.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

保姆级教学 uniapp绘制二维码海报并保存至相册,真机正常展示图片二维码

一、获取二维码 uni.request({url: https://api.weixin.qq.com/wxa/getwxacode?access_token${getStorage("token")},responseType: "arraybuffer",method: "POST",data: {path: "/pages/index/index"},success(res) {// 转换为 Uint…

coco数据集转换SAM2格式

coco是一个大json汇总了所有train的标签 SAM2训练一张图对应一个json标签 import json import os from pycocotools import mask as mask_utils import numpy as np import cv2def poly2mask(points, width, height):points_array np.array(points, dtypenp.int32).reshape(-…

Vue.createApp的对象参数

目录 template 属性 data 属性 methods 属性 疑问 function 函数的两种写法 methods 属性中 this 的指向 总结 Vue 实例是通过 Vue.createApp() 创建的&#xff0c;该函数需要接收一个对象作为参数&#xff0c;该对象可添加 template、data、methods 等属性。 template …

LLM大语言模型私有化部署-OpenEuler22.03SP3上容器化部署Ollama与OpenWebUI

背景 你是不是也有私有化部署大模型的需求&#xff1f;如今有了 Ollama &#xff0c; HuggingFace &#xff0c; ModelScope 等开源平台&#xff0c;我们可以非常方便地搭建一个属于自己的大模型&#xff0c;如果网速给力&#xff0c;真是分分钟~~。简单起见&#xff0c;这篇文…

使用字典进行动态编程

在你的程序中&#xff0c;你想要执行各种计算&#xff0c;例如计算卫星的总数。 此外&#xff0c;当你进行更高级的编程时&#xff0c;你可能会发现你需要从文件或数据库中加载此类信息&#xff0c;而不是直接编码到 Python 中。 为了帮助支持这些场景&#xff0c;Python 使你…

Linux——rootfs根文件系统构建

根文件系统也叫做rootfs FATFS这类的文件系统属于Linux内核的一部分&#xff0c;属于软件代码&#xff0c;所以ROOTFS不等于FATFS。 Linux的根文件系统实际上是一个文件夹或者叫目录&#xff0c;这个目录下会有许多子目录&#xff0c;这些目录中存放许多Linux运行所必须的文件…

go语言的成神之路-标准库篇-os标准库

一、权限 在操作系统&#xff08;OS&#xff09;中&#xff0c;标准库的权限管理是非常重要的&#xff0c;它确保了不同用户和进程能够安全地访问系统资源。以下是一些常见的权限概念和说明&#xff1a; 1.用户权限 用户ID&#xff08;UID&#xff09;&#xff1a;每个用户在…

linux 生成 nginx 的https ssl 证书详解

证书生成 1. 生成证书 会提示输入密码&#xff0c;输入两次相同密码即可。 openssl genrsa -des3 -out server.key 20482. 去除密码校验 如果想去除此输密码的步骤&#xff0c;可以执行如下命令&#xff0c;根据使用需求选择。 openssl rsa -in server.key -out server.ke…

LabVIEW实现MQTT通信

目录 1、MQTT通信原理 2、硬件环境部署 3、云端环境部署 4、程序架构 5、前面板设计 6、程序框图设计 7、测试验证 本专栏以LabVIEW为开发平台,讲解物联网通信组网原理与开发方法,覆盖RS232、TCP、MQTT、蓝牙、Wi-Fi、NB-IoT等协议。 结合实际案例,展示如何利用LabVIEW和常用…

【OpenCV】直方图

理论 可以将直方图视为图形或曲线图&#xff0c;从而使您对图像的强度分布有一个整体的了解。它是在X轴上具有像素值(不总是从0到255的范围)&#xff0c;在Y轴上具有图像中相应像素数的图。 这只是理解图像的另一种方式。通过查看图像的直方图&#xff0c;您可以直观地了解该…

【PlantUML系列】用例图(三)

目录 一、组成部分 二、典型案例 一、组成部分 参与者&#xff08;Actors&#xff09;&#xff1a;使用关键字 actor 后跟参与者的名称。用例&#xff08;Use Cases&#xff09;&#xff1a;使用关键字 usecase 后跟用例的名称和编号&#xff08;可选&#xff09;。系统边界…

Transformer部分知识点解释

传统Transformer 经典QKV算法 Transformer架构的优势与问题 万能模型&#xff0c;直接套用&#xff0c;代码实现简单&#xff0c;现成例子一大片并行的&#xff0c;比LSTM快&#xff0c;全局信息丰富&#xff0c;注意力机制效果好长序列中attention需要每一个点跟其他点计算(…

docker-compose 之 禅道(zentao) 社区版

docker-compose 关于 zentao 的配置片段如下所示&#xff1a; 镜像使用的官方镜像&#xff1a;https://hub.docker.com/r/easysoft/zentao zentao: image: easysoft/zentao:21.2container_name: zentaoports: - "8088:80"- "23306:3306"environment:TZ: A…

聚类及Python下实现 K-means 算法

聚类 聚类是无监督学习中的一种重要方法&#xff0c;旨在将数据集中相似的数据对象划分到同一个簇中&#xff0c;使得不同簇之间的数据对象差异尽可能大。在大数据环境下&#xff0c;聚类可以帮助挖掘数据中的隐藏结构和模式&#xff0c;应用场景十分广泛&#xff0c;比如在客…

LabVIEW调用Thorlabs的动态库进行开发

Thorlabs 产品在科研与生产领域中的应用广泛&#xff0c;当需要基于LabVIEW 进行二次开发时&#xff0c;可按照以下方法操作&#xff0c;以充分发挥设备性能并满足特定的项目需求。 创建 Kinesis LabVIEW 项目文件和文件夹 更详细的说明参见附件 在 LabVIEW 的启动界面中选择…

SQL中的通配符:使用LIKE操作符进行模式匹配

在SQL中&#xff0c;LIKE 操作符用于在查询中进行模式匹配。它常用于 WHERE 子句中&#xff0c;以便根据特定模式查找数据。与直接进行精确匹配的 操作符不同&#xff0c;LIKE 允许你使用通配符来对数据进行模糊查询&#xff0c;从而使查询更加灵活和强大。 常见的SQL通配符 …

三、Zookeeper

Zookeeper 三、Zookeeper3.1什么是zookeeper?3.2为什么需要zookeeper3.3Zookeeper基本运行流程3.4Zookeeper数据模型3.5Zookeeper主要角色3.6Zookeeper工作原理3.7Zookeeper节点数据操作流程三、Zookeeper 3.1什么是zookeeper? ZooKeeper是一个分布式的,开放源码的分布式应…

实现盘盈单自动化处理:吉客云与金蝶云星空数据对接

盘盈单103v2对接其他入库&#xff1a;吉客云数据集成到金蝶云星空 在企业信息化管理中&#xff0c;数据的高效流转和准确性至关重要。本文将分享一个实际案例&#xff0c;展示如何通过轻易云数据集成平台&#xff0c;将吉客云的数据无缝对接到金蝶云星空&#xff0c;实现盘盈单…

vue:构造结构,塞入数据:结构不变,数据改变

1. 引入vue 2. 创建页面容器&#xff0c;让vue去管理这个容器 3. 双向绑定 4. 单向绑定 5. 操作容器&#xff08;数据模型&#xff09;里的数据 5. 单向绑定的简写 6. v-if和v-else 6. v-if和v-show的区别&#xff1a; v-if要重新渲染界面&#xff0c;v-show只需要改一下元素属…

【qt环境配置】windows下的qt与vs工具集安装\版本对应关系

vs工具集安装通过vs的在线安装器勾选工具集即可 工具包下载路径&#xff1a;https://www.microsoft.com/zh-cn/download/details.aspx?id40784 配置工具集在qt中可以自动扫描到 《正确在 Windows 上配置 MSVC(2019) 作为 Qt 编译器》https://b3logfile.com/pdf/article/15922…