Qt使用API实现鼠标点击操作

news/2024/11/7 18:13:33/

前段时间,工作需要进行数据录入,每次都要点击3次按钮,想让鼠标自行点击,只要下位机接入,就自动点击按钮把数据读出,录入到服务端,并且进行检测,说干就干,没有经验,那只有面向百度编程.

根据查到的资料,可以使用WinAPI进行鼠标模似.可以使用的函数有两个,一个是SendMessageA(),一个是mouse_evnet();进行鼠标操作的模似;

SendMessageA()的参数说明:

LRESULT SendMessageA([in] HWND   hWnd,[in] UINT   Msg,[in] WPARAM wParam,[in] LPARAM lParam
);

hWnd:指定要接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。

Msg:指定被发送的消息。

wParam:指定附加的消息特定信息。

IParam:指定附加的消息特定信息。

返回值:返回值指定消息处理的结果,依赖于所发送的消息。

备注:需要用HWND_BROADCAST通信的应用程序应当使用函数RegisterWindowMessage来为应用程序间的通信取得一个唯一的消息。

如果指定的窗口是由正在调用的线程创建的,则窗口程序立即作为子程序调用。如果指定的窗口是由不同线程创建的,则系统切换到该线程并调用恰当的窗口程序。线程间的消息只有在线程执行消息检索代码时才被处理。发送线程被阻塞直到接收线程处理完消息为止。

mouse_evnet()的参数说明

VOID mouse_event(DWORD     dwFlags,     // motion and click optionsDWORD     dx,          // horizontal position or changeDWORD     dy,          // vertical position or changeDWORD     dwData,      // wheel movementULONG_PTR dwExtraInfo  // application-defined information
);

dwFlags

标志位集,指定点击按钮和鼠标动作的多种情况。此参数可以是下列值的某种组合:

名称

说明

MOUSEEVENTF_ABSOLUTE

dX和dY参数含有规范化的绝对坐标。如果不设置,这些参数含有相对数据:相对于上次位置的改动位置。此标志可设置,也可不设置,不管鼠标的类型或与系统相连的类似于鼠标的设备的类型如何。要得到关于相对鼠标动作的信息,参见下面备注部分。

MOUSEEVENTF_MOVE

这表示鼠标移动

MOUSEEVENTF_LEFTDOWN

这表示鼠标左键按下

MOUSEEVENTF_LEFTUP

这表示鼠标左键松开

MOUSEEVENTF_RIGHTDOWN

这表示鼠标右键按下

MOUSEEVENTF_RIGHTUP

这表示鼠标右键松开

MOUSEEVENTF_MIDDLEDOWN

这表示鼠标中键按下

MOUSEEVENTF_MIDDLEUP

这表示鼠标中键松开

MOUSEEVENTF_WHEEL

这表示鼠标轮被滚动,如果鼠标有一个滚轮。滚动的数量由dwData给出。

dx

指定鼠标沿x轴的绝对位置或者从上次鼠标事件产生以来移动的数量,依赖于MOUSEEVENTF_ABSOLUTE的设置。给出的绝对数据作为鼠标的实际X坐标;给出的相对数据作为移动的mickeys数。一个mickey表示鼠标移动的数量,表明鼠标已经移动。

dy

指定鼠标沿y轴的绝对位置或者从上次鼠标事件产生以来移动的数量,依赖于MOUSEEVENTF_ABSOLUTE的设置。给出的绝对数据作为鼠标的实际y坐标,给出的相对数据作为移动的mickeys数。

dwData

如果dwFlags为MOUSEEVENTF_WHEEL,则dwData指定鼠标轮移动的数量。正值表明鼠标轮向前转动,即远离用户的方向;负值表明鼠标轮向后转动,即朝向用户。一个轮击定义为WHEEL_DELTA,即120。如果dwFlagsS不是MOUSEEVENTF_WHEEL,则dWData应为零。

dwExtralnfo

指定与鼠标事件相关的附加32位值。应用程序调用函数GetMessageExtraInfo来获得此附加信息。

简单的翻译一下上在面的说明就是SendMessageA()可以用来发送任何消息,包括鼠标消息,发送的时候,有返回值,非0就是成功.但是此函数发送鼠标消息的时候不需要控制鼠标.

而mouse_evnet(),则需要控制鼠标移动到目标上操作.

好处是,SendMessageA()是相当于后台操作,属于是静默型,而mouse_evnet()则需要控制鼠标实际移动,也就是你使用了这个,任务没有安成前,你是无法使用鼠标的.

OK,了解了具体的函数之后,开始准备编写代码.经过测试

SendMessageA()需要传入组件的句柄,才可以进行消息传递,(经过测试,使用相对坐标,无法无成消息传递),

使用举例:SendMessageA(hwind,msg,wParam,lParam);

hwind:指的是窗口句柄,也就是窗口的唯一标识号,你要在哪个窗口传递消息,就指定窗口句柄即可.

msg:消息类型,指的是,你要给指定口传递什么消息.

wParam:消息附加说明,此处可以填写0,或者指定说明

lParam:组件句柄(这里貌似只能填写句柄,填写相对坐标是无法成功的个人已经测试验证)

Qt中使用方式:

//使用此函数,必须引入windows.h头文件
#include <windows.h>SendMessageA((HWND)winId(), WM_LBUTTONDOWN, BM_CLICK, 0);
SendMessageA((HWND)winId(), WM_LBUTTONUP, BM_CLICK, 0);
//WM_LBUTTONUP 左键抬起,
//BM_CLICK 按钮消息 点击

