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
Line 
1'Classes/ActiveBasic/Windows/UI/Control.ab
2
3#require <Classes/ActiveBasic/Windows/UI/EventArgs.ab>
4
5Namespace ActiveBasic
6Namespace Windows
7Namespace UI
8
9'Namespace Detail
10' TypeDef PTrackMouseEvent = *Function(ByRef tme As TRACKMOUSEEVENT) As BOOL
11'End Namespace
12
13Class Control
14 Inherits WindowHandle
15Public
16 /*!
17 @brief Destroyイベントよりも後に呼ばれるDestroyイベントデリゲート
18 @date 2008/07/16
19 */
20 finalDestroy As ActiveBasic.Windows.UI.Handler
21
22 Sub Control()
23 End Sub
24
25 Virtual Sub ~Control()
26 End Sub
27
28 Function Handle() As HWND
29 Handle = hwnd
30 End Function
31
32 Static Function FromHWnd(hwnd As HWND) As Control
33 FromHWnd = Nothing
34 If _System_IsWindow(hwnd) Then
35 FromHWnd = FromHWndCore(hwnd)
36 End If
37 End Function
38
39Private
40 Static Function FromHWndCore(hwnd As HWND) As Control
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
46 End If
47 End Function
48
49'--------------------------------
50' ウィンドウ作成
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
58
59Public
60 Sub Create(parent = Nothing As Control, style = 0 As DWord, exStyle = 0 As DWord, hmenu = 0 As HMENU)
61 Dim cs As CREATESTRUCT
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
80 GetCreateStruct(cs)
81 createImpl(cs, parent)
82 End Sub
83
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
87Protected
88 Abstract Sub GetCreateStruct(ByRef cs As CREATESTRUCT)
89
90 Sub createImpl(ByRef cs As CREATESTRUCT, parent As Control)
91 Imports System.Runtime.InteropServices
92
93 Dim gch = GCHandle.Alloc(This)
94 TlsSetValue(tlsIndex, GCHandle.ToIntPtr(gch) As VoidPtr)
95
96 StartWndProc()
97
98 With cs
99 'よそのクラスの場合、WndProcFirst内のhwndの代入が行われないため、ここでも行っておく。
100 hwnd = CreateWindowEx(.dwExStyle, .lpszClass, .lpszName, .style,
101 .x, .y, .cx, .cy, .hwndParent, .hMenu, .hInstance, .lpCreateParams)
102 If hwnd = 0 Then
103 ActiveBasic.Windows.ThrowByWindowsError(GetLastError())
104 End If
105
106 If IsNothing(FromHWndCore(hwnd)) <> False Then
107 AssociateHWnd(gch, hwnd)
108 TlsSetValue(tlsIndex, 0)
109 End If
110 End With
111
112 If IsNothing(parent) = False Then
113 RegisterUnassociateHWnd(parent)
114 End If
115 End Sub
116
117'--------------------------------
118' ウィンドウプロシージャ
119'Protected
120Public
121 Virtual Function WndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
122 Dim h = Nothing As MessageHandler
123 Dim b = messageMap.TryGetValue(Hex$(msg), h)
124 If b Then
125 If Not IsNothing(h) Then
126 Dim a = New MessageArgs(hwnd, msg, wp, lp)
127 h(This, a)
128 WndProc = a.LResult
129 Exit Function
130 End If
131 End If
132 WndProc = DefWndProc(msg, wp, lp)
133 End Function
134
135 Virtual Function DefWndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
136 DefWndProc = DefWindowProc(hwnd, msg, wp, lp)
137 End Function
138
139Private
140 Static Function makeKeysFormMsg(e As MessageArgs) As Keys
141 Dim t As DWord
142 t = e.WParam And Keys.KeyCode
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
146 makeKeysFormMsg = t As Keys
147 End Function
148
149 Static Function makeMouseEventFromMsg(e As MessageArgs) As MouseArgs
150 Dim wp = e.WParam
151 Dim lp = e.LParam
152 makeMouseEventFromMsg = New MouseArgs(LOWORD(wp) As MouseButtons, 1, GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 0)
153 End Function
154
155 /*!
156 @brief 最初にウィンドウプロシージャが呼ばれるときに実行される関数
157 ここでは、主なメッセージハンドラの登録を行っている。
158 @date 2008/07/11
159 */
160 Sub StartWndProc()
161 AddMessageEvent(WM_ERASEBKGND, AddressOf(OnEraseBackground))
162 Dim md = New MessageHandler(AddressOf(OnMouseDownBase))
163 AddMessageEvent(WM_LBUTTONDOWN, md)
164 AddMessageEvent(WM_RBUTTONDOWN, md)
165 AddMessageEvent(WM_MBUTTONDOWN, md)
166 AddMessageEvent(WM_XBUTTONDOWN, md)
167 Dim mu = New MessageHandler(AddressOf(OnMouseUpBase))
168 AddMessageEvent(WM_LBUTTONUP, mu)
169 AddMessageEvent(WM_RBUTTONUP, mu)
170 AddMessageEvent(WM_MBUTTONUP, mu)
171 AddMessageEvent(WM_XBUTTONUP, mu)
172 Dim mb = New MessageHandler(AddressOf(OnMouseDblClkBase))
173 AddMessageEvent(WM_LBUTTONDBLCLK, mu)
174 AddMessageEvent(WM_RBUTTONDBLCLK, mu)
175 AddMessageEvent(WM_MBUTTONDBLCLK, mu)
176 AddMessageEvent(WM_XBUTTONDBLCLK, mu)
177
178 AddMessageEvent(WM_MOUSEMOVE, AddressOf(OnMouseMoveBase))
179 AddMessageEvent(WM_MOUSELEAVE, AddressOf(OnMouseLeaveBase))
180 AddMessageEvent(WM_PAINT, AddressOf(OnPaintBase))
181 AddMessageEvent(WM_KEYDOWN, AddressOf(OnKeyDownBase))
182 AddMessageEvent(WM_CHAR, AddressOf(OnChar))
183 AddMessageEvent(WM_CREATE, AddressOf(OnCreateBase))
184 End Sub
185
186 Sub OnEraseBackground(sender As Object, e As MessageArgs)
187 Dim rc = ClientRect
188 FillRect(e.WParam As HDC, rc, (COLOR_3DFACE + 1) As HBRUSH)
189 e.LResult = TRUE
190 End Sub
191
192 Sub OnMouseDownBase(sender As Object, e As MessageArgs)
193 OnMouseDown(makeMouseEventFromMsg(e))
194 End Sub
195
196 Sub OnMouseUpBase(sender As Object, e As MessageArgs)
197 Dim me = makeMouseEventFromMsg(e)
198 If doubleClickFired = False Then
199' OnClick(System.Args.Empty)
200 OnMouseClick(me)
201 doubleClickFired = False
202 End If
203 OnMouseUp(me)
204 End Sub
205
206 Sub OnMouseDblClkBase(sender As Object, e As MessageArgs)
207 Dim me = makeMouseEventFromMsg(e)
208 doubleClickFired = True
209 OnMouseDown(me)
210' OnDoubleClick(System.Args.Empty)
211 OnMouseDoubleClick(me)
212 End Sub
213
214 Sub OnMouseMoveBase(sender As Object, e As MessageArgs)
215 Dim me = makeMouseEventFromMsg(e)
216 If mouseEntered Then
217 OnMouseMove(me)
218 Else
219 mouseEntered = True
220 OnMouseEnter(me)
221 End If
222 End Sub
223
224 Sub OnMouseLeaveBase(sender As Object, e As MessageArgs)
225 Dim me = makeMouseEventFromMsg(e)
226 OnMouseLeave(me)
227 mouseEntered = False
228 End Sub
229
230 Sub OnPaintBase(sender As Object, e As MessageArgs)
231 Dim ps As PAINTSTRUCT
232 BeginPaint(ps)
233 Try
234 OnPaintDC(New PaintDCArgs(ps.hdc, ps.rcPaint))
235 Finally
236 EndPaint(ps)
237 End Try
238 End Sub
239
240 Sub OnKeyDownBase(sender As Object, e As MessageArgs)
241 OnKeyDown(New KeyArgs(makeKeysFormMsg(e)))
242 End Sub
243
244 Sub OnKeyUpBase(sender As Object, e As MessageArgs)
245 OnKeyUp(New KeyArgs(makeKeysFormMsg(e)))
246 End Sub
247
248 Sub OnChar(sender As Object, e As MessageArgs)
249 OnKeyPress(New KeyPressArgs(e.WParam As Char))
250 End Sub
251
252 Sub OnCreateBase(sender As Object, e As MessageArgs)
253' OnCreate(New CreateArgs(e.LParam As *CREATESTRUCT))
254 End Sub
255
256 messageMap As System.Collections.Generic.Dictionary<Object /*DWord*/, MessageHandler>
257
258Public
259 /*!
260 @biref メッセージイベントハンドラを登録する。
261 @date 2007/12/04
262 */
263 Sub AddMessageEvent(message As DWord, h As MessageHandler)
264 If Not IsNothing(h) Then
265 If IsNothing(messageMap) Then
266 messageMap = New System.Collections.Generic.Dictionary<Object, MessageHandler>
267 End If
268 Dim msg = Hex$(message)
269 Dim m = Nothing As MessageHandler
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
276 End Sub
277
278 /*!
279 @biref メッセージイベントハンドラ登録を解除する。
280 @date 2007/12/04
281 */
282 Sub RemoveMessageEvent(message As DWord, a As MessageHandler)
283 If Not IsNothing(a) Then
284 If Not IsNothing(messageMap) Then
285 Dim msg = Hex$(message)
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
298'--------
299'イベント
300
301#include "ControlEvent.sbp"
302
303'--------------------------------
304' インスタンスメンバ変数
305Private
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
317
318'--------------------------------
319' 初期ウィンドウクラス
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
324 Dim rThis = FromHWndCore(hwnd)
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
335 If AssociateHWnd(gch, hwnd) = False Then
336 Goto *InstanceIsNotFound
337 End If
338 End If
339 If msg = WM_NCDESTROY Then
340 rThis.UnassociateHWnd()
341 End If
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)
348 Exit Function
349
350 *InstanceIsNotFound
351 OutputDebugString(Ex"ActiveBasic.Windows.UI.Control.WndProcFirst: The attached instance is not found.\r\n")
352 WndProcFirst = DefWindowProc(hwnd, msg, wp, lp)
353 End Function
354
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
401' Static Const WM_CONTROL_INVOKE = WM_USER + 0 As DWord
402' Static Const WM_CONTROL_BEGININVOKE = WM_USER + 1 As DWord
403
404'--------------------------------
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'--------------------------------
421' 初期化終了関連(特にウィンドウクラス)
422Private
423 'ウィンドウ作成時にウィンドウプロシージャへThisを伝えるためのもの
424 Static tlsIndex As DWord
425
426 Static hInstance As HINSTANCE
427 Static atom As ATOM
428 Static hmodComctl As HMODULE
429' Static pTrackMouseEvent As PTrackMouseEvent
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
437' hmodComctl = LoadLibrary("comctl32.dll")
438' pTrackMouseEvent = GetProcAddress(hmodComctl, ToMBStr("_TrackMouseEvent"))
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()
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
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.