如何在MS-Access中找到父窗口的宽度

时间:2009-08-17 20:06:43

标签: ms-access vba

我正在尝试强制MS-Access表单相对于主窗口的右边缘采取某个位置(实际上我想将它居中,但我可以看到也希望将它停靠在一侧或另一侧)。我可以使用Me.Move重新定位表格,例如,

    Me.Move newWindowLeft, newWindowTop, newWidth, newHeight

但是,如何找出父窗口的宽度?

5 个答案:

答案 0 :(得分:7)

您可以使用Windows API:

(更新后返回缇)

Type Rect
    x1 As Long
    y1 As Long
    x2 As Long
    y2 As Long
End Type

Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As Rect) As Long

Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long

Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long

Declare Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, ByVal nIndex As Long) As Long

Const LOGPIXELSX = 88
Const LOGPIXELSY = 90
Const DIRECTION_VERTICAL = 1
Const DIRECTION_HORIZONTAL = 0

Public Function GetMainWindowSize()

    Dim MDIRect As Rect
    Dim lWidthPixels As Long
    Dim lWidthTwips As Long

    ' Get the screen coordinates and window size of the MDIClient area'
    GetClientRect Application.hWndAccessApp, MDIRect

    lWidthPixels = MDIRect.x2 - MDIRect.x1
    lWidthTwips = PixelsToTwips(lWidthPixels, DIRECTION_HORIZONTAL)

    MsgBox "Width (Pixels) = " & lWidthPixels & "  Width (Twips) = " & lWidthTwips

End Function


Function PixelsToTwips(lPixels As Long, lDirection As Long) As Long

    Dim lDeviceHandle As Long
    Dim lPixelsPerInch As Long

    lDeviceHandle = GetDC(0)

    If lDirection = DIRECTION_HORIZONTAL Then
        lPixelsPerInch = GetDeviceCaps(lDeviceHandle, LOGPIXELSX)
    Else

        lPixelsPerInch = GetDeviceCaps(lDeviceHandle, LOGPIXELSY)
    End If

    lDeviceHandle = ReleaseDC(0, lDeviceHandle)

    PixelsToTwips = lPixels * 1440 / lPixelsPerInch

End Function

答案 1 :(得分:4)

不确定您使用的Access版本,但在Access 2003中,似乎没有办法直接获取此信息。

这是一个黑客:

DoCmd.Maximize

w = Forms("yourForm").WindowWidth
h = Forms("yourForm").WindowHeight

这将最大化当前窗口,让我们假设它是你的形式。然后,您可以测量窗体以获取父窗口显示区域的大小,然后取消最大化,并根据您现在知道的父窗口的大小移动窗体。

如果有办法在Access中关闭ScreenUpdating,您可以在最大化和测量代码之前执行此操作,然后重新打开它,就用户而言,它不会花费任何明显的时间

编辑:即使没有隐藏用户的最大化命令,整个最大化和移动操作也会比用户看到的更快。

这是一个丑陋的黑客,但确实有效。

答案 2 :(得分:3)

这是我使用的实际代码

Application.Echo False  'turn off screen updates

DoCmd.Maximize
w = Me.WindowWidth
h = Me.WindowHeight
DoCmd.Restore           'restore the window to it's old size

Application.Echo True   'turn on screen updates

DoCmd.MoveSize w / 2 - myWidth / 2, _
            h / 2 - myHeigth / 2, _
            myWidth, _
            myHeigth

答案 3 :(得分:1)

我意识到这是一个非常古老的问题,但我想分享一些代码,我已经创建这些代码来处理这个问题最初目的的最终结果 - 重新定位窗口,使它们与另一个现有实体保持一致。

This module暴露了3个功能:


TwipsToPixels ( _
    Twips As Long, _
    Optional Dimension As Dimension = DIMENSION_X _
) As Long

PixelsToTwips ( _
    Pixels As Long, _
    Optional Dimension As Dimension = DIMENSION_X _
) As Long

这些只是在一个测量单位和另一个测量单位之间进行转换。两者都接受长整数参数输入和Dimension枚举中的值,X或Y,可用于指定是否应根据水平或垂直显示设置完成转换。值得注意的是99.99999%的时间,两个维度的值都是相同的,所以你通常可以省略第二个参数。两者都返回一个长整数。

该模块在内部使用像素作为内容,因此这些转换函数仅为方便缇工作的应用程序提供便利。