最后一个参数,其实是要填写按钮的句柄,如果你要发消的窗口是自绘的,那么此函数就不适用了.

此时可以采用第mouseEvent()具体的使用方法

//第一个参数:鼠标移动事件,也就是把鼠标移动到指定的坐标,第二个参数,和第3个参数是坐标的X和Y,此处需要进行计算点击位置相对于窗口的相对坐标,这里不坐讨论,网上有很多相关的资料,此处演示的是其中的一种,
//窗口左*65535/当前分辨率的X,窗口左*65535/当前分辨率的Y,最后两个参数不设置,填0
mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, getDzzcleft * 65535 / resolution_x, getDzzcTop * 65535 / resolution_y,0 ,0);
//第一个参数,左键按下
mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
//第一个参数,左键抬起mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0);

思路:首先你需要获取组件在窗口上的相对坐标,然后再进行点击,这是因为,组件相对于窗口,这个坐标是恒定不变的,变化的只是窗口本身在桌面的位置,获取窗口在桌面的位置,需要先获取当前显示器的分辨率

这其中还有一个缩放比的问体,就是用户把窗体的大小改变了一点,此时,就需要重新计算了,我为了实现基本功能,把窗体的大小进行了固定,所以就规避了计算缩放比的问题.

EnumDisplaySettings()
获取分辨率的函数

思路:首先你需要获取组件在窗口上的相对坐标,然后再进行点击,这是因为,组件相对于窗口,这个坐标是恒定不变的,变化的只是窗口本身在桌面的位置,获取窗口在桌面的位置,需要先获取当前显示器的分辨率

这其中还有一个缩放比的问体,就是用户把窗体的大小改变了一点,此时,就需要重新计算了,我为了实现基本功能,把窗体的大小进行了固定,所以就规避了计算缩放比的问题.

brEnumDisplaySettings()br获取分辨率的函数

第一步我们需要获取这个目标窗口

使用GetWindowrect();获取窗口矩形,然后显示这个窗口,使用ShowWindow显示的目录是为了激活目标窗体,并且将其置于顶层.

声明一个矩形变量 RECT rec

GetWindowRect(WindowHandle,&rec);
ShowWindow(WindowHandle, SW_NORMAL);

然后通把rec.left + 组件坐标.x 获取鼠标点击位置的x,rec.top + 组件坐标.y 获取鼠标点击位置的y

SetCursorPos(x,y);

将鼠标指针移动到 x,y,再使用mouse_event(),则实现了点击.

此方法使用QT5.9已经测试成功。


http://www.ppmy.cn/news/31235.html

相关文章

Python每日一练(20230309)

目录 1. 删除有序数组中的重复项 ★ 2. 二叉树的最小深度 ★★ 3. 只出现一次的数字 II ★★ &#x1f31f; 每日一练刷题专栏 C/C 每日一练 ​专栏 Python 每日一练 专栏 1. 删除有序数组中的重复项 给你一个有序数组 nums &#xff0c;请你原地删除重复出现的元素…

【冲刺蓝桥杯的最后30天】day6

大家好&#x1f603;&#xff0c;我是想要慢慢变得优秀的向阳&#x1f31e;同学&#x1f468;‍&#x1f4bb;&#xff0c;断更了整整一年&#xff0c;又开始恢复CSDN更新&#xff0c;从今天开始更新备战蓝桥30天系列&#xff0c;一共30天&#xff0c;如果对你有帮助或者正在备…

Linux-0.11 kernel目录进程管理sched.c详解

Linux-0.11 kernel目录进程管理sched.c详解 sched.c主要功能是负责进程的调度&#xff0c;其最核心的函数就是schedule。除schedule以外&#xff0c; sleep_on和wake_up也是相对重要的函数。 schedule void schedule(void)schedule函数的基本功能可以分为两大块&#xff0c;…

回文日期(蓝桥杯真题)小白入!

//明白打表的重要性,哭了 #include<iostream>using namespace std;int date[15]{0,31,29,31,30,31,30,31,31,30,31,30,31}; //为什么要从0&#xff0c;开始&#xff0c;由于我们想使用i(月份)作为所以&#xff0c;月份是从1开始的 //还有一点&#xff0c;不能怪我们&…

@Value注解取不到值的几种错误

在程序中使用了yml文件,然后把有些参数写在里面作为全局变量,在定时器里面使用,但是后来发现取不到: @Value("${spring.datasource.druid.master.url}") private String url; @Value("${spring.datasource.druid.master.driver-class-name}") private …

【Linux】线程概念 | 线程控制

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;知识补充&…

软件测试员如何进行产品测试?

一般来讲&#xff0c;当软件成为一个成功的产品后&#xff0c;产品测试工作就会复杂很多。比如拥有的用户量大&#xff0c;迭代频繁&#xff0c;测试的周期短&#xff0c;重复性强。面对紧张复杂的产品测试工作&#xff0c;软件测试员应怎样完成这一系列的测试工作呢&#xff1…

好的提高代码质量的方法有哪些?有什么经验和技巧?

用于确保代码质量的6个高层策略&#xff1a; 1 编写易于理解的代码 考虑如下这段文本。我们有意地使其变得难以理解&#xff0c;因此&#xff0c;不要浪费太多时间去解读。粗略地读一遍&#xff0c;尽可能吸收其中的内容。 〓ts〓取一个碗&#xff0c;我们现在称之为A。取一…