ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 1317|回复: 24

[原创] 窗体控件在屏幕上的精确位置,可用于实现窗体跟随

[复制链接]

TA的精华主题

TA的得分主题

发表于 2024-6-1 23:54 | 显示全部楼层 |阅读模式

在 VBA 里如何把一个窗体放到另一个窗体的某个控件附近,并且精确到1个像素?

众所周知,我写过一段用 VBA 调用 Windows 系统日历控件的代码,并且这个日历控件可以在窗体上用,设计上要放到文本框等控件附近使用。网上也有很多人用窗体和窗体控件自制日历窗体,也需要将做好的日历放到别的窗体上使用,但这些自制的日历控件大多没有给出令人满意的窗体跟随功能(我看过的代码里面,做得最好的是郑广学先生相关作品里面的)。

这些日历窗体都很优秀,界面都很漂亮。为了弥补其窗体跟随功能的缺失,我决定把这问题研究透,半月前得出可用的代码,而今趁着周末有空,分享出来以供这些日历窗体使用。以下图片是我测试时的效果:
效果预览.png
附件压缩包中共有3个文件,其中 PDF 文件为说明文档,Word 文件为测试用例,完整代码在 bas 文件里。


但愿能给诸位的日历窗体锦上添花。

原创-窗口控件屏幕位置-窗体跟随可用.zip

204.21 KB, 下载次数: 82

评分

2

查看全部评分

TA的精华主题

TA的得分主题

发表于 2024-6-2 07:03 | 显示全部楼层
image.png
测试没成功,不知道什么原因

另外这个方法只是定位窗体中控件的位置跟随?能不能用于跟随单元格位置?

TA的精华主题

TA的得分主题

发表于 2024-6-2 07:10 | 显示全部楼层
以前用的简单的方法,直接用窗体位置和控件位置合并计算,除了需要调整一下标题宽度基本能满足常规情况

image.png

如果考虑做通用的窗体跟随,希望是能实现如果控件出现在屏幕边缘时,比如右侧边缘和下方边缘,能自动让跟随的窗体显示在左侧或上方,而不要出现在屏幕外侧。举例

image.png
image.png

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-6-2 13:10 | 显示全部楼层
micch 发表于 2024-6-2 07:03
测试没成功,不知道什么原因

另外这个方法只是定位窗体中控件的位置跟随?能不能用于跟随单元格位置?

问的问题有点多,但都在我意料之中,根本原因在于没看文档,或者没看懂我写的代码,太急于发表评论
回答2楼的问题:
测试没成功,不知道什么原因
GetControlRect 返回的是文本框在屏幕上的坐标,单位是像素,而 UserForm1 的 Top 和 Left 属性单位是点:
出错原因.png
这就好比 5 毛钱和 5 块钱一样,数值都是 5,但单位不一样,不能直接相等(变量赋值)。
正确的调用方式可以参考1楼附件里给的 Word 文档。里面甚至给了两种调用方法,注意里面 ControlPositionPixel 和 ControlPositionPoint 的区别。
如果懒得看,请务必先看懂 GetControlRect 的代码再用

另外这个方法只是定位窗体中控件的位置跟随?能不能用于跟随单元格位置?

明显不可以。这个帖子的标题不是“工作表单元格在屏幕上的精确位置”。

至于单元格的跟随功能,其实StackOverflow网站上已经给出代码,(对于Excel 2007及以上版本)那个就是正解。我的日历窗体主题第51楼附件“month_calendar_v1.0.4”中既给出了代码,也给了链接。Excel 2007以前的Office版本需要额外的计算,稍微麻烦些。正是由于单元格定位功能(很早之前就)已经由外国网友解决,并非我原创,所以不适合放在这个帖子里面。而这个帖子的代码是纯纯原创的。

TA的精华主题

TA的得分主题

发表于 2024-6-2 14:15 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
是指这里吗?也就是rect得到的数据还需要自己另外写函数转换?
image.png

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-6-2 14:24 | 显示全部楼层
micch 发表于 2024-6-2 07:10
以前用的简单的方法,直接用窗体位置和控件位置合并计算,除了需要调整一下标题宽度基本能满足常规情况

...

以前用的简单的方法,直接用窗体位置和控件位置合并计算,除了需要调整一下标题宽度基本能满足常规情况
这个问题也在意料之中。其实我已经在文档里面提到了:
文档截图.png
以前用的简单的方法“基本能满足常规情况”,此帖是“完全能满足所有情况”。

下面解释一下截图中的“无视嵌套层级”的含义,先看图:
控件嵌套测试窗体.png
这是在网友 mythqiu 的提议下正在测试更新版日历控件所用的窗体,其中有多个文本框,有的文本框直接放在窗体上,有的嵌入其它控件里面。用此帖的方法,可以获得任意一个文本框的精确位置,无需关心文本框是嵌套在多少层嵌套的其它控件里面。

