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

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

MouseLeave, MouseHoverが動作するようにした。

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