在VB中“遥控”鼠标

2016-02-19 14:54 9 1 收藏

想要天天向上,就要懂得享受学习。图老师为大家推荐在VB中“遥控”鼠标,精彩的内容需要你们用心的阅读。还在等什么快点来看看吧!

【 tulaoshi.com - 编程语言 】

  尽管Windows的API函数在当今Visual成风的时代正渐渐被人们忘却,但是正如当年开发高技巧的DOS软件离不开汇编语言和DOS系统功能调用一样,无论开发平台高级到什么地步,只要Windows还在最底层运作,就要用到API函数。无论VB的开发手段多么高明,功能多么强大,但是在现实应用中,总有一些功能的实现是VB无能为力的。微软也早意识到这一点,在VB的诸多版本中始终为API留有一席之地。根据笔者多年的VB开发经验,每当我们为了实现一个功能在VB浩瀚的对象、属性、方法、函数中苦苦搜索最终无功而返时,如果换一个角度,到API函数库中去探寻,往往能得到一个惊喜。 Windows API

  API函数是应用程序接口函数的缩写。Windows在API函数库中,为用户开发基于Windows的应用程序提供了所需的各种基本功能。API函数库的几百个函数分布在Windows系统的三个动态链接库中。这三个库在Windows3.x中名为KERNEL、USER和GDI,在Windows 95中名为KERNEL32、USER32和GDI32。这些API函数的功能和接口在Windows的编程手册中有系统详尽的说明,也可以从Visual C++ for Windows或Borland C++ for Windows的联机帮助手册中查到。  

  在VB中引用API函数,就像混合语言编程一样,要声明所引用的函数调用接口以及函数所在的动态链接库。声明一个API函数的语法为:

  Declare Function 函数名

  Lib 库名  ([参数表])

  As 返回类型

  如果一个API函数返回值为空(void),可以把它声明为过程:

  Declare Sub 过程名

  Lib 库名  ([参数表])

  此外,相当一部分API函数的调用参数中用到了Windows系统定义的结构数据类型,这些类型在VB中也要用Type语句定义。 

  好在VB在提供访问API函数功能的同时,也给用户提供了一个友好的工具,可以省去我们声明API函数、定义结构数据类型的绝大部分工作。这个工具在VB5.0中叫API Text Viewer。在该工具中,载入Win32api.txt后,就可以在Declares类中搜索API函数声明,在Types类中搜索结构数据类型的定义,或在Costants类中搜索API函数中用到的常量定义。把搜索到的声明、定义直接通过剪贴板复制 B程序中比较省力省心。 

  把需要用到的函数声明和相关的数据结构定义以及常数定义加到窗体(Form)的General部分,就可以在程序中像调用普通VB函数一样方便地调用API函数。

