我有一个WTL应用程序,它使用具有ComboBoxEx32
样式的扩展组合框控件(Win32类CBS_DROPDOWNLIST
)。它运行良好(我可以对框中的每个项目都有图像)但键盘行为与普通组合框不同 - 按键不会跳转到以该字母开头的组合中的第一项。
例如,如果我将字符串'Arnold','Bob'和'Charlie'添加到组合中,如果我然后选择组合并按'B',则不会选择'Bob'。
有谁知道如何使这项工作?目前,我能想到的唯一想法是以某种方式将“实际”组合框子类化(我可以使用CBEM_GETCOMBOCONTROL
消息获取此处理)并处理WM_CHARTOITEM
。这是一个PITA所以我想我会问其他人是否曾经遇到过这个问题。
答案 0 :(得分:3)
最后,我连接了组合框控件(使用CBEM_GETCOMBOCONTROL
获得)并捕获了WM_CHARTOITEM
消息并执行了我自己的查找。如果其他人有兴趣,我可以发布代码。
答案 1 :(得分: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;
}
答案 2 :(得分:0)
我的建议是放弃CComboBoxEx并使用所有者绘制常规组合框绘制图标。 CComboBoxEx与'普通'组合框略有不同,但我认为它是一个完全重新实现的方式。请注意所选项目与普通组合框中选择的项目略有不同。
使用COwnerDraw mixin可以很容易地实现WTL中的所有者绘制控件。
不是你问题的答案,只是让你知道我现在如何处理CComboBoxEx:)
答案 3 :(得分:0)
在我们的应用程序中,您描述的键盘行为在版本之间丢失了。事实证明,我们删除了一个额外的清单依赖项,这导致依赖于旧版本的comctl32.dll(5.82)。这一行在项目设置中,配置属性 - &gt;链接器 - &gt;清单文件 - &gt;额外的清单依赖:
type ='win32'name ='Microsoft.Windows.Common-Controls'version ='6.0.0.0'processorArchitecture =''publicKeyToken ='6595b64144ccf1df'language =''
为我们修好了。
使用Dependency Walker,可以检查应用程序现在是否仅依赖于具有正确行为的comctl32.dll版本6.10。