网上查了半天都没有讲清楚,为什么都喜欢把Form的坐标搞成(0,0),特例是不能当通用方法来用的,随意摆放的位置才有比对学习的价值。系统地学习、测试了一下,弄明白了。

百度百科里说的窗口,实际上适用于Form/控件

目录

一.常规方法能获得的准确值

二.API方法能做到的什么

1.针对Form

2.针对控件

三.常见API应用举例

1.怎样获取任一控件的尺寸,及在其容器对象中的坐标

(1)入门思路

(2)归纳为一条标准化的套路

(3)再精进一步

2.待续...

四.关于API函数MoveWindow()


一.常规方法能获得的准确值

【Form】在屏幕中的位置及尺寸:(100,100,839,390)
【Form】的客户区坐标系:(0,0)-(823,351)
【控件】在客户区坐标系中的位置及尺寸:(80,40,97,46)

二.API方法能做到的什么

1.针对Form

【Form】在屏幕坐标系中的位置及尺寸:(100,100,939,490)
【Form】的客户区坐标系:(0,0,823,351)
将屏幕坐标系中的点p(0,0)转换为【Form】的客户区坐标:(-108,-131)
将【Form】的客户区坐标系中的点p(0,0)转换为屏幕坐标:(108,131)

2.针对控件

【控件】在屏幕坐标系中的位置及尺寸:(188,171,285,217)
【控件】的客户区坐标系:(0,0,97,46)
将屏幕坐标系中的点p(0,0)转换为【控件】客户区坐标:(-188,-171)
将【控件】的客户区坐标系中的点p(0,0)转换为屏幕坐标:(188,171)

相应代码如下:

