スタイルの変更と簡易的な描画
前回、CreateWindowExを使って標準モジュールでフォームを作成する例が作成できました。
でもわざわざ面倒な方法で普通のフォームを作っても面白くないですね。
そこでタイトルの無いウィンドウにして何かを描画してみましょう。
タイトルの無いウィンドウにするにはウィンドウスタイルを変更します。
'ウィンドウスタイルの変更 dStyle = dStyle Or WS_VISIBLE dStyle = dStyle Or WS_DLGFRAME dStyle = dStyle Or WS_POPUP
このままだとタイトルバーの閉じるボタンが無くなってしまうので、閉じる手段が無くなってしまいます。
そこで取り敢えずウィンドウ内をダブルクリックしたら閉じるように変更します。
1つ目の変更点はウィンドウクラスで、ダブルクリックを受け付けるように変更します。
ついでにこの後、描画もするので背景色を黒にしておきます。
'メインウィンドウ With wndCls .cbSize = Len(wndCls) .lpszClassName = "myWin" .lpfnWndProc = FPtr(AddressOf WndProc) .hbrBackground = GetStockObject(BLACK_BRUSH) .style = CS_DBLCLKS End With
続いて、ウィンドウプロシージャでダブルクリックに対応
Case WM_LBUTTONDBLCLK Call SendMessageW(hWnd, WM_CLOSE, 0, 0)
それでは何か簡易的に描画してみます。
描画は線の色とか、塗りつぶしの設定とかをデバイスコンテキストに選択し、
描画命令で描画する流れになります。
今回はシート上の選択範囲を元に簡易的なグラフを描画します。
1.描画する線をLOGPEN構造体に設定
tLogPen.lopnStyle = PS_SOLID '線種 tLogPen.lopnColor = vbGreen '色 tLogPen.lopnWidth.x = 2 '太さ newPen = CreatePenIndirect(tLogPen) orgPen = SelectObject(hDC, newPen)
2.直線の描画
Call MoveToEx(hDC, lngAxisX, lngAxisY, 0) Call LineTo(hDC, lngAxisX, lngHeight + lngAxisY) Call LineTo(hDC, lngWidth + lngAxisX, lngHeight + lngAxisY)
3.塗りつぶしの設定
'ブラシ(ポイント○の塗りつぶし用) newBrush = CreateSolidBrush(RGB(255, 0, 0)) orgBrush = SelectObject(hDC, newBrush)
4.点(円)の描画
Private Function DrawPointCircle(hDc As LongPtr, x As Long, y As Long, nSize As Long) As Long Dim Ret As Long Ret = Ellipse(hDc, x - nSize, y - nSize, x + nSize, y + nSize) DrawPointCircle = Ret End Function
プログラム全体は下記の通り。
しかし、こいつは隠そうとしているけど描画に関して問題点が。
次回はその問題点と、このウィンドウが邪魔と感じる場合の対応について修正します。
Option Explicit Public Const WS_VISIBLE = &H10000000 Public Const WS_POPUP = &H80000000 Public Const WS_DLGFRAME = &H400000 Public Const WM_CLOSE = &H10 Public Const WM_LBUTTONDBLCLK = &H203 Public Const CS_DBLCLKS = &H8 '背景用 Public Const WHITE_BRUSH = 0 Public Const BLACK_BRUSH = 4 Public Const PS_SOLID = 0 Public Type POINTAPI x As Long y As Long End Type Public Type LOGPEN lopnStyle As Long lopnWidth As POINTAPI lopnColor As Long End Type Public Type MSG hWnd As LongPtr message As Long wParam As LongPtr lParam As LongPtr time As Long pt As POINTAPI End Type Public Type WNDCLASSEX cbSize As Long style As Long lpfnWndProc As LongPtr cbClsExtra As Long cbWndExtra As Long hInstance As LongPtr hIcon As LongPtr hCursor As LongPtr hbrBackground As LongPtr lpszMenuName As String lpszClassName As String hIconSm As LongPtr End Type Public Declare PtrSafe Function CreateWindowEx Lib "user32" Alias "CreateWindowExA" _ (ByVal dwExStyle As Long, _ ByVal lpClassName As String, _ ByVal lpWindowName As String, _ ByVal dwStyle As Long, _ ByVal x As Long, _ ByVal y As Long, _ ByVal nWidth As Long, _ ByVal nHeight As Long, _ ByVal hWndParent As LongPtr, _ ByVal hMenu As LongPtr, _ ByVal hInstance As LongPtr, _ lpParam As Any) As LongPtr Public Declare PtrSafe Function RegisterClassEx Lib "user32" Alias "RegisterClassExA" _ (pcWndClassEx As WNDCLASSEX) As Integer Public Declare PtrSafe Function UnregisterClass Lib "user32" Alias "UnregisterClassA" _ (ByVal lpClassName As String, _ ByVal hInstance As LongPtr) As Long Public Declare PtrSafe Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" _ (ByVal lpModuleName As String) As LongPtr Public Declare PtrSafe Function DestroyWindow Lib "user32" _ (ByVal hWnd As LongPtr) As Long Public Declare PtrSafe Sub PostQuitMessage Lib "user32" _ (ByVal nExitCode As Long) Public Declare PtrSafe Function DefWindowProc Lib "user32" Alias "DefWindowProcA" _ (ByVal hWnd As LongPtr, _ ByVal wMsg As Long, _ ByVal wParam As LongPtr, _ ByVal lParam As LongPtr) As LongPtr 'メッセージループ Public Declare PtrSafe Function GetMessage Lib "user32" Alias "GetMessageA" _ (lpMsg As MSG, _ ByVal hWnd As LongPtr, _ ByVal wMsgFilterMin As Long, _ ByVal wMsgFilterMax As Long) As Long Public Declare PtrSafe Function TranslateMessage Lib "user32" _ (lpMsg As MSG) As Long Public Declare PtrSafe Function DispatchMessage Lib "user32" Alias "DispatchMessageA" _ (lpMsg As MSG) As LongPtr Public Declare PtrSafe Function SendMessageW Lib "user32" _ (ByVal hWnd As LongPtr, _ ByVal wMsg As Long, _ ByVal wParam As LongPtr, _ ByVal lParam As LongPtr) As LongPtr '描画関連 Public Declare PtrSafe Function GetDC Lib "user32" _ (ByVal hWnd As LongPtr) As LongPtr Public Declare PtrSafe Function ReleaseDC Lib "user32" _ (ByVal hWnd As LongPtr, _ ByVal hDc As LongPtr) As Long Public Declare PtrSafe Function SelectObject Lib "gdi32" _ (ByVal hDc As LongPtr, _ ByVal hObject As LongPtr) As LongPtr Public Declare PtrSafe Function DeleteObject Lib "gdi32" _ (ByVal hObject As LongPtr) As Long Public Declare PtrSafe Function GetStockObject Lib "gdi32" _ (ByVal nIndex As Long) As LongPtr Public Declare PtrSafe Function CreatePenIndirect Lib "gdi32" _ (lpLogPen As LOGPEN) As LongPtr Public Declare PtrSafe Function CreateSolidBrush Lib "gdi32" _ (ByVal crColor As Long) As LongPtr 'Public Declare PtrSafe Function MoveToEx Lib "gdi32" _ ' (ByVal hdc As LongPtr, _ ' ByVal x As Long, _ ' ByVal y As Long, _ ' lpPoint As POINTAPI) As Long Public Declare PtrSafe Function MoveToEx Lib "gdi32" _ (ByVal hDc As LongPtr, _ ByVal x As Long, _ ByVal y As Long, _ lpPoint As LongPtr) As Long Public Declare PtrSafe Function LineTo Lib "gdi32" _ (ByVal hDc As LongPtr, _ ByVal x As Long, _ ByVal y As Long) As Long Public Declare PtrSafe Function Ellipse Lib "gdi32" _ (ByVal hDc As LongPtr, _ ByVal X1 As Long, _ ByVal Y1 As Long, _ ByVal X2 As Long, _ ByVal Y2 As Long) As Long 'アドインリボンに選択範囲を元にグラフ描画するボタンを追加 Sub Auto_Open() Dim cb As CommandBar For Each cb In Application.CommandBars If cb.Name = "SampleGraph" Then cb.Delete End If Next Set cb = Application.CommandBars.Add("SampleGraph", msoBarTop, , True) With cb.Controls.Add(msoControlButton) .style = msoButtonCaption .Caption = "グラフ描画" .OnAction = "DrawMain" End With cb.Visible = True End Sub 'メイン Private Sub DrawMain() Dim hWnd As LongPtr Dim hDc As LongPtr Dim wndCls As WNDCLASSEX Dim dStyle As Long Dim dStyleEx As Long Dim tMsg As MSG Dim lngRet As Long Dim varRng As Variant On Error GoTo ErrHDL 'Excelシートからデータ取得 varRng = Selection '1次元配列以下の場合を排除(2次元の最大取得で判定) On Error Resume Next lngRet = UBound(varRng, 2) If Err.Number <> 0 Then Exit Sub End If On Error GoTo ErrHDL 'メインウィンドウの登録 With wndCls .cbSize = Len(wndCls) .lpszClassName = "myWin" .lpfnWndProc = FPtr(AddressOf WndProc) .hbrBackground = GetStockObject(BLACK_BRUSH) .style = CS_DBLCLKS End With If RegisterClassEx(wndCls) = 0 Then Call UnregisterClass(wndCls.lpszClassName, wndCls.hInstance) Exit Sub End If 'ウィンドウスタイル dStyle = dStyle Or WS_VISIBLE dStyle = dStyle Or WS_DLGFRAME dStyle = dStyle Or WS_POPUP hWnd = CreateWindowEx(0, wndCls.lpszClassName, "TEST", _ dStyle, 0, 0, 600, 600, 0&, 0&, 0&, 0&) If hWnd = 0 Then GoTo ErrHDL End If hDc = GetDC(hWnd) Call DrawGraph(hDc, "", 500, 500, 50, 50, varRng, 200) Call ReleaseDC(hWnd, hDc) 'メッセージループ Do While (GetMessage(tMsg, 0, 0, 0)) Call TranslateMessage(tMsg) Call DispatchMessage(tMsg) Loop '終了 Call UnregisterClass(wndCls.lpszClassName, wndCls.hInstance) Exit Sub ErrHDL: Call SendMessageW(hWnd, WM_CLOSE, 0, 0) Call UnregisterClass(wndCls.lpszClassName, wndCls.hInstance) End Sub 'グラフ描画 Private Sub DrawGraph(hDc As LongPtr, _ strCategory As String, _ lngWidth As Long, _ lngHeight As Long, _ lngAxisX As Long, _ lngAxisY As Long, _ arryData As Variant, _ Optional varBase As Variant = 1) Dim Ret As Long Dim tLogPen As LOGPEN Dim newPen As LongPtr Dim orgPen As LongPtr Dim newBrush As LongPtr Dim orgBrush As LongPtr Dim i As Long Dim j As Long '0除算の回避 If varBase = 0 Then varBase = 1 End If 'グラフのXY軸 tLogPen.lopnStyle = PS_SOLID tLogPen.lopnColor = vbGreen tLogPen.lopnWidth.x = 2 '太さ newPen = CreatePenIndirect(tLogPen) orgPen = SelectObject(hDc, newPen) 'X軸の目盛 For i = LBound(arryData, 1) To UBound(arryData, 1) Call MoveToEx(hDc, i / UBound(arryData, 1) * lngWidth + lngAxisX, lngHeight - 3 + lngAxisY, 0) Call LineTo(hDc, i / UBound(arryData, 1) * lngWidth + lngAxisX, lngHeight + lngAxisY) Next i Call MoveToEx(hDc, lngAxisX, lngAxisY, 0) Call LineTo(hDc, lngAxisX, lngHeight + lngAxisY) Call LineTo(hDc, lngWidth + lngAxisX, lngHeight + lngAxisY) 'グラフ tLogPen.lopnColor = vbRed tLogPen.lopnWidth.x = 1 tLogPen.lopnStyle = PS_SOLID newPen = CreatePenIndirect(tLogPen) Call SelectObject(hDc, newPen) 'ブラシ(ポイント○の塗りつぶし用) newBrush = CreateSolidBrush(RGB(255, 0, 0)) orgBrush = SelectObject(hDc, newBrush) 'グラフ描画 For j = LBound(arryData, 2) To UBound(arryData, 2) Call MoveToEx(hDc, 0 + lngAxisX, lngHeight + lngAxisY, 0) For i = LBound(arryData, 1) To UBound(arryData, 1) If Not IsNumeric(arryData(i, j)) Then arryData(i, j) = 0 End If Call LineTo(hDc, (i / UBound(arryData, 1)) * lngWidth + lngAxisX, lngHeight - arryData(i, j) / varBase * lngHeight + lngAxisY) Ret = DrawPointCircle(hDc, (i / UBound(arryData, 1)) * lngWidth + lngAxisX, lngHeight - arryData(i, j) / varBase * lngHeight + lngAxisY, 3) Next i Next j Call SelectObject(hDc, orgBrush) Call DeleteObject(newBrush) Call SelectObject(hDc, orgPen) Call DeleteObject(newPen) End Sub Private Function DrawPointCircle(hDc As LongPtr, x As Long, y As Long, nSize As Long) As Long Dim Ret As Long Ret = Ellipse(hDc, x - nSize, y - nSize, x + nSize, y + nSize) DrawPointCircle = Ret End Function Private Function FPtr(ByVal p As LongPtr) As LongPtr FPtr = p End Function Public Function WndProc(ByVal hWnd As LongPtr, ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr Select Case uMsg Case WM_CLOSE Call DestroyWindow(hWnd) Call PostQuitMessage(0) Case WM_LBUTTONDBLCLK Call SendMessageW(hWnd, WM_CLOSE, 0, 0) End Select WndProc = DefWindowProc(hWnd, uMsg, wParam, lParam) End Function