source: trunk/ab5.0/ablib/src/Classes/ActiveBasic/Windows/UI/Control.ab@ 551

Last change on this file since 551 was 551, checked in by イグトランス (egtra), 16 years ago

Buttonの追加。WM_COMMANDから子のClickイベントを発生させる仕組みの追加など。

File size: 13.5 KB
RevLine 
[473]1'Classes/ActiveBasic/Windows/UI/Control.ab
2
[545]3#require <Classes/ActiveBasic/Windows/UI/EventArgs.ab>
[473]4
5Namespace ActiveBasic
6Namespace Windows
7Namespace UI
8
[542]9'Namespace Detail
10' TypeDef PTrackMouseEvent = *Function(ByRef tme As TRACKMOUSEEVENT) As BOOL
11'End Namespace
12
[473]13Class Control
[547]14 Inherits WindowHandle
[473]15Public
[551]16 /*!
17 @brief Destroyイベントよりも後に呼ばれるDestroyイベントデリゲート
18 @date 2008/07/16
19 */
20 finalDestroy As ActiveBasic.Windows.UI.Handler
[547]21
[473]22 Sub Control()
23 End Sub
24
25 Virtual Sub ~Control()
26 End Sub
27
[542]28 Function Handle() As HWND
29 Handle = hwnd
[473]30 End Function
31
32 Static Function FromHWnd(hwnd As HWND) As Control
33 FromHWnd = Nothing
[547]34 If _System_IsWindow(hwnd) Then
[473]35 FromHWnd = FromHWndCore(hwnd)
36 End If
37 End Function
38
39Private
40 Static Function FromHWndCore(hwnd As HWND) As Control
[551]41 Dim gchValue = GetProp(hwnd, PropertyInstance As ULONG_PTR As PCTSTR) As ULONG_PTR
42 If gchValue <> 0 Then
43 Dim gch = System.Runtime.InteropServices.GCHandle.FromIntPtr(gchValue)
44 FromHWndCore = gch.Target As Control
45 Exit Function
[473]46 End If
47 End Function
48
49'--------------------------------
[544]50' ウィンドウ作成
[547]51' Function Create(
52' parent As HWND,
53' rect As RECT,
54' name As String,
55' style As DWord,
56' exStyle = 0 As DWord,
57' menu = 0 As HMENU) As HWND
[542]58
[473]59Public
[551]60 Sub Create(parent = Nothing As Control, style = 0 As DWord, exStyle = 0 As DWord, hmenu = 0 As HMENU)
[473]61 Dim cs As CREATESTRUCT
[551]62 With cs
63 .dwExStyle = exStyle
64 .lpszClass = (atom As ULONG_PTR) As LPCTSTR
65 .lpszName = 0
66 .style = style Or WS_CHILD Or WS_VISIBLE
67 .x = CW_USEDEFAULT
68 .y = CW_USEDEFAULT
69 .cx = CW_USEDEFAULT
70 .cy = CW_USEDEFAULT
71 If IsNothing(parent) Then
72 .hwndParent = 0
73 Else
74 .hwndParent = parent As HWND
75 .style Or= WS_CHILD
76 End If
77 .hMenu = hmenu
78 .hInstance = hInstance
79 End With
[473]80 GetCreateStruct(cs)
[551]81 createImpl(cs, parent)
[547]82 End Sub
[473]83
[551]84 Sub Create(parent As Control, style As DWord, exStyle As DWord, id As Long)
85 Create(parent, style, exStyle, id As HMENU)
86 End Sub
[473]87Protected
88 Abstract Sub GetCreateStruct(ByRef cs As CREATESTRUCT)
89
[551]90 Sub createImpl(ByRef cs As CREATESTRUCT, parent As Control)
[473]91 Imports System.Runtime.InteropServices
92
93 Dim gch = GCHandle.Alloc(This)
94 TlsSetValue(tlsIndex, GCHandle.ToIntPtr(gch) As VoidPtr)
95
[542]96 StartWndProc()
97
[473]98 With cs
[551]99 'よそのクラスの場合、WndProcFirst内のhwndの代入が行われないため、ここでも行っておく。
100 hwnd = CreateWindowEx(.dwExStyle, .lpszClass, .lpszName, .style,
[473]101 .x, .y, .cx, .cy, .hwndParent, .hMenu, .hInstance, .lpCreateParams)
[547]102 If hwnd = 0 Then
103 ActiveBasic.Windows.ThrowByWindowsError(GetLastError())
104 End If
[551]105
106 If IsNothing(FromHWndCore(hwnd)) <> False Then
107 AssociateHWnd(gch, hwnd)
108 TlsSetValue(tlsIndex, 0)
109 End If
[473]110 End With
[551]111
112 If IsNothing(parent) = False Then
113 RegisterUnassociateHWnd(parent)
114 End If
[547]115 End Sub
[473]116
117'--------------------------------
118' ウィンドウプロシージャ
119'Protected
120Public
121 Virtual Function WndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
[551]122 Dim h = Nothing As MessageHandler
[542]123 Dim b = messageMap.TryGetValue(Hex$(msg), h)
124 If b Then
125 If Not IsNothing(h) Then
[551]126 Dim a = New MessageArgs(hwnd, msg, wp, lp)
[542]127 h(This, a)
128 WndProc = a.LResult
129 Exit Function
130 End If
131 End If
132 WndProc = DefWndProc(msg, wp, lp)
[473]133 End Function
134
135 Virtual Function DefWndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
[542]136 DefWndProc = DefWindowProc(hwnd, msg, wp, lp)
[473]137 End Function
138
139Private
[551]140 Static Function makeKeysFormMsg(e As MessageArgs) As Keys
[473]141 Dim t As DWord
[544]142 t = e.WParam And Keys.KeyCode
[473]143 t Or= (GetKeyState(VK_SHIFT) As Word And &h8000) << 1
144 t Or= (GetKeyState(VK_CONTROL) As Word And &h8000) << 2
145 t Or= (GetKeyState(VK_MENU) As Word And &h8000) << 3
[544]146 makeKeysFormMsg = t As Keys
[473]147 End Function
148
[551]149 Static Function makeMouseEventFromMsg(e As MessageArgs) As MouseArgs
[544]150 Dim wp = e.WParam
151 Dim lp = e.LParam
[551]152 makeMouseEventFromMsg = New MouseArgs(LOWORD(wp) As MouseButtons, 1, GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 0)
[542]153 End Function
[473]154
[542]155 /*!
156 @brief 最初にウィンドウプロシージャが呼ばれるときに実行される関数
157 ここでは、主なメッセージハンドラの登録を行っている。
158 @date 2008/07/11
159 */
160 Sub StartWndProc()
[547]161 AddMessageEvent(WM_ERASEBKGND, AddressOf(OnEraseBackground))
[551]162 Dim md = New MessageHandler(AddressOf(OnMouseDownBase))
[542]163 AddMessageEvent(WM_LBUTTONDOWN, md)
164 AddMessageEvent(WM_RBUTTONDOWN, md)
165 AddMessageEvent(WM_MBUTTONDOWN, md)
166 AddMessageEvent(WM_XBUTTONDOWN, md)
[551]167 Dim mu = New MessageHandler(AddressOf(OnMouseUpBase))
[542]168 AddMessageEvent(WM_LBUTTONUP, mu)
169 AddMessageEvent(WM_RBUTTONUP, mu)
170 AddMessageEvent(WM_MBUTTONUP, mu)
171 AddMessageEvent(WM_XBUTTONUP, mu)
[551]172 Dim mb = New MessageHandler(AddressOf(OnMouseDblClkBase))
[542]173 AddMessageEvent(WM_LBUTTONDBLCLK, mu)
174 AddMessageEvent(WM_RBUTTONDBLCLK, mu)
175 AddMessageEvent(WM_MBUTTONDBLCLK, mu)
176 AddMessageEvent(WM_XBUTTONDBLCLK, mu)
[544]177
[547]178 AddMessageEvent(WM_MOUSEMOVE, AddressOf(OnMouseMoveBase))
179 AddMessageEvent(WM_MOUSELEAVE, AddressOf(OnMouseLeaveBase))
180 AddMessageEvent(WM_PAINT, AddressOf(OnPaintBase))
181 AddMessageEvent(WM_KEYDOWN, AddressOf(OnKeyDownBase))
[551]182 AddMessageEvent(WM_CHAR, AddressOf(OnChar))
[547]183 AddMessageEvent(WM_CREATE, AddressOf(OnCreateBase))
[542]184 End Sub
[473]185
[551]186 Sub OnEraseBackground(sender As Object, e As MessageArgs)
[547]187 Dim rc = ClientRect
[542]188 FillRect(e.WParam As HDC, rc, (COLOR_3DFACE + 1) As HBRUSH)
189 e.LResult = TRUE
190 End Sub
[473]191
[551]192 Sub OnMouseDownBase(sender As Object, e As MessageArgs)
[544]193 OnMouseDown(makeMouseEventFromMsg(e))
[542]194 End Sub
195
[551]196 Sub OnMouseUpBase(sender As Object, e As MessageArgs)
[544]197 Dim me = makeMouseEventFromMsg(e)
[542]198 If doubleClickFired = False Then
[551]199' OnClick(System.Args.Empty)
[542]200 OnMouseClick(me)
201 doubleClickFired = False
202 End If
203 OnMouseUp(me)
204 End Sub
205
[551]206 Sub OnMouseDblClkBase(sender As Object, e As MessageArgs)
[544]207 Dim me = makeMouseEventFromMsg(e)
[542]208 doubleClickFired = True
209 OnMouseDown(me)
[551]210' OnDoubleClick(System.Args.Empty)
[542]211 OnMouseDoubleClick(me)
212 End Sub
213
[551]214 Sub OnMouseMoveBase(sender As Object, e As MessageArgs)
[544]215 Dim me = makeMouseEventFromMsg(e)
[542]216 If mouseEntered Then
217 OnMouseMove(me)
218 Else
219 mouseEntered = True
220 OnMouseEnter(me)
221 End If
222 End Sub
223
[551]224 Sub OnMouseLeaveBase(sender As Object, e As MessageArgs)
[544]225 Dim me = makeMouseEventFromMsg(e)
226 OnMouseLeave(me)
227 mouseEntered = False
228 End Sub
229
[551]230 Sub OnPaintBase(sender As Object, e As MessageArgs)
[542]231 Dim ps As PAINTSTRUCT
[547]232 BeginPaint(ps)
[544]233 Try
[551]234 OnPaintDC(New PaintDCArgs(ps.hdc, ps.rcPaint))
[544]235 Finally
[547]236 EndPaint(ps)
[544]237 End Try
[542]238 End Sub
239
[551]240 Sub OnKeyDownBase(sender As Object, e As MessageArgs)
241 OnKeyDown(New KeyArgs(makeKeysFormMsg(e)))
[544]242 End Sub
[542]243
[551]244 Sub OnKeyUpBase(sender As Object, e As MessageArgs)
245 OnKeyUp(New KeyArgs(makeKeysFormMsg(e)))
[544]246 End Sub
247
[551]248 Sub OnChar(sender As Object, e As MessageArgs)
249 OnKeyPress(New KeyPressArgs(e.WParam As Char))
250 End Sub
[544]251
[551]252 Sub OnCreateBase(sender As Object, e As MessageArgs)
253' OnCreate(New CreateArgs(e.LParam As *CREATESTRUCT))
[544]254 End Sub
255
[551]256 messageMap As System.Collections.Generic.Dictionary<Object /*DWord*/, MessageHandler>
[542]257
258Public
[473]259 /*!
[542]260 @biref メッセージイベントハンドラを登録する。
[473]261 @date 2007/12/04
262 */
[551]263 Sub AddMessageEvent(message As DWord, h As MessageHandler)
[542]264 If Not IsNothing(h) Then
265 If IsNothing(messageMap) Then
[551]266 messageMap = New System.Collections.Generic.Dictionary<Object, MessageHandler>
[542]267 End If
268 Dim msg = Hex$(message)
[551]269 Dim m = Nothing As MessageHandler
[542]270 If messageMap.TryGetValue(msg, m) Then
271 messageMap.Item[msg] = m + h
272 Else
273 messageMap.Item[msg] = h
274 End If
275 End If
[473]276 End Sub
277
[542]278 /*!
279 @biref メッセージイベントハンドラ登録を解除する。
280 @date 2007/12/04
281 */
[551]282 Sub RemoveMessageEvent(message As DWord, a As MessageHandler)
[542]283 If Not IsNothing(a) Then
284 If Not IsNothing(messageMap) Then
[545]285 Dim msg = Hex$(message)
[542]286 Dim m = messageMap.Item[msg]
287 If Not IsNothing(m) Then
288 messageMap.Item[msg] = m - a
289 End If
290 End If
291 End If
292 End Sub
293
294'--------------------------------
295' ウィンドウメッセージ処理
296
297
[473]298'--------
299'イベント
300
301#include "ControlEvent.sbp"
302
303'--------------------------------
[544]304' インスタンスメンバ変数
[473]305Private
[542]306 /*!
307 @brief マウスカーソルがクライアント領域に入っているかどうかのフラグ
308 外から中に入ってきたときにMouseEnterイベントを発生させるために用意している。
309 */
310 mouseEntered As Boolean
311 /*!
312 @brief ダブルクリックが起こったかどうかのフラグ
313 Click/MouseClickイベントのために用意している。
314 @date 2008/07/12
315 */
316 doubleClickFired As Boolean
[473]317
318'--------------------------------
[544]319' 初期ウィンドウクラス
[473]320Private
321 Static Function WndProcFirst(hwnd As HWND, msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
322 Imports System.Runtime.InteropServices
323
[547]324 Dim rThis = FromHWndCore(hwnd)
[473]325 If IsNothing(rThis) Then
326 Dim gchValue = TlsGetValue(tlsIndex) As LONG_PTR
327 TlsSetValue(tlsIndex, 0)
328 If gchValue = 0 Then
329 Goto *InstanceIsNotFound
330 End If
331 Dim gch = GCHandle.FromIntPtr(gchValue)
332 rThis = gch.Target As Control
333 ' ウィンドウが作られて最初にWndProcFirstが呼ばれたとき
334
[551]335 If AssociateHWnd(gch, hwnd) = False Then
[473]336 Goto *InstanceIsNotFound
337 End If
338 End If
339 If msg = WM_NCDESTROY Then
[551]340 rThis.UnassociateHWnd()
[473]341 End If
[551]342 If msg = WM_DESTROY And IsNothing(rThis.finalDestroy) = False Then
343 Dim f = rThis.finalDestroy
344 f(rThis, Args.Empty)
345' finalDestroy(This, Args.Empty)
346 End If
347 WndProcFirst = rThis.WndProc(msg, wp, lp)
[473]348 Exit Function
349
350 *InstanceIsNotFound
[547]351 OutputDebugString(Ex"ActiveBasic.Windows.UI.Control.WndProcFirst: The attached instance is not found.\r\n")
[473]352 WndProcFirst = DefWindowProc(hwnd, msg, wp, lp)
353 End Function
[542]354
[551]355 /*!
356 @brief Controlインスタンスとウィンドウハンドルを結び付ける。
357 @param[in] 結び付けられるControlインスタンスを格納したGCHandle
358 @param[in] hwnd 結び付けるウィンドウハンドル
359 @date 2008/07/16
360 これを実行することで、UnassociateHWndされるまでControlがGC対象にならなくなる。
361 */
362 Static Function AssociateHWnd(gch As System.Runtime.InteropServices.GCHandle, hwnd As HWND) As Boolean
363 Imports System.Runtime.InteropServices
364 Dim rThis = gch.Target As Control
365 If IsNothing(rThis) Then
366 Exit Function
367 End If
368 rThis.hwnd = hwnd
369 rThis.Prop[PropertyInstance] = GCHandle.ToIntPtr(gch) As HANDLE
370 End Function
371
372 /*!
373 @brief オーナーの破棄時にこのControlインスタンスとウィンドウハンドルの結び付けを解除するよう登録する。
374 @param[in] owner 結び付けの解除を連動させるControl
375 @date 2008/07/16
376 ownerのFinalDestoryでこのControlとHWNDとの結び付けを解除する。
377 */
378 Sub RegisterUnassociateHWnd(owner As Control)
379 If IsNothing(owner) = False Then
380 Dim e = New Handler(AddressOf(UnassociateHWndOnEvent))
381 If IsNothing(finalDestroy) Then
382 owner.finalDestroy = e
383 Else
384 owner.finalDestroy += e
385 End If
386 End If
387 End Sub
388
389 Sub UnassociateHWndOnEvent(sender As Object, e As Args)
390 UnassociateHWnd()
391 End Sub
392
393 Sub UnassociateHWnd()
394 Imports System.Runtime.InteropServices
395 Dim gchValue = Prop(PropertyInstance) As ULONG_PTR
396 If gchValue <> 0 Then
397 GCHandle.FromIntPtr(gchValue).Free()
398 End If
399 End Sub
400
[473]401' Static Const WM_CONTROL_INVOKE = WM_USER + 0 As DWord
402' Static Const WM_CONTROL_BEGININVOKE = WM_USER + 1 As DWord
403
404'--------------------------------
[542]405' その他の補助関数
406Private
407' Sub tracMouseEvent()
408/* If pTrackMouseEvent <> 0 Then
409 Dim tme As TRACKMOUSEEVENT
410 With tme
411 .cbSize = Len(tme)
412 .dwFlags = TME_HOVER Or TME_LEAVE
413 .hwndTrack = wnd
414 .dwHoverTime = HOVER_DEFAULT
415 End With
416 pTrackMouseEvent(tme)
417 End If
418*/ 'End Sub
419
420'--------------------------------
[544]421' 初期化終了関連(特にウィンドウクラス)
[542]422Private
[473]423 'ウィンドウ作成時にウィンドウプロシージャへThisを伝えるためのもの
424 Static tlsIndex As DWord
425
426 Static hInstance As HINSTANCE
427 Static atom As ATOM
[542]428 Static hmodComctl As HMODULE
429' Static pTrackMouseEvent As PTrackMouseEvent
[473]430
431 Static Const WindowClassName = "ActiveBasic.Windows.UI.Control"
432 Static Const PropertyInstance = 0 As ATOM
433Public
434 Static Sub Initialize(hinst As HINSTANCE)
435 tlsIndex = TlsAlloc()
436 hInstance = hinst
[542]437' hmodComctl = LoadLibrary("comctl32.dll")
438' pTrackMouseEvent = GetProcAddress(hmodComctl, ToMBStr("_TrackMouseEvent"))
[473]439
440 Dim PropertyInstanceString = WindowClassName + " " + Hex$(GetCurrentProcessId())
441 PropertyInstance = GlobalAddAtom(ToTCStr(PropertyInstanceString))
442
443 Dim wcx As WNDCLASSEX
444 With wcx
445 .cbSize = Len (wcx)
446 .style = CS_HREDRAW Or CS_VREDRAW Or CS_DBLCLKS
447 .lpfnWndProc = AddressOf (WndProcFirst)
448 .cbClsExtra = 0
449 .cbWndExtra = 0
450 .hInstance = hinst
451 .hIcon = 0
452 .hCursor = LoadImage(0, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE Or LR_SHARED) As HCURSOR
453 .hbrBackground = 0
454 .lpszMenuName = 0
455 .lpszClassName = ToTCStr(WindowClassName)
456 .hIconSm = 0
457 End With
458 atom = RegisterClassEx(wcx)
459 If atom = 0 Then
460 Dim buf[1023] As TCHAR
461 wsprintf(buf, Ex"ActiveBasic.Windows.UI.Control.Control: RegisterClasseEx failed. Error code: &h%08X\r\n", GetLastError())
462 OutputDebugString(buf)
463 Debug
464 ExitThread(0)
465 End If
466 End Sub
467
468 Static Sub Uninitialize()
[542]469 If atom <> 0 Then
470 UnregisterClass(atom As ULONG_PTR As PCSTR, hInstance)
471 End If
472 If tlsIndex <> 0 And tlsIndex <> &hffffffff Then
473 TlsFree(tlsIndex)
474 End If
475' If hmodComctl <> 0 Then
476' FreeLibrary(hmodComctl)
477' End If
478 If PropertyInstance <> 0 Then
479 GlobalDeleteAtom(PropertyInstance)
480 End If
[473]481 End Sub
482
483End Class
484
485End Namespace 'UI
486End Namespace 'Widnows
487End Namespace 'ActiveBasic
Note: See TracBrowser for help on using the repository browser.