应用实例

  以下从实用的角度出发,援引笔者在实际工作开发中的API应用一例,谨供参考。

  漫游过Windows 3.2的五分钟教程的用户,大概还记得演示鼠标用法。鼠标指针自动随教程的指令移动,自动点开菜单、按动按钮,完全脱离了对物理鼠标器的依赖。这种高级控制技巧在VB的函数和方法中是找不到的,仍然要借助于API函数。  

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  本例用API函数实现对鼠标的遥控:无论鼠标指针在何处,一个菜单命令Alt-C就能使鼠标指针自动平滑移动到窗口中一个按钮的中心,然后自动按动按钮,激活按钮的Click事件处理过程。掌握了本例的方法后,前面提到的五分钟教程软件就不难制作了。

  本例中,以下几个功能的实现至关重要:获取鼠标光标在屏幕上的位置、获取按钮在屏幕上(注意:不是在窗口中)的位置、移动鼠标光标、自动按下和放开按钮,下面分别介绍。  

  获取鼠标光标在屏幕上的位置和移动鼠标光标,分别需调用API函数GetCursorPos和SetCursorPos。这两个函数的接口声明如下:

  Declare Function GetCursorPos Lib user32  (lpPoint As POINTAPI) As Long Declare Function SetCursorPos Lib user32  (ByVal X As Long, ByVal Y As Long) As Long

  在SetCursorPos函数中,参数X和Y指定了鼠标光标在屏幕上的坐标。GetCursorPos函数把鼠标光标的当前位置存到结构变量lpPoint中。结构变量的定义如下:

  Private Type POINTAPI

  X As Long

  Y As Long

  End Type

  按钮的Left和Top属性给出的是按钮的左上角在窗口客户区坐标系中的坐标位置。要把鼠标光标移到按钮正中,需要得到按钮中心在屏幕坐标系中的坐标位置。窗口客户区坐标系与屏幕坐标系不仅坐标原点不同,二者的坐标单位(scale)也不同。窗口客户区坐标系的单位是Twip,屏幕坐标系单位是Pixel,二者的关系可以从屏幕对象Screen的TwipsPerPixelX和TwipsPerPixelY属性获取。这两个属性分别代表了水平和垂直两个方向上的单位转换比例。  

  把按钮中心在窗口客户区中的坐标单位转换为屏幕坐标系的单位后,还要通过一个API函数进行坐标平移变换,最终取得按钮中心在屏幕坐标系中的坐标位置。这个API函数的接口声明如下:

  Declare Function ClientToScreen Lib user32  (ByVal hwnd As Long, lpPoint As POINTAPI) As Long

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  最后一步是自动按下和放开按钮,这是通过模拟鼠标左键的按下和放开来实现的。该功能需调用API函数SendMessage向按钮发一对鼠标左键按下和放开的消息,函数接口声明如下:

  Declare Function SendMessage Lib user32  Alias SendMessageA  (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

  SendMessage函数的hwnd参数为接收消息的窗口或控件的hwnd句柄。wMsg参数指定具体的消息值。在本例中,要发送鼠标左键按下和释放的消息,wMsg的取值分别为WM_LBUTTONDOWN和WM_LBUTTONUP,这两个常量定义如下:

  Const WM_LBUTTONDOWN = &H201

  Const WM_LBUTTONUP = &H202  

  把这两个消息发送给一个按钮,按钮就会像真的被鼠标左键单击了一样。SendMessage函数中的后两个参数在本例中可以不理,简单置0即可。

  还有一点细节需注意。如果连续给按钮发送一对WM_LBUTTONDOWN和WM_LBUTTONUP消息,Windows会来不及进行一些必要的系统操作,这样在视觉上就看不出按钮被按下后又放开的效果,好像按钮没有按动。但按钮的Click事件处理过程被激活执行表明按钮确实被按过。为了达到视觉上的完美效果,我们不妨在WM_LBUTTONDOWN和WM_LBUTTONUP两个消息之间插入一段短短的延时,比如说200毫秒,在这段延时期间,把处理权交给Windows,这样Windows就有时间显示按钮被按下的效果了。插入延时的办法有很多,可以加入一段空循环或利用计时器控件,这里再介绍一个API函数GetTickCount,该函数获取自Windows启动至被调用时所经过的毫秒数。利用这个函数控制延时,不仅精确,而且节省资源。GetTickCount函数的接口声明如下:

  Declare Function GetTickCount Lib kernel32  () As Long  

  下面进行窗体设计。我们在窗体Form1中安插一个按钮Command1。Command1的Click事件处理过程调用VB的Beep产生一声蜂鸣。另外在Form1的主菜单上加上一个ClickButton的菜单命令,热键设为Alt-C,该菜单命令的事件处理过程完成对鼠标光标的遥控。 

  最后给出Form1的完整程序清单:

  

Begin VB.Form Form1BorderStyle = 1 Fixed SingleCaption = Auto-click demonstration ClientHeight = 3195ClientLeft = 150ClientTop = 720ClientWidth = 4680LinkTopic = Form1 MaxButton = 0 FalseScaleHeight = 3195ScaleWidth = 4680StartUpPosition = 3 Windows DefaultBegin VB.CommandButton Command1Caption = Click me! Height = 495Left = 1740TabIndex = 0Top = 1380Width = 1215EndBegin VB.Menu mnuClickButtonCaption = &ClickButton EndEndAttribute VB_Name = Form1 Attribute VB_GlobalNameSpace = FalseAttribute VB_Creatable = FalseAttribute VB_PredeclaredId = TrueAttribute VB_Exposed = FalsePrivate Type POINTAPIX As LongY As LongEnd TypeConst WM_LBUTTONDOWN = &H201Const WM_LBUTTONUP = &H202Dim ButtonPos As POINTAPIPrivate Declare Function GetCursorPos Lib  user32  (lpPoint As POINTAPI) AsongPrivate Declare Function SetCursorPos Lib user32  (ByVal X As Long,yVal Y As Long) As LongPrivate Declare Function SendMessage Lib  user32  Alias SendMessageA ByValhwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any)s LongPrivate Declare Function ClientToScreen Lib user32  (ByVal hwnd Asong, lpPoint As POINTAPI) As LongPrivate Declare Function GetTickCount Lib  kernel32  () As LongPrivate Sub Command1_Click()BeepEnd SubPrivate Sub Form_Load()Dim tmp As LongWith Command1ButtonPos.X = (.Left + .Width / 2) / Screen.TwipsPerPixelXButtonPos.Y = (.Top + .Height / 2) / Screen.TwipsPerPixelYEnd Withtmp = ClientToScreen(Me.hwnd, ButtonPos)End SubPrivate Sub mnuClickButton_Click()Const MoveStep As Integer = 50Dim CursorPos As POINTAPIDim DistX As Double, DistY As DoubleDim tmp As LongDim i As IntegerDim PosX As Integer, PosY As IntegerDim TickCount As Longtmp = GetCursorPos(CursorPos)DistX = ButtonPos.X - CursorPos.XDistY = ButtonPos.Y - CursorPos.YFor i = 1 To MoveStepPosX = CursorPos.X+DistX*i / MoveStepPosY = CursorPos.Y+DistY*i / MoveSteptmp = SetCursorPos(PosX, PosY)Next itmp = SendMessage(Command1.hwnd,M_LBUTTONDOWN, 0, 0)TickCount = GetTickCount()While GetTickCount() - TickCount < 200mp = DoEvents()Wendtmp = SendMessage(Command1.hwnd,WM_LBUTTONUP, 0, 0)End Sub  

  笔者所用的操作系统为Windows 95,开发环境为VB企业版5.0。以上两例已调试运行成功,所介绍的方法同样适用于Windows 3.x下的VB 3.0和VB 4.0。

