【Access VBA】フォームの表示位置を指定する - カットマンブログ

【Access VBA】フォームの表示位置を指定する


フォームの表示位置を指定する

Windows APIを使ってフォームの表示位置を指定します。下記リンク先にて作成したカレンダーコントロールの表示位置が呼び出し元フォームのテキストボックスの位置に連動して変わるようにします。
【Access VBA】カレンダーコントロールの作成 - カットマンブログ



twipをpixelに変換する関数の記述

テキストボックスの位置がtwip単位で取得されるため、これをpixelに変換する関数を標準モジュールに記述します。下記サイトよりコピペしました。
Access VBA Form の位置、サイズはtwip単位で係数は567である #access - Qiita

Public Const SM_CYCAPTION As Long = 4
Public Const SM_CXFIXEDFRAME As Long = 7
Public Const SM_CYFIXEDFRAME As Long = 8
Public Const SM_CXFULLSCREEN As Long = 16
Public Const SM_CYFULLSCREEN As Long = 17
Public Const WU_LOGPIXELSX = 88
Public Const WU_LOGPIXELSY = 90

Public Declare PtrSafe Function GetWindowRect Lib "user32" (ByVal hwnd As LongPtr, ByRef lpRect As RECT) As LongPtr
Public Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Public Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, ByVal nIndex As Long) As LongPtr
Public Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As LongPtr
Public Declare PtrSafe Function MoveWindow Lib "user32" (ByVal hwnd As LongPtr, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As LongPtr
Public Declare PtrSafe Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
Public Declare PtrSafe Function GetClientRect Lib "user32" (ByVal hwnd As LongPtr, lpRect As RECT) As Long
Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
End Type

Public meRect_parent As RECT
Public meRect_client As RECT
Public ownerRect As RECT

Public Function ConvertTwipsToPixels(lngTwips As Long, lngDirection As Long) As Long
   'Handle to device
   Dim lngDC As Long
   Dim lngPixelsPerInch As Long
   Const nTwipsPerInch = 1440
   lngDC = GetDC(0)
   If (lngDirection = 0) Then       'Horizontal
      lngPixelsPerInch = GetDeviceCaps(lngDC, WU_LOGPIXELSX)
   Else                            'Vertical
      lngPixelsPerInch = GetDeviceCaps(lngDC, WU_LOGPIXELSY)
   End If
   lngDC = ReleaseDC(0, lngDC)
   ConvertTwipsToPixels = (lngTwips / nTwipsPerInch) * lngPixelsPerInch
End Function


カレンダーフォームの開く時のイベントプロシージャの記述

Fカレンダーの開く時のイベントプロシージャに以下のコードを記述します。
Fカレンダーが画面の右側にはみ出す場合に、Fカレンダーの右端がテキストボックスの右端にくるようにしています。
Fカレンダーが画面の下側にはみ出す場合に、Fカレンダーの下端がテキストボックスの上端にくるようにしています。

Private Sub Form_Open(Cancel As Integer)
    Dim leftPosition As Long
    Dim topPosition As Long
    Dim oForm As Object
    Set oForm = Forms(Application.CurrentObjectName)

    GetWindowRect Forms(Application.CurrentObjectName).hwnd, ownerRect

    Dim meWidth_parent As Long
    Dim meHeight_parent As Long
    GetWindowRect Me.hwnd, meRect_parent
    GetClientRect Me.hwnd, meRect_client
    With meRect_parent
        meWidth_parent = .Right - .Left 'Fカレンダーの幅
        meHeight_parent = .Bottom - .Top 'Fカレンダーの高さ
    End With
    Dim leftPosition_owner As Long
    Dim topPosition_owner As Long
    Dim xframeWidth As Long
    Dim titleHeight As Long
    Dim leftPosition_textbox As Long
    Dim topPosition_textbox As Long
    Dim textboxWidth As Long
    Dim textboxHeight As Long
    Dim screenWidth As Long
    Dim screenHeight As Long
    Dim meWidth_client As Long
    Dim meHeight_client As Long
    leftPosition_owner = ownerRect.Left '呼び出し元フォームの左位置
    topPosition_owner = ownerRect.Top '呼び出し元フォームの上位置
    xframeWidth = GetSystemMetrics(SM_CXFIXEDFRAME) 'ウインドウの水平罫線の太さ
    titleHeight = GetSystemMetrics(SM_CYCAPTION) 'タイトルバーの高さ
    screenWidth = GetSystemMetrics(SM_CXFULLSCREEN) '全画面表示ウインドウのクライアント領域の幅
    screenHeight = GetSystemMetrics(SM_CYFULLSCREEN) '全画面表示ウインドウのクライアント領域の高さ
    meWidth_client = meRect_client.Right 'Fカレンダーのクライアント領域の幅
    meHeight_client = meRect_client.Bottom 'Fカレンダーのクライアント領域の高さ
    
    With oForm.Controls(OpenArgs)
        leftPosition_textbox = ConvertTwipsToPixels(.Left, 0) 'テキストボックスの左位置
        topPosition_textbox = ConvertTwipsToPixels(.Top, 1) 'テキストボックスの上位置
        textboxWidth = ConvertTwipsToPixels(.Width, 0) 'テキストボックスの幅
        textboxHeight = ConvertTwipsToPixels(.Height, 1) 'テキストボックスの高さ
    End With
        If leftPosition_owner + leftPosition_textbox > screenWidth - meWidth_parent Then
            leftPosition = leftPosition_owner + leftPosition_textbox + textboxWidth - meWidth_client
        Else
            leftPosition = leftPosition_owner + leftPosition_textbox
        End If
        
        If topPosition_owner + xframeWidth + titleHeight + topPosition_textbox + textboxHeight > screenHeight - meHeight_parent Then
            topPosition = topPosition_owner + topPosition_textbox - meHeight_client
        Else
            topPosition = topPosition_owner + xframeWidth + titleHeight + topPosition_textbox + textboxHeight
        End If

    MoveWindow Me.hwnd, leftPosition, topPosition, meWidth_parent, meHeight_parent, True
End Sub


呼び出し元フォームのボタンクリック時イベントプロシージャの修正

呼び出し元フォームのボタンクリック時イベントプロシージャのOpenFormメソッドのOpenArgs引数にテキストボックスの名前を追加しました。

Private Sub btnCalendar_Click()
        sDate = Nz(txtDate, 0)
        DoCmd.OpenForm "Fカレンダー", , , , , acDialog, "txtDate"
        If sDate <> 0 Then
            txtDate = sDate
        End If
End Sub