2010-01-14 30 views
4

我有一個使用擴展組合框控件(Win32類ComboBoxEx32)和CBS_DROPDOWNLIST樣式的WTL應用程序。它運作良好(我可以在盒子中的每個項目上都有圖像),但鍵盤的行爲與普通的組合框不同 - 按下某個鍵不會跳轉到以該字母開頭的組合中的第一個項目。例如,如果我將字符串'Arnold','Bob'和'Charlie'添加到組合中,如果我然後選擇組合並按'B',那麼將不會選擇'Bob'。ComboBoxEx32(CComboBoxEx)鍵盤行爲

有誰知道如何使這項工作?目前我能想到的唯一想法是以某種方式將「實際」組合框(我可以通過使用CBEM_GETCOMBOCONTROL消息獲得句柄)和過程WM_CHARTOITEM進行子類化。這是PITA,所以我想我會問是否有其他人遇到過這個問題。

回答

3

在我迷上ComboBox控件(與CBEM_GETCOMBOCONTROL獲得)結束,被困WM_CHARTOITEM消息,並執行我自己擡頭。如果其他人感興趣,我可以發佈代碼。

0

我的建議是溝CComboBoxEx並繪製圖標與所有者繪製常規組合框。 CComboBoxEx與「普通」組合框略有不同,但我認爲這是一個完整的重新實現。請注意,選定的項目與正常組合框中選擇的項目看起來略有不同。

WTL中的所有者繪製控件很容易與COwnerDraw mixin一起實現。

不回答你的問題,只是讓你知道,這就是我如何處理CComboBoxEx時下:)

1

我創建了一個工作的解決方案,並希望分享的是:

ComboBoxExKeyboardSupport.h

#pragma once 

class CComboBoxExKeyboardSupport 
{ 
// Construction 
public: 
    CComboBoxExKeyboardSupport(void); 
    ~CComboBoxExKeyboardSupport(void); 

// Attributes 
private: 
    static CSimpleMap<HWND, CComboBoxExKeyboardSupport*> responsibleMap; 

    HWND hComboBoxHwnd; 
    WNDPROC fpOriginalWndProc; 

// Operations 
private: 
    static LRESULT CALLBACK StaticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 
    LRESULT WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 
    LRESULT HandleCharToItemMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 

    bool IsWindowsXPPlatform(void); 
    bool InputMatches(CString inputChar, CString& itemText); 

public: 
    void Attach(CComboBoxEx& comboBoxEx); 
    void Detach(void); 
}; 

ComboBoxExKeyboardSupport.cpp

#include "StdAfx.h" 
#include "ComboBoxExKeyboardSupport.h" 

// Static member 
CSimpleMap<HWND, CComboBoxExKeyboardSupport*> CComboBoxExKeyboardSupport::responsibleMap; 

CComboBoxExKeyboardSupport::CComboBoxExKeyboardSupport(void) 
{ 
    hComboBoxHwnd = nullptr; 
    fpOriginalWndProc = nullptr; 
} 

CComboBoxExKeyboardSupport::~CComboBoxExKeyboardSupport(void) 
{ 
    Detach(); 
} 

void CComboBoxExKeyboardSupport::Attach(CComboBoxEx& comboBoxEx) 
{ 
    ATLASSERT(hComboBoxHwnd == nullptr); 
    if(hComboBoxHwnd != nullptr) 
     return; 

    if(!IsWindowsXPPlatform()) 
     return; 

    LONG_PTR lpNewWndProc = reinterpret_cast<LONG_PTR>(StaticWndProc); 
    LONG_PTR lpOldWndProc = 0; 

    //---- 
    hComboBoxHwnd = comboBoxEx.GetComboBoxCtrl()->GetSafeHwnd(); 
    ATLASSERT(hComboBoxHwnd != nullptr); 

    // Exchange the WndProc 
    lpOldWndProc = SetWindowLongPtr(hComboBoxHwnd, GWLP_WNDPROC, lpNewWndProc); 
    ATLASSERT(lpOldWndProc != 0); 
    fpOriginalWndProc = reinterpret_cast<WNDPROC>(lpOldWndProc); 

    // Remember the handle and the old WndProc 
    responsibleMap.Add(hComboBoxHwnd, this); 
} 