结语

  API函数在Windows程序开发中的地位就相当于DOS的INT 21H系统功能调用,无论高级语言、可视平台,最终都要归结于对这些底层功能的调用。我们开发高级的应用软件不能纯粹依赖这些底层调用(当然不是技术上实现不了,而是工作量吃不消),但也不能彻底撇开,就像盖楼时既要充分利用大量的预制件,也要用最基本的泥砂砖石一样。

来源:https://www.tulaoshi.com/n/20160219/1608287.html

延伸阅读
使用VisualBasic编写应用程序的开发人员一定都遇到过这样的情形:当你的应用程序要完成一个比较大的任务时,并且该任务是那种“独占式”的任务(比如:使用函数FileCopy复制一个超过50MB的文件),如果不对程序作出特殊的处理,则用户将被迫面对一个像是被“挂起”的窗体,任凭你用鼠标怎样点击也没有任何反应,更糟糕的是当你从屏幕保护程序切...
在Visual Basic(以下简称VB)程序设计过程中,如何轻松地处理众多的随机事件,往往是制作大型系统首先要考虑的问题之一。例如,多个窗口同时打开同一个表(Table),一个窗口中对数据进行了修改,而其它窗口也能够随之进行数据更新,这时就需要有一条说明数据改变了的消息在所有窗口间进行广播。在C中,只需要定义一条用户消息即可实现这一...
BASModule模块 把以下代码回到BASModule模块: OptionExplicit PrivateConstIP_SUCCESSAsLong=0 PrivateConstIP_STATUS_BASEAsLong=11000 PrivateConstIP_BUF_TOO_SMALLAsLong=(11000 1) PrivateConstIP_DEST_NET_UNREACHABLEAsLong=(11000 2) PrivateConstIP_DEST_HOST_UNREACHABLEAsLong=(11000 3) PrivateConstIP...
标签: 电脑入门
1. 巧分窗口 如果仔细观察可能会发现,在Excel垂直滚动条上方与带黑三角形按钮相邻的地方,有一个折叠起来的按钮,双击(以下双击均指双击鼠标左键)它,即可将当前窗口上下一分为二;双击水平滚动条右方的折叠起来的按钮,可将当前窗左右一分为二。 2. 调整列宽 单元格内的文本或数字在列宽不够时,超出宽度部分不显示或显示为#,这时可将鼠标...
VB作为一种面向对象的Windows应用程序的开发软件,以其功能强大和简单易用的编程手段受到广大编程人员的喜爱。VB中提供了许多用于Windows程序设计的控件和大量的函数,本文就将告诉您怎样利用VB中的函数来实现邮件传输的功能。 首先我们在服务器上按照不同的帐号建立了不同的工作目录,采用NFS协议将多台PC终端连接到服务器。这样,邮件发送...

经验教程

147

收藏

44
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部