MS Access 2016 - 从作为 AcDialog 打开的表单中删除标题栏

Posted

技术标签:

【中文标题】MS Access 2016 - 从作为 AcDialog 打开的表单中删除标题栏【英文标题】:MS Access 2016 - Remove the title bar from a form opened as AcDialog 【发布时间】:2016-06-03 11:32:28 【问题描述】:

我正在尝试复制具有透明背景的 Windows 10 风格的全屏模式对话框。除了标题栏外,我的一切都运行良好。

我无法摆脱它。我还为窗口透明度禁用了任何其他 API 子类化。 Borderstyle 设置为 None,我隐藏了所有的标题栏控件。表单设置为 Popup 和 Modal

我是这样打开的:

DoCmd.OpenForm "Modal_Full_Screen", acNormal, , , , acDialog

这些是我在 Form_Load 事件中进行的 API 调用,试图摆脱它:

Dim lStyle As Long
SetWindowLong Me.hwnd, GWL_EXSTYLE, GetWindowLong(Me.hwnd, GWL_EXSTYLE) And Not WS_EX_DLGMODALFRAME

SetWindowPos Me.hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED Or SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOZORDER
lStyle = GetWindowLong(Me.hwnd, GWL_STYLE)
lStyle = lStyle And Not (WS_BORDER Or WS_DLGFRAME Or WS_MAXIMIZEBOX Or WS_MINIMIZEBOX Or WS_THICKFRAME Or WS_CAPTION)
Call SetWindowLong(Me.hwnd, GWL_STYLE, lStyle)
SetWindowPos Me.hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED Or SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOZORDER

我绝对希望它停止处理并等待输入。我知道弹出窗口的技巧,在它打开后放置一个循环等待窗口关闭,但我不是 DoEvents 的粉丝,只是倾向于使堆栈崩溃,尤其是在速度更快的机器上。

如果这不可能,是否有办法禁用或捕获标题栏事件,单击并拖动它会从全屏恢复窗口(但双击它不会最大化它?)。

【问题讨论】:

【参考方案1】:

这里有很多可能出错的地方。

首先要检查的是表单在表单加载事件中是否真的有窗口句柄。它可能不会。 (它不在.net 的WinForms 中。)在调用SetWindowLong 时设置断点,或者在进行API 调用之前检查hwnd 的值是否为0。

要检查的第二件事是这些 API 调用的实际返回值是什么。 SetWindowLong如果函数失败返回0,除非窗口样式以0开头,这种情况需要在调用前调用SetLastError(0),并使用GetLastError的结果来判断调用是否真的失败.在伪代码中是这样的:

SetLastError(0)
result = SetWindowLong(...)
if result = 0:
    lastError = GetLastError()
    if lastError <> 0:
        ' Handle the error here.
    else:
        ' The window style is actually 0.

还要查看文档以获取 SetWindowPos 的返回值。 (请记住,Windows API BOOL 类型实际上是一个 32 位整数。)您还应该使用 GetWindowLong 查看是否有任何窗口样式应用于窗口,因为如果窗口仍在初始化,并且还没有'还没得到它是WM_CREATE,它可能处于未确定状态。这很好地导致了接下来要检查的事情。

假设表单的句柄是有效的,并且 API 调用都成功了,那么窗口在初始化期间很可能会在应用其属性时重置其窗口样式。要解决此问题,您可以将样式自定义移至表单的 Activate 事件,该事件在表单最终显示并呈现给用户时发生。

如果这些都不起作用,您可以子类化窗口过程,并处理WM_NCHITTEST 消息。在英语中,这就是“窗口消息 - 非客户端命中测试”。消息由窗口管理器发送到窗口过程,以决定鼠标在任何给定点位于窗口的哪个部分。要禁用非客户区1 中的所有内容,请使用HTCLIENT 回复消息,告诉窗口管理器鼠标在您的职责范围内。 (此消息也是您如何制作可被其背景拖动的表单的方法。)

如果您想完全消除标题栏,并且无法通过将边框样式设置为None 来管理它,那么唯一的其他选择就是处理WM_NCPAINT 消息,并绘制非客户端手动区域。请参阅documentation,了解如何回复该消息的示例。

最后两个解决方案都需要更多的编程工作,但 *** 上和网络上的其他地方都有很多示例。处理绘画至少需要 4 或 5 次额外的 API 调用。这实际上取决于从表单中删除标题栏的重要性。


1 为了大大简化,非客户区代表标题栏、系统菜单、最小化和最大化按钮以及窗口边框。客户区就是其他一切。

【讨论】:

我应该给你买件斗篷,你今天是我的英雄。查找 GWL_Style 的第一个 GetWindowLong 引发了无效索引错误。我对常量的声明是私有的,所以 GWL_Style 为 Null。现在它完美地工作了。非常感谢,这是一堂很棒的诊断课。

以上是关于MS Access 2016 - 从作为 AcDialog 打开的表单中删除标题栏的主要内容,如果未能解决你的问题,请参考以下文章

从 MS Access VBA 通过 ODBC 进行 MySQL 查询:ADODB 异步执行不起作用

如何使用 Pass-through 查询从 MS Access 前端向 sql 表输入数据?

MS Access 2016:如何将连接字段从表单输入到表中

从 MS Access 2016 VBA 启动 Outlook 2016 触发“另一个程序正在使用 Outlook”并死掉

MS Access 选择不同的随机值

从 MS Access 执行存储过程导致超时