void CComboBoxExKeyboardSupport::Detach(void) 
{ 
    if(hComboBoxHwnd == nullptr) 
     return; 

    //---- 
    LONG_PTR lpResult = 0; 

    // Reset original WndProc 
    lpResult = SetWindowLongPtr(hComboBoxHwnd, GWLP_WNDPROC, 
     reinterpret_cast<LONG_PTR>(fpOriginalWndProc)); 
    ATLASSERT(lpResult != 0); 

    // Remove handle and WndProc from map 
    responsibleMap.Remove(hComboBoxHwnd); 

    //---- 
    hComboBoxHwnd = nullptr; 
    fpOriginalWndProc = nullptr; 
} 

bool CComboBoxExKeyboardSupport::IsWindowsXPPlatform(void) 
{ 
    OSVERSIONINFO osvi = {0}; 
    bool bResult = false; 

    //---- 
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 
    if(GetVersionEx(&osvi)) 
    { 
     // 5.1 = Windows XP 
     // 5.2 = Windows Server 2003, Windows Server 2003 R2 
     bResult = (osvi.dwMajorVersion == 5 && 
      (osvi.dwMinorVersion == 1 || osvi.dwMinorVersion == 2)); 
    } 

    return bResult; 
} 

LRESULT CComboBoxExKeyboardSupport::StaticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    CComboBoxExKeyboardSupport* pResponsibleClass = nullptr; 

    // Get responsible class from map 
    pResponsibleClass = responsibleMap.Lookup(hwnd); 
    ATLASSERT(pResponsibleClass != nullptr); 

    //---- 
    return pResponsibleClass->WndProc(hwnd, uMsg, wParam, lParam); 
} 

LRESULT CComboBoxExKeyboardSupport::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    // Save originalWndProc because after WM_DESTROY/Detach the member variable is nullptr. 
    WNDPROC fpOriginalWndProc = this->fpOriginalWndProc; 

    //---- 
    if(uMsg == WM_DESTROY) 
    { 
     Detach(); 
    } 
    else if(uMsg == WM_CHARTOITEM) 
    { 
     return HandleCharToItemMessage(hwnd, uMsg, wParam, lParam); 
    } 

    //---- 
    return ::CallWindowProc(fpOriginalWndProc, hwnd, uMsg, wParam, lParam); 
} 

LRESULT CComboBoxExKeyboardSupport::HandleCharToItemMessage(
    HWND hwnd, 
    UINT uMsg, 
    WPARAM wParam, 
    LPARAM lParam) 
{ 
    //---- 
    LRESULT lResult = CB_ERR; 
    CComboBox* pComboBox = nullptr; 
    int itemCount = 0; 
    int itemSelected = 0; 
    CString itemText; 
    TCHAR inputCharacter = 0; 

    //---- 
    pComboBox = (CComboBox*)CComboBox::FromHandle(hwnd); 

    //---- 
    itemCount = pComboBox->GetCount(); 
    itemSelected = pComboBox->GetCurSel(); 
    inputCharacter = static_cast<TCHAR>(LOWORD(wParam)); 

    // Search from the current selected item plus one to the end 
    for(int i = (itemSelected + 1); i < itemCount; i++) 
    { 
     pComboBox->GetLBText(i, itemText); 
     if(InputMatches(inputCharacter, itemText)) 
     { 
      lResult = i; 
      break; 
     } 
    } 

    if(lResult == CB_ERR) 
    { 
     // Search from the beginning to the selected item minus one. 
     for(int i = 0; i < itemSelected; i++) 
     { 
      pComboBox->GetLBText(i, itemText); 
      if(InputMatches(inputCharacter, itemText)) 
      { 
       lResult = i; 
       break; 
      } 
     } 
    } 

    //---- 
    return lResult; 
} 

bool CComboBoxExKeyboardSupport::InputMatches(CString inputChar, CString& itemText) 
{ 
    CString firstCharString; 
    bool bInputMatches = false; 

    //---- 
    firstCharString = itemText; 
    firstCharString.Left(1); 

    //---- 
    bInputMatches = firstCharString.CompareNoCase(inputChar) == 0; 

    //---- 
    return bInputMatches; 
} 
0

在我們的應用程序,您所描述的鍵盤行爲迷路了版本之間。事實證明,我們刪除了一個額外的清單依賴項,導致依賴於舊版本的comctl32.dll(5.82)。此行在項目設置中,配置屬性 - >鏈接器 - >清單文件 - >其他清單相關性:

type ='win32'name ='Microsoft.Windows.Common-Controls'version ='6.0.0.0'processorArchitecture =''publicKeyToken ='6595b64144ccf1df'language =''

爲我們修復了它。

使用Dependency Walker,可以檢查應用程序現在是否僅依賴於具有正確行爲的comctl32.dll 6.10版。