Win 10 Excel 2016 无法解释的 PixelsToPoints 系数来定位用户窗体

2024-03-27

序言

当尝试将用户窗体定位在特定像素位置(存储在POINTAPI类型结构),必须将 Pixel 坐标转换为 Point 坐标才能设置UserForm.Left and UserForm.TopVBA 属性。我们称这个系数为K。

从我的测试中,我开始了解到,就我而言,GetWindowRect以及 UserForm 的 VBA 定位属性 (Left, Top, Width, Height)包括包含 MSForm UserForm 控件的窗口(属于“ThunderDFrame”类)周围的阴影。要真正获得由边框界定的窗口矩形,DwnGetWindowAttribute(hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, rcOutRECT, LenB(rcOutRECT)必须使用Win API。

定位 UserForm 的坐标系原点是 Pixel (0; 0),所以无需担心ActiveWindow.PointsToScreenPixelsX / ActiveWindow.PointsToScreenPixelsY以及 Excel 窗口的左上角与工作表网格的左上角之间的偏移量(至少直到Range.Left, Range.Top等属性发挥作用)。然而,有趣的是,ActiveWindow.PointsToScreenPixelsX行为不像ActiveWindow.ActivePane.PointsToScreenPixelsX。第一个使用具有输入的像素,而不是像第二个那样使用点。该方法的真实名称应该是ActiveWindow.WorksheetPixelsXToScreenPixelsX。您可以轻松验证:

ActiveWindow.PointsToScreenPixelsX(1) - ActiveWindow.PointsToScreenPixelsX(0)

返回 1,而如果它确实在进行转换,则应该返回大于 1 的值,因为 1 Point 占用屏幕上的多个像素。 (由于像素的整数舍入,也不是真正的 1/K)

Problem

考虑到缩放系数为 1 以简化我的 MCV 示例,确定的系数.Left and .Top我们希望其显示的屏幕像素中 (x; y) 位置的用户窗体的 Points 属性应该是:

72 / GetDeviceCaps(GetDC(0), LOGPIXELSX)
72 / GetDeviceCaps(GetDC(0), LOGPIXELSY)

这是

  • 96 DPI 传统显示屏为 0.75(我已在使用 Win 7 + Excel 2007 的 PC 上尝试过)
  • 0.375,我的 Surface Pro 4 平板电脑在 Win 10 64 位和 Excel 2016 32 位上运行

现在的问题是,在我的平板电脑上,虽然上述计算返回 0.375,定位用户窗体的正确系数在给定的像素位置(从GetCursorPos以Win API为例)通过将其转换为对应的Point位置is 0.35. 我不知道这个价值从哪里来......???

现在的进展

在平板电脑上:

reg key HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\AppliedDPI表示 192 和72 / 192 = 0.375

我还尝试了 MSDN Windows 桌面应用程序 UI 参考中的高 DPI 参考中的一些功能:

  • GetDPIForWindow(我尝试使用Application.Hwnd和UserForm的窗口句柄)
  • GetDPIForMonitor

但一切都会正常返回 192。

最小、完整且可验证的示例

以下内容允许我在平板电脑上检索神秘的 K = 0.35 系数,但在另一台计算机上返回 0.75,正如预期的那样。

模块1.bas

Private Declare Function GetWindowRect Lib "user32" (ByVal hWnd As Long, rcWindowRect As RECT) As Long
Private Declare Function GetCursorPos Lib "user32" (ptCursorPoint As POINTAPI) As Long

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Type POINTAPI
    X As Long
    Y As Long
End Type

Sub test()
    Dim rcUsfWindowRect As RECT
    UserForm1.Show vbModeless
    lRet& = GetWindowRect(UserForm1.hWnd, rcUsfWindowRect)
    dblUsfRectWidth# = rcUsfWindowRect.Right - rcUsfWindowRect.Left
    dblUsfRectHeight# = rcUsfWindowRect.Bottom - rcUsfWindowRect.Top
    Debug.Print UserForm1.Width / dblUsfRectWidth
End Sub

用户表单1

Private Declare Function FindWindowA Lib "user32" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public hWnd As Long

Private Sub UserForm_Initialize()
    hWnd = FindWindowA("ThunderDFrame", UserForm1.Caption)
End Sub

我有同样的问题。我在 64 位上尝试了你的代码,也收到了 0.35。

module1

Option Explicit

Private Declare PtrSafe Function GetWindowRect Lib "user32" (ByVal hWnd As Long, rcWindowRect As RECT) As Long
Private Declare PtrSafe Function GetCursorPos Lib "user32" (ptCursorPoint As POINTAPI) As Long

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Type POINTAPI
    X As Long
    Y As Long
End Type

Sub test()
    Dim rcUsfWindowRect As RECT
    Dim dblUsfRectWidth As Double
    Dim dblUsfRectHeight As Double
    
    UserForm1.Show vbModeless
    Call GetWindowRect(UserForm1.hWnd, rcUsfWindowRect)
    dblUsfRectWidth = rcUsfWindowRect.Right - rcUsfWindowRect.Left
    dblUsfRectHeight = rcUsfWindowRect.Bottom - rcUsfWindowRect.Top
    Debug.Print UserForm1.Width / dblUsfRectWidth
End Sub

用户表单1

Option Explicit

Private Declare PtrSafe Function FindWindowA Lib "user32" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public hWnd As Long

Private Sub UserForm_Initialize()
    hWnd = FindWindowA("ThunderDFrame", UserForm1.Caption)
End Sub

奇怪的是,我下载了一个标尺应用程序来测量 UserForm1 的宽度(以像素为单位)。我将 Excel 中表单的宽度调整为 500,结果我得到的测量宽度为 1406 像素。并且 500/1406 = 0.356 而不是 0.375。 我还发现了为什么它是 0.356 而不是 0.35,这是因为 GetWindowRect 函数显然返回一个宽度,包括边框周围的阴影。 (左边是 15 或 16 像素,右边是 10 像素)。如果没有这个,宽度将为 1406 + 15 + 10 = 1431 和 500/1431 = 0.349,更接近 0.35。

我之前的笔记本电脑上没有出现这些问题,并且使用外接显示器也没有出现这些问题。这种情况仅发生在高 DPI 显示器上。 (可能是因为 Windows 中的这些显示器启用了显示虚拟化)。

编辑: 如果我将窗口缩放更改为 100% 注销并重新登录,我会得到 0.75 的值,一切都会按预期进行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Win 10 Excel 2016 无法解释的 PixelsToPoints 系数来定位用户窗体 的相关文章

随机推荐

  • 如何离线存储密码

    虽然这是针对Windows Phone 7的 但我想这个原理是通用的 我想在我的应用程序中设置一个密码保护区 但是 我的应用程序完全离线 因此我必须在手机上存储凭据详细信息 我最初的想法是存储密码和盐的哈希值 这是最好的方法吗 如果是这样
  • 更改特定索引而不在 Vuejs 中重新渲染整个数组

    In a Vuejs项目 我有一个array in my 数据对象并将其呈现在视图中v for指示 现在 如果我更改该数组中的特定索引 Vue 会在视图中重新渲染整个数组 有没有办法在不重新渲染整个数组的情况下查看视图的变化 这个问题背后的
  • 如何处理 JSON 字符串中的 unicode 值?

    我正在用 C 编写 JSON 解析器 在解析 JSON 字符串时遇到问题 JSON 规范规定 JSON 字符串可以包含以下形式的 unicode 字符 here comes a unicode character u05d9 我的 JSON
  • 如何获取要执行的 PTX 文件

    我知道如何生成 ptx文件来自 cu以及如何生成 cubin文件来自 ptx 但我不知道如何获得最终的可执行文件 更具体地说 我有一个sample cu文件 编译为sample ptx 然后我使用 nvcc 来编译sample ptx to
  • 如何在Oracle中查找模式名称?当您使用只读用户连接到 SQL 会话时

    我使用只读用户连接到 Oracle 数据库 并且在 sql Developer 中设置连接时使用了服务名称 因此我不知道 SID 架构 如何找到我连接到的架构名称 我正在寻找这个 因为我想要生成 ER 图 https stackoverfl
  • 按方案中的第一个元素对列表列表进行排序

    例如 我正在研究按第一个元素对列表列表进行排序 排序 列表 2 1 6 7 4 3 1 2 4 5 1 1 预期输出 gt 1 1 2 1 6 7 4 3 1 2 4 5 我使用的算法是冒泡排序 我修改了它来处理列表 但是 该代码无法编译
  • jQuery Mobile 范围滑块响应不够灵敏

    各位互联网界的好心人 大家好 我正在尝试使用 jQuery Mobile 滑块 范围 虽然它们工作得相当好并且在桌面浏览器上响应良好 但它们似乎在实际手机 例如 Android 与互联网网页交互时 Android 上使用触摸屏的滑块交互非常
  • Facebook SDK:ApiException:代理应用程序在未事先安装的情况下无法请求发布权限

    我正在努力使用 Android facebook SDK 3 5 riigth ow 我的账户一切都很完美 现在我把这个应用程序给了我的一个朋友 当他登录时 他并没有因为这个失败而被卡住 ApiException The proxied a
  • Azure 表存储将数据导出到 SQL 的平面或 XML 文件

    I am looking for capability to Export data from SQL Azure Azure Table Storage to Some Flat file or XML file so that we c
  • 如何将我的表单放在 css/html 中的图像之上?

    开发者们好 我想问一下如何才能让我的表单出现在我的图片之上 问题是我的表格出现在底部 这是我的屏幕截图 这是我的代码 HTML div class container align center div img src assets img
  • Fabric 不断要求输入密码

    我有 fab 文件 其中包含 env hosts localhost env user code env password searce def mk dirtree sudo mkdir s PROJECT DIR sudo chown
  • Java中int是如何实现的?

    根据文档Integer class Integer 类将基本类型 int 的值包装在对象中 Integer 类型的对象包含一个类型为 int 的字段 和文档int 默认情况下 int 数据类型是 32 位有符号二进制补码整数 其最小值为 2
  • 在组件安装之前反应设置滚动位置

    我有下面的反应组件 它本质上是一个聊天框 render const messages this props messages return div h1 this props project 0 project h1 div div div
  • 如何在 XCode4 中复制项目目标

    我想为测试环境创建一个具有不同捆绑 ID 的目标 我尝试使用 复制 功能来克隆目标并更改捆绑 ID 发现原始目标也发生了更改 感谢您的任何提示 更新 解决复制目标后的链接错误 这是一个xcode bug 搜索路径中的引号字符 更改为 目标的
  • PostgreSQL bigserial 和 nextval

    我有一个 PgSQL 9 4 3 服务器设置 之前我只使用公共模式 例如我创建了一个如下表 CREATE TABLE ma accessed by members tracking reference bigserial NOT NULL
  • 给定一个 4x4 齐次矩阵,我如何获得 3D 世界坐标?

    所以我有一个正在旋转然后再次平移和旋转的对象 我将这些翻译的矩阵存储为对象成员 现在 当我进行对象拾取时 我需要知道该对象的 3D 世界坐标 目前我已经能够像这样获得物体的位置 coords 0 finalMatrix 12 坐标 1 最终
  • h2o.saveModel 在 Windows 8 上抛出目录异常

    我在 R 中使用 h2o 版本 3 0 0 22 并尝试保存我的模型 但我似乎无法弄清楚预期的格式 我尝试了各种变化 但遇到了各种不同的异常 h2o saveModel model dir c temp name my model ERRO
  • Python - 基于 LSTM 的 RNN 需要 3D 输入?

    我正在尝试构建一个基于 LSTM RNN 的深度学习网络 这是尝试过的 from keras models import Sequential from keras layers import Dense Dropout Activatio
  • "message":"没有活动连接","node_env":"生产"

    我正在尝试在我的计算机上安装 Kibana 4 但出现以下错误 timestamp 2015 04 15T06 25 50 688Z level error node env production error Request error r
  • Win 10 Excel 2016 无法解释的 PixelsToPoints 系数来定位用户窗体

    序言 当尝试将用户窗体定位在特定像素位置 存储在POINTAPI类型结构 必须将 Pixel 坐标转换为 Point 坐标才能设置UserForm Left and UserForm TopVBA 属性 我们称这个系数为K 从我的测试中 我