【若要用“以前用的简单的方法”,可以试试此楼附件中的窗体框架,要求是新建一个窗体,放在图中 UserForm1 TextBox3 的右侧。试试就知道“以前用的简单的方法”的问题在哪了】


如果考虑做通用的窗体跟随,希望是能实现如果控件出现在屏幕边缘时,比如右侧边缘和下方边缘,能自动让跟随的窗体显示在左侧或上方,而不要出现在屏幕外侧。
请看帖子标题。窗体跟随的核心问题在于精确定位,获得窗体要放置的位置信息。至于窗体是放在该位置的左侧还是右侧还是下方或者上方,由用户决定,并非此帖所需要关心的。此帖子解决的是比窗体跟随更为基础、更为重要的问题。

所说的这个问题,有个帖子讨论过,那个帖子有人给了解决方案,但其实那个方案并未尽善,只是我看那个帖子的楼主已经对给出的方案感到满意,我也就没有另给解法(怕抢了别人的风头,也怕楼主被已有方案先入为主,无法欣赏更好方案的美妙之处)。

窗体框架.zip

2.06 KB, 下载次数: 35

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-6-2 14:51 | 显示全部楼层
micch 发表于 2024-6-2 14:15
是指这里吗?也就是rect得到的数据还需要自己另外写函数转换?


还需要自己另外写函数转换?
等的就是这句话。

答案是:看是直接用还是间接用。

如果想要的就是像素坐标,那就直接用,就像 Word 文档里面所给两种调用例子里的第一种一样,无需转换。如果是像2楼那样间接用,确实需要自己写函数转换。

这就有点像大型超市里面卖的牛肉一样,有生有熟。有的人想买生牛肉,有的人想买熟牛肉,能直接吃的那种。有的人进了超市,买了两斤牛肉回去,路上一看发现是生的,掉头回去问超市老板:“你这牛肉怎么是生的啊?没法直接吃啊!难道还要我自己动手煮吗?” 也有的人进了超市,一看生鲜区的牛肉都是熟的,直接问超市老板:“老板你这牛肉怎么都是熟了啊?都是怎么做的?”老板说:“用上好的龙骨汤熬了三天三夜呢,放了朝天椒、青椒……”,这顾客听到这说了句“好的”,扭头就走——他本想买生牛肉自己做,而且他不吃辣。

此帖子就像一个超市,主要是生肉。熟肉也有,在 Word 文档里面。

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-6-2 15:15 | 显示全部楼层
micch 发表于 2024-6-2 14:15
是指这里吗?也就是rect得到的数据还需要自己另外写函数转换?
是指这里吗?

不是指那里。

红色方框框住的部分,不需要自己另外写函数转换。
所给代码已经完成了整个“实现原理”的内容。

TA的精华主题

TA的得分主题

发表于 2024-6-2 15:47 | 显示全部楼层
prome3 发表于 2024-6-2 15:15
不是指那里。

红色方框框住的部分,不需要自己另外写函数转换。

image.png


这是全部代码吧?没仔细研究,这个函数根据输入的控件,计算返回一个rect,分别有4个属性值,对应控件的坐标位置和大小。

使用的时候,想让窗体显示在右侧的话,就是窗体top=RECT.TOP  ?  窗体.left=控件的Left+Width  ??  不能这样直接用,因为RECT的单位和窗体的单位不一样,所以需要转换一下,也就是类似进制转换然后就能定位了。

这个转换的代码没看到,主要还是我自己都没搞懂,两个单位的区别,

TA的精华主题

TA的得分主题

发表于 2024-6-2 15:58 | 显示全部楼层
现在理解下来:用这个函数可以获取控件在屏幕的像素位置,然后知道了像素坐标点,那么想把窗体显示在这个坐标位置,只需要把这个RECT的值,转化为点坐标,赋值给窗体的属性,就能想放哪放哪?

我这样理解的对吗?
假设我写一个屏幕像素转化点的函数,比如 PixelTo点(Pix)  那么在使用的时候,只需要在我原来的用法上嵌套一下 比如  userform1.top = PixelTo点(RECT.Top)  ?
如果我想放在下方,就加高度,想放左侧或者右侧,根据left和width的值计算下窗体位置就行。


如果上述理解的正确,那么再另外写个功能,判断需要定位的控件,是不是出现在右边缘或者下边缘,对窗体显示位置做相应调整,就能解决窗体现在超出屏幕的问题。


然后继续引申我第一次的问题:这个代码无法用到单元格上,我的意思是能否用同样的方法,换一个代码实现跟随单元格,也就是有没有计算出单元格屏幕像素坐标的api,有的话换一下api只要能算出单元格的像素坐标,后续显示窗体的方法就一样了。

PS.  主要是没看懂,并不是挑毛病,因为对api一向不喜欢研究,看不懂代码,也就不会二次开发代码
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-17 07:25 , Processed in 0.046800 second(s), 14 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表