PositionWindow ( _
    hWnd As Long, _
    Mode As PositionMode, _
    Optional OffsetX As Long = 0, _
    Optional OffsetY As Long = 0 _
)
  • hWnd是要定位的窗口的句柄(例如,要定位窗体窗口,可以使用objForm.hWnd获取)。
  • Mode是根据PositionMode枚举中的选项构建的位掩码(见下文)。
  • OffsetX是在评估Mode后,在水平维度中调整位置的像素数。
  • OffsetY是在评估Mode后,在垂直维度调整位置的像素数。

<强>模式

每次定位调用都需要X组件和Y组件。这些组件由两个子组件组成,即基础和位置。

base是一个用作计算新位置的参考的实体,可以是DISPLAY(机器上的活动物理显示)之一,WINDOW(主Access窗口)或CURSOR(鼠标指针)。为方便起见,这些值组合在PositionMode enum。

的值中

使用主Access窗口的中心像素确定活动显示。如果这超出了机器附带的物理显示器上显示的区域范围,则调整该值以进行补偿,并使用应用程序中可见部分最大的显示。

X组件的位置可以是LEFTRIGHTX_CENTER中的一个。 Y分量包含TOPBOTTOMY_CENTER

使用LEFT会导致目标窗口的最左侧像素与基本实体的最左侧像素对齐,此模式将跟随RIGHTTOPBOTTOMCENTER位置使目标窗口的中心线与基本实体的中心线对齐。

来自PositionMode枚举的值与按位Or运算符组合以实现所需的表达式。

处理显示溢出

有时,当WINDOWCURSOR用作其中一个组件的基础时,可以定位目标窗口,使其中的部分或全部不在可见显示器上。为避免这种情况,您可以使用PREVENT_OVERFLOW_XPREVENT_OVERFLOW_Y标志。这些可以简单地包含在使用按位Mode运算符传递给Or参数的位掩码中。

如果需要,这些标志会调整位置,以确保整个目标窗口位于活动监视器的边缘内。

为方便起见,枚举中还包含PREVENT_OVERFLOW项,这与指定PREVENT_OVERFLOW_XPREVENT_OVERFLOW_Y相同。

Oveflow预防不适用于基于DISPLAY的职位。

<强>偏移

OffsetXOffsetY参数可用于在窗口以Mode指定的方式对齐后调整窗口的位置。两者都可以是正数或负数,表示在相关维度中改变位置的像素数。

显示溢出防止将覆盖偏移 - 仍将应用偏移,但如果结果位置导致目标窗口的一部分或全部位于活动显示之外,则将调整位置以使其返回边界内

<强>限制

多个显示器的处理代码有两个假设:

  • 虚拟显示区域(所有显示器被视为单个显示器的组合)是统一的 - 所以它不会很好地使用L形设置或其他如此荒谬的配置。
  • 所有活动的显示器使用相同的分辨率。

根据我的经验,在现实世界中,这些都是相当安全的假设。

不支持同时重新定位和重新调整大小(与objForm.Move一样)。您需要将这些视为单独的任务。

<强>实施例

' Get the window handle for frm_MyForm
Dim hWnd As Long
hWnd  = Forms("frm_MyForm").hWnd

' Align the form to the top left corner of the active display
PositionWindow hWnd, DISPLAY_LEFT Or DISPLAY_TOP

' Align the form to the center of the Access main window
PositionWindow hWnd, WINDOW_X_CENTER Or WINDOW_Y_CENTER

' Align the form to the bottom right of the mouse pointer position, prevent the
' window from disappearing off the screen
' This effectively sets the top left corner of the window to the pointer location
PositionWindow hWnd, CURSOR_RIGHT Or CURSOR_BOTTOM Or PREVENT_OVERFLOW

' Horizontally center the form on the display, vertically center on the mouse
PositionWindow hWnd, DISPLAY_X_CENTER Or CURSOR_Y_CENTER

' Center the window on the mouse pointer then move it 200px right and 30px up
PositionWindow hWnd, CURSOR_X_CENTER Or CURSOR_Y_CENTER, 200, -30

答案 4 :(得分:0)

这可能是有意义的:http://www.mvps.org/access/downloads/clFormWindow.bas

它说:

 '' Moves and resizes a window in the coordinate system        *
 '' of its parent window.                                      *
 '' N.B.: This class was developed for use on Access forms     *
 ''       and has not been tested for use with other window    *
 ''       types.                                               *