VBAのフォームは通常の方法ではサイズの変更ができない
VBAでフォームを作成した場合に、ひとつ不便なことがあります。それはフォームのサイズが変更できないことです。
×ボタンが付いているだけで、最大化や最小化もできません。でも、フォームのサイズは変更したくなるのが一般的なPCユーザーの感覚です。
Win32APIを使えばサイズの変更は可能
しかし、サイズ変更したい場合はやはり出てきます。たとえばテキストボックスを広げたい場合などですね。
VBAの機能だけでは実現できませんが、Win32APIを利用すると実現できます。
ソースコード
以下のソースコードは標準モジュールに書いていきます。
フォームのサイズ変更をするには以下の4つを用意します。
- Win32APIの参照宣言
- フォームのサイズ変更をする関数
- フォームサイズ変更関数を呼ぶ処理
- フォームサイズ変更時の処理
Win32APIの参照宣言
以下のWin32APIの参照宣言は標準モジュールの先頭に書いてください。
32bit版と64bit版を#Ifで分けていますが、そのままコピペしてもいいですし、必要な方だけをコピーしてもいいです。わかんない場合はそのままコピペしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Option Explicit '// Win32API用定数 Private Const GWL_STYLE = (-16) Private Const WS_MAXIMIZEBOX = &H10000 Private Const WS_MINIMIZEBOX = &H20000 Private Const WS_THICKFRAME = &H40000 '// Win32API参照宣言 '// 64bit版 #If VBA7 And Win64 Then Private Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As Long Private Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr Private Declare PtrSafe Function DrawMenuBar Lib "user32" (ByVal hwnd As LongPtr) As Long '// 32bit版 #Else Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Private Declare Function GetActiveWindow Lib "user32" () As Long Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long #End If |
フォームのサイズ変更をする関数
フォームのサイズの変更を行うメインの関数です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Public Sub FormResize() Dim hwnd As Long '// ウインドウハンドル Dim style As Long '// ウインドウスタイル '// ウインドウハンドル取得 hwnd = GetActiveWindow() '// ウインドウのスタイルを取得 style = GetWindowLong(hwnd, GWL_STYLE) '// ウインドウのスタイルにウインドウサイズ可変+最小ボタン+最大ボタンを追加 style = style Or WS_THICKFRAME Or WS_MINIMIZEBOX Or WS_MAXIMIZEBOX '// ウインドウのスタイルを再設定 Call SetWindowLong(hwnd, GWL_STYLE, style) End Sub |
このフォームサイズ変更処理の簡単な説明です。
- アクティブフォームのハンドル(フォームの識別番号)を取得します。GetActiveWindowの部分です。
- 現在のフォームのスタイル(表示状態)を取得します。GetWindowLongの部分です。
- フォームの表示状態変数に、サイズ可変と最小ボタンと最大ボタンを追加します。style = style Or ~の部分です。
- 再度ウインドウのスタイルを設定します。SetWindowLongの部分です。
処理自体は簡単な流れですが、Windowsプログラミングは見慣れない定数などが多くあり、それらの知識が要求されるため、もしカスタマイズをする際にはいろいろと調べる必要が出てきます。
このマクロはフォームのサイズ変更と最小ボタンと最大ボタンの対応を行っていますが、たとえば、サイズ変更のみでよい場合は、
1 |
style = style Or WS_THICKFRAME Or WS_MINIMIZEBOX Or WS_MAXIMIZEBOX |
の部分を以下のように変更します。
1 |
style = style Or WS_THICKFRAME |
フォームサイズ変更関数を呼ぶ処理
次に、フォームからその関数を呼ぶ処理です。
フォームがアクティブになった際のイベント関数であるUserForm_Activate()を作成して、フォームサイズ変更関数を呼びます。
フォームが選択された際にフォームサイズ変更関数を呼ぶことで、サイズ変更を実現します。
ここでは例としてリストビュー(lstvCell)を用意しています。
1 2 3 4 5 6 |
Private Sub UserForm_Activate() '// フォームのリサイズを可能にする Call FormResize Call lstvCell.ListItems.Clear End Sub |
フォームサイズ変更時の処理
最後にフォームサイズ変更時の処理です。フォームのサイズを変更する場合は、一緒に他のコントロールのサイズも変更することがほとんどです。そのため、他のコントロールのサイズを設定する必要があります。
フォームサイズが変わったときのイベント関数であるUserForm_Resize()を作成して、他のコントロールのサイズ変更処理を記述します。ここでは例としてリストビュー(lstvCell)のサイズを変更しています。
UserForm_Resize()でのテキストボックス等のサイズ設定の際には、微調整が必要な場合があります。以下の例ではListViewのサイズ変更時に、高さに+36して調整しています。
そのあたりは作りながらやってみてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Private Sub UserForm_Resize() Dim iHeight Dim iWidth '// Heightの+36は目視調整した。 iWidth = Me.InsideWidth - lstvCell.Left * 2 iHeight = Me.InsideHeight - lstvCell.Top * 2 + 36 '// WidthとHeightには0以下は設定不可のためエラーになるので0チェック If (iWidth > 0 And iHeight > 0) Then lstvCell.Width = iWidth lstvCell.Height = iHeight End If End Sub |