Option Explicit'获取指定窗口(Form/控件)的位置及尺寸。该尺寸以相对于屏幕坐标左上角的屏幕坐标给出。
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long'获取窗口(Form/控件)客户区的坐标系。客户区坐标指定客户区的左上角和右下角,即(0,0)-(ScaleWidth,ScaleHeight)。
Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long'将屏幕坐标系中的点转换为客户区坐标
Private Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long'将客户区坐标系中的点转换为屏幕坐标
Private Declare Function ClientToScreen Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long'给RECT变量赋值
Private Declare Function SetRect Lib "user32" (lpRect As RECT, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As LongPrivate Type RECTLeft As LongTop As LongRight As LongBottom As Long
End Type
Private Type POINTAPIX As LongY As Long
End TypePrivate Sub Form_Load()Dim rec As RECTDim recWin1 As RECT, recCli1 As RECT, recWin2 As RECT, recCli2 As RECT, p As POINTAPIMe.Move 100 * Screen.TwipsPerPixelX, 100 * Screen.TwipsPerPixelYCommand1.Move 80, 40'常规方法能获得的准确值addLog3 "常规方法能获得的准确值", ""SetRect rec, toX(Me.Left), toY(Me.Top), toX(Me.Width), toY(Me.Height)addLog "【Form】在屏幕中的位置及尺寸", recaddLog3 "【Form】的客户区坐标系", "(0,0)-(" & Me.ScaleWidth & "," & Me.ScaleHeight & ")"SetRect rec, Command1.Left, Command1.Top, Command1.Width, Command1.HeightaddLog "【控件】在客户区坐标系中的位置及尺寸", rec, True'下面是API方法能做到的addLog3 "下面是API方法能做到的", ""'1.针对FormaddLog3 "一.针对Form", ""'获取【Form】在屏幕坐标系中的位置及尺寸GetWindowRect Me.hwnd, recWin1addLog "【Form】在屏幕坐标系中的位置及尺寸", recWin1'获取【Form】的客户区坐标系GetClientRect Me.hwnd, recCli1addLog "【Form】的客户区坐标系", recCli1'将屏幕坐标系中的点p(0,0)转换为客户区坐标p.X = 0: p.Y = 0ScreenToClient Me.hwnd, paddLog2 "将屏幕坐标系中的点p(0,0)转换为【Form】的客户区坐标", p'将客户区坐标系中的点p(0,0)转换为屏幕坐标p.X = 0: p.Y = 0ClientToScreen Me.hwnd, paddLog2 "将【Form】的客户区坐标系中的点p(0,0)转换为屏幕坐标", p, True'2.针对控件addLog3 "二.针对控件", ""'获取【控件】在屏幕坐标系中的位置及尺寸GetWindowRect Command1.hwnd, recWin1addLog "【控件】在屏幕坐标系中的位置及尺寸", recWin1'获取【控件】的客户区坐标系GetClientRect Command1.hwnd, recCli1addLog "【控件】的客户区坐标系", recCli1'将屏幕坐标系中的点p(0,0)转换为【控件】的客户区坐标p.X = 0: p.Y = 0ScreenToClient Command1.hwnd, paddLog2 "将屏幕坐标系中的点p(0,0)转换为【控件】客户区坐标", p'将【控件】客户区坐标系中的点p(0,0)转换为屏幕坐标p.X = 0: p.Y = 0ClientToScreen Command1.hwnd, paddLog2 "将【控件】的客户区坐标系中的点p(0,0)转换为屏幕坐标", p, True
End SubPrivate Function toX(X As Long)toX = X / Screen.TwipsPerPixelX
End Function
Private Function toY(Y As Long)toY = Y / Screen.TwipsPerPixelY
End Function
Private Sub addLog(sTitle, rec As RECT, Optional dblcrlf As Boolean)With recText1.Text = Text1.Text & sTitle & ":(" & .Left & "," & .Top & "," & .Right & "," & .Bottom & ")" & vbCrLf & IIf(dblcrlf, vbCrLf, "")End With
End Sub
Private Sub addLog2(sTitle, p As POINTAPI, Optional dblcrlf As Boolean)With pText1.Text = Text1.Text & sTitle & ":(" & .X & "," & .Y & ")" & vbCrLf & IIf(dblcrlf, vbCrLf, "")End With
End Sub
Private Sub addLog3(sTitle, log As String, Optional dblcrlf As Boolean)Text1.Text = Text1.Text & sTitle & ":" & log & vbCrLf & IIf(dblcrlf, vbCrLf, "")
End Sub

三.常见API应用举例

1.怎样获取任一控件的尺寸,及在其容器对象中的坐标

题意:已知一个控件的句柄,求其尺寸及在其容器对象中的坐标
代表性:可求任意控件的相对坐标及其尺寸,只要有句柄就可以
应用场景:在界面控制中,有时需要将某个控件从容器A搬到容器B中显示,最后还能搬回到容器A中,这时就需要在控件搬离容器A前记住控件在容器A中的位置。如果该控件是自定义控件,事先是不知道它被置于什么容器里的,这种情况下求控件在其容器中的坐标,常规方法是有困难的,如容器客户区坐标系的单位不能指望是统一的,什么时候需要转换,怎样转换都是难题,再比如该容器可能没暴露句柄属性,使用API就受到限制。

以上面的示例为例,Command1的容器对象是Form1,这里用API来求一下Command1在Form1中的坐标及尺寸

(1)入门思路

第一步:求Command1的屏幕坐标

Dim recWin As RECT
GetWindowRect Command1.hwnd, recWin

变量recWin即为矩形CDEF在屏幕坐标系A中位置,C点坐标为(recWin.Left,recWin.Top),E点坐标为(recWin.Right,recWin.Bottom),
所以,Command1的尺寸为:
宽度=recWin.Right-recWin.Left
高度=recWin.Bottom-recWin.Top

但recWin描述的是Command1的屏幕坐标,我们需要的是Command1在Form1客户区中的坐标,明显,需要用ScreenToClient()做坐标转换。下面将C点的屏幕坐标转换为Form1客户区中的坐标。

Dim C As POINTAPI
C.X = recWin.Left
C.Y = recWin.Top
ScreenToClient Form1.hwnd, C

这样我们就得到了C点在From1客户区中的坐标,也就是Command1在Form1客户区中的坐标,即
Command1的左上角坐标=(C.X,C.Y)

(2)归纳为一条标准化的套路

上面的求法有点晦涩,不如直接将C点和E点的屏幕坐标转换都转换成在Form1客户区中的坐标,我们用一个RECT变量来存储,赋予其含义为控件在Form1客户区中的矩形坐标,更便于理解、存储、作为参数传递,形成形式化的套路,就记得牢靠了。代码如下:

'功能:获取一个控件在某容器客户区中矩形坐标
'参数:ctlHwnd,控件句柄;clientHwnd:容器句柄
Private Function GetCtlRect(ctlHwnd As Long, clientHwnd As Long) As RECT'获取控件的屏幕坐标Dim recWin As RECTGetWindowRect ctlHwnd, recWin'将C点的屏幕坐标转换为客户区坐标Dim C As POINTAPIC.X = recWin.LeftC.Y = recWin.TopScreenToClient clientHwnd, C'将E点的屏幕坐标转换为客户区坐标Dim E As POINTAPIE.X = recWin.RightE.Y = recWin.BottomScreenToClient clientHwnd, E'将控件矩形的客户区坐标收容到RECT存储起来Dim recForm As RECTSetRect recForm, C.X, C.Y, E.X, E.YGetCtlRect = recForm
End FunctionPrivate Sub Command2_Click()Dim rec As RECTrec = GetCtlRect(Command1.hwnd, Form1.hwnd)addLog "Command1在Form1客户区中的坐标", rec, True
End Sub

(3)再精进一步

有些容器对象没有暴露其句柄属性的,又当怎样求控件在父容器客户区中的矩形坐标呢?实际上,我们要解决的是怎样得到容器的句柄,可用另一个API函数——GetParent(),上述代码演变成如下:

'获取父容器的句柄
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As LongPrivate Sub Command2_Click()Dim rec As RECTrec = GetCtlRect(Command1.hwnd, GetParent(Command1.hwnd))addLog "Command1在Form1客户区中的坐标", rec, True
End Sub

2.待续...

四.关于API函数MoveWindow()

'挪动控件/窗口
Private Declare Function MoveWindow Lib "user32" (ByVal hwnd As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long

要强调的是,这个挪动是指在被挪动对象的父容器中挪动,即调用API的坐标参数是参照父容器客户区坐标系的描述。这是特定的,不能想入非非,哪儿哪儿瞎用。

VB里怎样使用GetWindowRect、GetClientRect、ScreenToClient、ClientToScreen相关推荐

  1. 关于Excel在VB里的应用(来自微软)

    下面的文章讲述了在VB里如何使用Excel,及如何添加数据到Excel中,提供了多种方法. 以下为代码摘要: With Automation, you can transfer data to a w ...

  2. 关于VB里的ScaleMode问题

    我是一个VB初学者,最近苦恼于VB的窗体和控件的ScaleMode问题,VB里默认的ScaleMode是twip,而往往我们希望它是pixel,虽然在属性面板里面能够将ScaleMode改为" ...

  3. GetClientRect相当于GetWindowRect和ScreenToClient区别

    From: http://www.cnblogs.com/yongtaiyu/archive/2011/05/18/2049554.html GetWindowRect是取得窗口在屏幕坐标系下的REC ...

  4. 易语言-API 取窗口或者组件句柄的 屏幕坐标并限制区域 GetWindowRect ClipCursor getwindowrect GetClientRect WindowFromPoint

    .版本 2 .DLL命令 ClipCursor_, 整数型, "user32", "ClipCursor", , 将指针限制到指定区域.ClipCursorBy ...

  5. CRECT,RECT区别GetWindowRect GetClientRect

    RECT是一个结构体,CRect是一个MFC类,它从RECT继承,该类实现了许多函数用来操作RECT GetWindowRect是一个Windows API函数.该函数返回指定窗口的边框矩形的大小,函 ...

  6. DPtoLP/LPtoDP 和 ScreenToClient/ClientToScreen

    设备坐标(Device Coordinate)又称为物理坐标(Physical Coordinate),是指输出设备上的坐标.通常将屏幕上的设备坐标称为屏幕坐标.设备坐标用对象距离窗口左上角的水平距离 ...

  7. GetClientRect,ClientToScreen,ClipCursor

    CRect rect;                           //创建一个矩形区域 GetClientRect(&rect);         //指定窗口的用户区域矩形,得到R ...

  8. GetWindowRect GetClientRect

    https://www.cnblogs.com/wb-DarkHorse/archive/2013/07/08/3178201.html https://blog.csdn.net/ljh060030 ...

  9. vb里的lbound和ubound的用法

    学习中,遇到难题,遇到了函数的详细讲解,转载过来收藏,原文地址:http://hi.baidu.com/freewolf/item/5f5a1baaa3e61e716cd45599 LBound 函数 ...

  10. vb修改计算机时间,如何在VB里进行日期格式转换

    满意答案 gzhys 2013.10.30 采纳率:54%    等级:7 已帮助:664人 使用 format 函数: 如: Dim MyTime, MyDate, MyStr MyTime = # ...

最新文章

  1. micropython stm32f103_micropython
  2. 字符串与base64相互转换
  3. c java 异常_javac -version 异常
  4. Google Guava EventBus用于事件编程
  5. _int64_在Linux对应对文件,linux下32位机与64位机基本数据类型长度对比
  6. RHEL 8 - RHEL自带AppStream应用模块管理
  7. 在perl中获取当前的日期和时间
  8. jetty运行web项目
  9. k6前级效果器怎么用_【易开EK-K6 DSP 专业 数字前级效果器 前置】价格_厂家_图片 -Hc360慧聪网...
  10. TP-LINK配置无线上网短信Wifi认证方式
  11. 什么是ECS + Job
  12. AWS Python应用
  13. Holt Winter时间序列模型
  14. 小知识系列(3):Hanoi塔(汉诺塔,河内塔)
  15. C语言头昏,眩晕、头晕、头昏混为一谈?这可不是一种病症
  16. 手机(局域网)远程连接 windows电脑
  17. 使用EasyPoi导出Word文件,使用@Excel注释导出实体对象图片的解决方案
  18. 超时锁定计算机,Win10电脑设置锁定屏幕超时怎么办
  19. FFC1000系列全频带微波超宽带上下变频器
  20. 素玄科技有限公司 php,php实现简单算法1 - osc_sw6n0c3p的个人空间 - OSCHINA - 中文开源技术交流社区...

热门文章

  1. HI3559A soc中使用sensor hub的uart0
  2. Origin 2022b | 更新及安装 | 中英文切换
  3. matlab 动平衡,运用labview和matlab混合编程实现转子动平衡的测试与控制
  4. 过年倒计时 java swing 附源码
  5. Dreamweaver CS4自学实例视频教程(高清)
  6. 邮箱大师支持html,网易邮箱大师使用过程的常见问题
  7. 盘点新加坡旅游宣传片中不可错过的景点
  8. EasyDarwin开源云平台接入海康威视EasyCamera摄像机之快照获取与上传
  9. 龙芯2F Debain编openssl报/usr/local/bin/ld: /usr/lib/libdl.so: error adding symbols: file in wrong format
  10. 笔记本电脑电源和电池充电管理电路设计