2016-01-03 46 views
0

我是這個論壇的新手,所以在此先感謝您對此主題的幫助。訪問表單子類捕獲WM_MOVING郵件

我試圖解決我認爲是一個古老的Access窗體問題。我正在開發一個數據庫,在這個數據庫中,彈出式主表單打開了我想要保留在主表單邊框內的其他幾個彈出窗體。當主窗體移動或調整大小時,我需要相應地移動並調整其他打開的窗體的大小。我基本上試圖讓我的數據庫看起來類似於一個主窗體有幾個子窗體的實際應用程序。

我使用事件Detail_Paint()來檢測主窗體的大小是否改變,以調整其他窗體的大小,它似乎工作。但是在屏幕上沒有與該移動相關的事件。 MouseMove()似乎不起作用,因爲當用戶在表單標題上移動鼠標光標時,它不會觸發。我已經用一個定時器解決了這個問題,該定時器每10毫秒檢查一次主窗體的位置並相應地改變其他窗體的位置。但是,這會導致顯示器出現令人討厭的閃爍,並且在用戶在控件中輸入文字時也會出現問題。

我讀過,可以子窗體和捕獲WM_MOVING消息到窗口。我爲此開發了一些測試代碼,但是當我嘗試運行它時,Access停止工作,我必須使用任務管理器關閉它。我在Windows 10 64位系統上使用Access 2016 Professional 64位。

這是我寫到目前爲止的代碼。

' This code goes into a general module (mdl_subclass) 
' When subclassing shows the coordinates of the window in its caption 

Option Explicit 

Declare PtrSafe Function SetWindowLongPtr Lib "user32" Alias  "SetWindowLongPtrA" _ 
     (ByVal hWnd As LongPtr, _ 
     ByVal nIndex As LongPtr, _ 
     ByVal dwNewLong As LongPtr) As LongPtr 

Declare PtrSafe Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _ 
     (ByVal lpPrevWndFunc As LongPtr, _ 
     ByVal hWnd As LongPtr, _ 
     ByVal Msg As LongPtr, _ 
     ByVal wParam As LongPtr, _ 
     ByVal lParam As LongPtr) As LongPtr 

Public Const GWL_WNDPROC = (-4) 
Private Const WM_MOVE = &H3 

Dim m_PrevProc As LongPtr 

Public Sub SubClass_On(ByVal hWnd As Long) 
    m_PrevProc = SetWindowLongPtr(hWnd, GWL_WNDPROC, AddressOf WindowProc) 
End Sub 

Public Sub SubClass_Off(ByVal hWnd As Long) 
    SetWindowLongPtr hWnd, GWL_WNDPROC, m_PrevProc 
End Sub 

Private Function WindowProc(ByVal hWnd As LongPtr, ByVal uMsg As LongPtr,  ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr 

    WindowProc = CallWindowProc(m_PrevProc, hWnd, uMsg, wParam, lParam) 

    If uMsg = WM_MOVE Then 

    Form_frm_main.Me_OnMove lParam And CLng(&HFFFF&), lParam \ CLng(&HFFFF&) 

    End If 

End Function 


' This code instead goes into the form module, starts subclassing on form loading and stop subclassing on form unload 

Private Sub Form_Load() 

    SubClass_On Me.hWnd 

End Sub 

Private Sub Form_Unload(Cancel As Integer) 

    SubClass_Off Me.hWnd 

End Sub 


Friend Sub Me_OnMove(ByVal xPos As Long, ByVal yPos As Long) 

    Me.Caption = "x=" & xPos & "; y=" & yPos 

End Sub 

...有關如何解決我的代碼的任何想法?或者對我的問題有其他建議嗎?

謝謝

+0

您的聲明是錯誤的,nIndex和Msg是長。 –

回答

1

我想我找到了解決我的問題! 我試圖重新創建一個帶Access窗體的MDI應用程序環境。我發現了一個API函數,可以將窗體的屬性設置爲子窗體。該函數是SetParent()。

如果您嘗試在任何訪問表單的Form_Open()事件中使用此函數,它會將該表單視爲任何其他指定表單的子表單。一旦設置了子屬性,Windows將自動將子窗體移動到屏幕上任何位置的主窗體中。效果非常好!

下面是一個例子。

聲明一個模塊

Public Declare PtrSafe Function SetParent Lib "user32" _ 
           (ByVal hWndChild As LongPtr, _ 
           ByVal hWndParent As LongPtr) As Long 

Public Declare PtrSafe Function SetWindowPos Lib "user32" _ 
           (ByVal hwnd As LongPtr, _ 
           ByVal hWndInsertAfter As LongPtr, _ 
           ByVal x As Long, _ 
           ByVal y As Long, _ 
           ByVal cx As Long, _ 
           ByVal cy As Long, _ 
           ByVal wFlags As Long) As Long 

注意我用的LongPtr因爲我在64位環境中工作在以下WinAPI的功能。 然後,在孩子form_open事件,使用下面的代碼

Private Sub Form_open(Cancel As Integer) 

    Dim hWndParent As LongPtr 
    Dim hWndChild As LongPtr 

    hWndParent = Form_frm_parent.hwnd 
    hWndChild = Form_frm_child.hwnd 

    SetParent hWndChild, hWndParent ' open the form as a child 

            ' this is used to position the form 
    SetWindowPos hWndChild, hWndParent, 163, 44, 725, 437, &H4 

End sub 

我只用彈出窗口的形式嘗試過,所以我不知道這是否與其他形式的作品,以及。但是,如果您將兩個表單(父級和子級)都設置爲彈出式窗體,則會看到Windows自動移動子窗體與父窗體。您還可以添加子表單的子項,它仍然可以很好地工作。

但是,一旦您將窗體聲明爲孩子,命令docmd.move會產生一些奇怪的效果。更好的方法是使用WinAPI函數SetWindowPos來定位您的子窗體。座標系將相對於父表單的位置。所以0,0座標是父窗體的左上角。

我發現使用函數GetWindowRect獲取父窗體的座標並設置子窗體的位置很有用。

Public Type RECT 
    wdw_left As Long 
    wdw_top As Long 
    wdw_right As Long 
    wdw_bottom As Long 
End Type 

Public Declare PtrSafe Function GetWindowRect Lib "user32" _ 
           (ByVal hwnd As LongPtr, _ 
           lpRect As RECT) As Long 

然後在子窗體

Dim hWndParent As LongPtr ' handle finestra 
Dim hWndChild As LongPtr ' handle finestra 
Dim mainRECT As RECT  ' coordinate form_home (struct RECT) 

hWndParent = Form_frm_parent.hwnd 
hWndChild = Form_frm_child.hwnd 

GetWindowRect hWndParent, mainRECT 

而且一旦你的主窗體的座標,你可以決定在哪裏放置你的孩子形式form_resize()事件。最後,如果您想根據父表單的大小動態調整子表單的位置,可以使用父表單的form_resize()事件調用子表單的form_resize()事件並更改它們的大小和位置。爲了做到這一點,子表單的form_resize()必須聲明爲public,那麼你可以從任何其他表單(我們的情況下的父表單)調用它。這樣,如果父窗體太小,可以將滾動條添加到子窗體。

我希望這可以幫助任何其他對此類解決方案感興趣的用戶。

乾杯

+0

有趣。你能否給你的答案增加一個例子,你如何使用API​​函數? – Andre

+0

嗨@Andre,我編輯了我的答案,並添加了一些代碼和解釋...我希望它有幫助! :) – Jashin