CListBox などのオーナードロー
リストスクロール時,動作が逆に見える現象の調査のため調べたこと.
WinCore.cpp CWnd::OnMeasureItem での CtlType の値
/* * Owner draw control types */ #define ODT_MENU 1 #define ODT_LISTBOX 2 #define ODT_COMBOBOX 3 #define ODT_BUTTON 4 #if(WINVER >= 0x0400) #define ODT_STATIC 5 #endif /* WINVER >= 0x0400 */
/* * Listbox Styles */ #define LBS_NOTIFY 0x0001L #define LBS_SORT 0x0002L #define LBS_NOREDRAW 0x0004L #define LBS_MULTIPLESEL 0x0008L #define LBS_OWNERDRAWFIXED 0x0010L #define LBS_OWNERDRAWVARIABLE 0x0020L #define LBS_HASSTRINGS 0x0040L #define LBS_USETABSTOPS 0x0080L #define LBS_NOINTEGRALHEIGHT 0x0100L #define LBS_MULTICOLUMN 0x0200L #define LBS_WANTKEYBOARDINPUT 0x0400L #define LBS_EXTENDEDSEL 0x0800L #define LBS_DISABLENOSCROLL 0x1000L #define LBS_NODATA 0x2000L #if(WINVER >= 0x0400) #define LBS_NOSEL 0x4000L #endif /* WINVER >= 0x0400 */ #define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER)
// Measure item implementation relies on unique control/menu IDs void CWnd::OnMeasureItem(int /*nIDCtl*/, LPMEASUREITEMSTRUCT lpMeasureItemStruct) { if (lpMeasureItemStruct->CtlType == ODT_MENU) { // ... } else { CWnd* pChild = GetDescendantWindow(lpMeasureItemStruct->CtlID, TRUE); if (pChild != NULL && pChild->SendChildNotifyLastMsg()) return; // eaten by child } // not handled - do default Default(); }
GetDescendantWindow で求めた pChild が NULL のため CListBox::OnChildNotify から MeasureItem が呼ばれない?
呼ばれた時の lpMeasureItemStruct->itemHeight は,ODT_LISTBOX は 18 ,ODT_COMBOBOX は 20 .
デバッガで高さを設定すると,その高さになる.
OWNERDRAWVARIABLE は項目ごとに呼ばれるが,OWNERDRAWFIXED の時はうまくない?
結局,VC 6 などの場合にそうなる(逆にスクロール)様子.
コモンコントロール Ver.6 を使う様にすることで回避できる.
VC 6 exe などの場合は (VC6_app).exe.manifest ファイルを用意する.
視覚スタイルを有効にする