duilib 滾動條不能拖動 問題處理
遇到過很多次群裡朋友問:為什麼滾動條不能拖動,點選兩端的按鈕可以滾動,通過滑鼠滾輪也可以滾動,就是滑鼠拖動時拖不動?
這是個提問次數較高的問題。
下面的內容只針對可能的原因中的一個,也是最可能的原因。
因為通過滑鼠拖動滾動條,實際內部用到了定時器,具體有興趣的可以檢視duilib的原始碼。我們的程式在處理時常常也會用到WM_TIMER訊息,通過攔截WM_TIMER訊息來做一些定時器處理,不能拖動的原因很有可能就是我們攔截了定時器訊息之後,不管觸發這個訊息的定時器ID是多少,我們統統都不再繼續傳遞給duilib內部處理了。這樣就造成了無法拖動。
下面我們來簡單看下程式碼流程:
LRESULT CMainWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lRes = 0; BOOL bHandled = TRUE; switch( uMsg ) { case WM_CREATE: lRes = OnCreate(uMsg, wParam, lParam, bHandled); break; case WM_NCHITTEST: lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break; case WM_SYSCOMMAND: lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break; case WM_TIMER: lRes = OnTimer(uMsg, wParam, lParam, bHandled); break; case WM_KEYDOWN: { if (wParam == VK_ESCAPE) { Close(); } else bHandled = FALSE; } default: bHandled = FALSE; } if( bHandled ) return lRes; if( m_PM.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes; return CWindowWnd::HandleMessage(uMsg, wParam, lParam); }
上面是一個常見的HandleMessage的過程(其他的訊息攔截函式類似),在這裡面我們攔截了WM_TIMER,這樣的話,如果不去設定bHandled的值,那他因為無法走default的處理而自然變為TRUE,這樣在switch的下面,可以看到:if(bHandled) return lRes;當bHandled為true時,本次處理就返回了,並沒有繼續給m_PM.MessageHandler和CWindowWnd::HandleMessage去繼續處理此訊息的機會,相當於WM_TIMER徹底攔截了,那麼其他在你這個HandleMessage之後才有機會處理訊息的地方,都因為無法收到此訊息而再無機會處理了。
此時該怎麼辦?
很簡單,針對定時器ID,根據需求攔截就行了。在OnTimer裡面,凡是自己用到的定時器ID,又不想讓它在其他地方也可能被處理,此時在將bHandled置為TRUE,其他時候都置為FALSE就好了。
LRESULT CMainWnd::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (wParam == TIMER_ID_MYUSE)
{
//do
OutputDebugString(_T("自己用的定時器"));
bHandled = TRUE;
}
else
bHandled = FALSE;
return 0;
}
另一個原因:滾動條上層可能有其他控制元件,把滾動條蓋住了,上層控制元件不設定背景,介面上直接看不出來,但是會影響滑鼠的事件響應。