■お題
ウィンドウの表示(問題出典:どう書く?org)
- 問題詳細 -
ウィンドウの表示(問題出典:どう書く?org)
- 問題詳細 -
画面中央に幅100ピクセル、高さ75ピクセルのウィンドウを表示してください。
タイトルには「こんにちは、GUI!」と表示してください。
使用するGUIライブラリに名前が付いているならば、それをタグでつけてください。(例えば「Swing」など。)
追記:100x75はあまりに小さすぎるようなので、小さすぎるせいでうまく行かない場合は400x300でもいいということにします。 このお題の意図は「小さいウィンドウを出せ」というわけではないので。
■解答例
ポイントは2つ。
・ディスプレイのサイズはどうやって取得するか?
・ポイントとピクセルの違いは?
ExcelVBAでウィンドウサイズを取得できないようなので、WindowsAPIのGetWindowRect関数を使って取得するとよさそうです。
□ウィンドウズAPIとは?
平たくいえば、OSの機能を外部プログラムとやりとりするものですね。
WindowsAPIのGetWindowRect関数は、“ウィンドウ”全体の座標を取得することができます。
この関数では、あらゆる“ウィンドウ”の座標を取得できるのでまずどの“ウィンドウ”の座標を知りたいのか指定する必要があります。“ウィンドウの”指定方法は、全ての“ウィンドウ”には重複のない番号が割り当てられているのでその番号を取得してGetWindowRect関数に渡す必要があります。
今回知りたい“ウィンドウ”は、デスクトップです。
デスクトップのハンドルを知るのにGetDesktopWindow関数を使いました。
では、コードです。
まずは、デスクトップのサイズを取得する関数についてです。
モジュール名:SubModule内
4行目:ウィンドウ全体の座標を取得する
6~11行目:WindowsAPIのGetWindowRect関数の第二引数で使う変数を定義
13行目:デスクトップの幅と高さを返す関数。返り値に幅と高さを保持したユーザー定義型を返します。
14行目:hwnd変数、デスクトップのウィンドウハンドルを取得する変数
15行目:WindowsAPIのGetDesktopWindow関数でデスクトップのウィンドウハンドルを取得
17行目:変数REをユーザー定義型RECTとして宣言。WindowsAPIのGetWindowRectの第二引数に渡す
18行目:変数Result、GetWindowRect関数の戻り値を格納。0の時関数は、取得失敗を意味する。
19行目:WindowsAPIのGetWindowRect関数で第一引数に渡したウィンドウハンドルの座標を取得
21行目:変数WindowSizeをユーザー定義型WIndowSizeとして宣言
22行目:ユーザー定義型WindowSizeを宣言した変数のWidthにデスクトップの幅を格納
23行目:ユーザー定義型WindowSizeを宣言した変数のHeightにデスクトップの高さを格納
24行目:戻り値としてユーザー定義型WindowSizeを返す
SampleCode1関数を実行することで
・ウィンドウサイズ400x300
・画面中央表示
・タイトルをこんにちは、GUI!
で表示します。
モジュール名:MainModule内
デスクトップの幅と高さを受け取る為に使います。
ウィンドウのサイズを変更します。
タイトルが見づらいので400x300で表示します。
9行目 :ウィンドウの高さを300pxにする
10行目:ウィンドウの幅を400pxにする
12行目:変数DeskTopSizeは、デスクトップの幅と高さを受け取る為の変数
13行目:GetWindowSize関数で、幅と高さを戻り値として受け取る。
ウィンドウの位置をデスクトップの中央に移動します。
(15、16行目に問題あり。)
15行目:デスクトップの高さ÷2 - ウィンドウの高さ÷2
16行目:デスクトップの幅 ÷2 - ウィンドウの幅 ÷2
18行目:タイトルを変更する。
あってそうな気がしますが、残念ながらこれじゃ画面中央に表示されません。
GetWindowRect関数の返す値の単位とApplication.Topや.Leftに指定する値の単位が違います。
・GetWindowRect関数 →px(ピクセル)
・Application.Top/.Left→pt(ポイント)
つまり、単位変換しないと画面中央に表示されません。
pxとptの変換は、
[pt] = [px] ÷ [解像度] × 72
[px] = [pt] × [解像度] ÷ 72
なお、解像度は、
Application.DefaultWebOptions.PixelsPerInchで調べられます。
そこらへんを考慮してSampleCode1関数を書き直すと
モジュール名:MainModule内
よって、最終的なコードは下記になります。
MainModule内のSampleCode2関数を実行すると題意のとおりになります。
モジュール名:MainModule内
モジュール名:SubModule内
ポイントは2つ。
・ディスプレイのサイズはどうやって取得するか?
・ポイントとピクセルの違いは?
ExcelVBAでウィンドウサイズを取得できないようなので、WindowsAPIのGetWindowRect関数を使って取得するとよさそうです。
□ウィンドウズAPIとは?
Windows API(ウィンドウズ エーピーアイ)とは、Microsoft WindowsのAPIのことである。特に32ビットプロセッサで動作するWindows 95以降やWindows NTで利用できるものはWin32 APIと呼ばれる。また、それらのWindowsにおけるWin32 APIの実装をWin32と呼ぶ。(WikiPediaより引用)
平たくいえば、OSの機能を外部プログラムとやりとりするものですね。
WindowsAPIのGetWindowRect関数は、“ウィンドウ”全体の座標を取得することができます。
この関数では、あらゆる“ウィンドウ”の座標を取得できるのでまずどの“ウィンドウ”の座標を知りたいのか指定する必要があります。“ウィンドウの”指定方法は、全ての“ウィンドウ”には重複のない番号が割り当てられているのでその番号を取得してGetWindowRect関数に渡す必要があります。
今回知りたい“ウィンドウ”は、デスクトップです。
デスクトップのハンドルを知るのにGetDesktopWindow関数を使いました。
では、コードです。
まずは、デスクトップのサイズを取得する関数についてです。
モジュール名:SubModule内
Option Explicit Declare Function GetDesktopWindow Lib "user32" () As Long Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long Type RECT Left As Long Top As Long Right As Long Bottom As Long End Type Function GetWindowSize() As WindowSize Dim hwnd As Long hwnd = GetDesktopWindow() Dim Re As RECT Dim Result As Long Result = GetWindowRect(hwnd, Re) Dim WindowSize As WindowSize WindowSize.Width = Re.Right - Re.Left WindowSize.Height = Re.Bottom - Re.Top GetWindowSize = WindowSize End Function3行目:デスクトップウィンドウのハンドルを取得するためにWindowsAPIの関数を宣言
4行目:ウィンドウ全体の座標を取得する
6~11行目:WindowsAPIのGetWindowRect関数の第二引数で使う変数を定義
13行目:デスクトップの幅と高さを返す関数。返り値に幅と高さを保持したユーザー定義型を返します。
14行目:hwnd変数、デスクトップのウィンドウハンドルを取得する変数
15行目:WindowsAPIのGetDesktopWindow関数でデスクトップのウィンドウハンドルを取得
17行目:変数REをユーザー定義型RECTとして宣言。WindowsAPIのGetWindowRectの第二引数に渡す
18行目:変数Result、GetWindowRect関数の戻り値を格納。0の時関数は、取得失敗を意味する。
19行目:WindowsAPIのGetWindowRect関数で第一引数に渡したウィンドウハンドルの座標を取得
21行目:変数WindowSizeをユーザー定義型WIndowSizeとして宣言
22行目:ユーザー定義型WindowSizeを宣言した変数のWidthにデスクトップの幅を格納
23行目:ユーザー定義型WindowSizeを宣言した変数のHeightにデスクトップの高さを格納
24行目:戻り値としてユーザー定義型WindowSizeを返す
SampleCode1関数を実行することで
・ウィンドウサイズ400x300
・画面中央表示
・タイトルをこんにちは、GUI!
で表示します。
モジュール名:MainModule内
Option Explicit Type WindowSize Height As Long Width As Long End Type Sub SampleCode1() '問題を含んだコード Application.Height = 400 Application.Width = 300 Dim DeskTopSize As WindowSize DeskTopSize = GetWindowSize() Application.Top = DeskTopSize.Height / 2 - Application.Height / 2 Application.Left = DeskTopSize.Width / 2 - Application.Width / 2 ActiveWindow.Caption = "こんにちは、GUI!" End Sub3~6行目:ユーザー定義型を定義します。
デスクトップの幅と高さを受け取る為に使います。
ウィンドウのサイズを変更します。
タイトルが見づらいので400x300で表示します。
9行目 :ウィンドウの高さを300pxにする
10行目:ウィンドウの幅を400pxにする
12行目:変数DeskTopSizeは、デスクトップの幅と高さを受け取る為の変数
13行目:GetWindowSize関数で、幅と高さを戻り値として受け取る。
ウィンドウの位置をデスクトップの中央に移動します。
(15、16行目に問題あり。)
15行目:デスクトップの高さ÷2 - ウィンドウの高さ÷2
16行目:デスクトップの幅 ÷2 - ウィンドウの幅 ÷2
18行目:タイトルを変更する。
あってそうな気がしますが、残念ながらこれじゃ画面中央に表示されません。
GetWindowRect関数の返す値の単位とApplication.Topや.Leftに指定する値の単位が違います。
・GetWindowRect関数 →px(ピクセル)
・Application.Top/.Left→pt(ポイント)
つまり、単位変換しないと画面中央に表示されません。
pxとptの変換は、
[pt] = [px] ÷ [解像度] × 72
[px] = [pt] × [解像度] ÷ 72
なお、解像度は、
Application.DefaultWebOptions.PixelsPerInchで調べられます。
そこらへんを考慮してSampleCode1関数を書き直すと
モジュール名:MainModule内
Option Explicit Sub SampleCode2() '完成版 Dim WindowSize As WindowSize Call GetWindowSize(WindowSize) Dim dpi As Double dpi = Application.DefaultWebOptions.PixelsPerInch '解像度求める Application.Width = 100 Application.Height = 75 Application.Top = (WindowSize.Height / dpi) * 72 / 2 - Application.Height / 2 'WindowsAPIから得た値はptへ変換する Application.Left = (WindowSize.Width / dpi) * 72 / 2 - Application.Width / 2 'WindowsAPIから得た値はptへ変換する End Sub
よって、最終的なコードは下記になります。
MainModule内のSampleCode2関数を実行すると題意のとおりになります。
モジュール名:MainModule内
Option Explicit Type WindowSize Height As Long Width As Long End Type Sub SampleCode2() '完成版 Dim WindowSize As WindowSize Call GetWindowSize(WindowSize) Dim dpi As Double dpi = Application.DefaultWebOptions.PixelsPerInch '解像度求める Application.Width = 100 Application.Height = 75 Application.Top = (WindowSize.Height / dpi) * 72 / 2 - Application.Height / 2 'WindowsAPIから得た値はptへ変換する Application.Left = (WindowSize.Width / dpi) * 72 / 2 - Application.Width / 2 'WindowsAPIから得た値はptへ変換する End Sub
モジュール名:SubModule内
Option Explicit Declare Function GetDesktopWindow Lib "user32" () As Long Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long Type RECT Left As Long Top As Long Right As Long Bottom As Long End Type Function GetWindowSize() As WindowSize Dim hwnd As Long hwnd = GetDesktopWindow() Dim Re As RECT Dim Result As Long Result = GetWindowRect(hwnd, Re) Dim WindowSize As WindowSize WindowSize.Width = Re.Right - Re.Left WindowSize.Height = Re.Bottom - Re.Top GetWindowSize = WindowSize End Function
0 件のコメント:
コメントを投稿