如何子類別下拉式方塊
本主題示範如何子類別下拉式方塊。 C++ 範例應用程式會建立包含兩個下拉式方塊的工具列視窗。 藉由子類別化下拉式方塊內的編輯控件,工具列視窗會攔截將忽略的 TAB、ENTER 和 ESC 鍵。
您需要知道的事項
技術
必要條件
- C/C++
- Windows 使用者介面程序設計
指示
處理WM_CREATE訊息
應用程式會 處理WM_CREATE 訊息,以建立兩個下拉式方塊控件做為子視窗。
// Create two combo box child windows.
dwBaseUnits = GetDialogBaseUnits();
hwndCombo1 = CreateWindow(L"COMBOBOX", L"",
CBS_DROPDOWN | WS_CHILD | WS_VISIBLE,
(6 * LOWORD(dwBaseUnits)) / 4,
(2 * HIWORD(dwBaseUnits)) / 8,
(100 * LOWORD(dwBaseUnits)) / 4,
(50 * HIWORD(dwBaseUnits)) / 8,
hwnd, NULL, NULL, NULL);
hwndCombo2 = CreateWindow(L"COMBOBOX", L"",
CBS_DROPDOWN | WS_CHILD | WS_VISIBLE,
(112 * LOWORD(dwBaseUnits)) / 4,
(2 * HIWORD(dwBaseUnits)) / 8,
(100 * LOWORD(dwBaseUnits)) / 4,
(50 * HIWORD(dwBaseUnits)) / 8,
hwnd, NULL, hInst, NULL);
然後,應用程式會將每個下拉式方塊中的編輯控件(選取欄位)子類別化,因為它們會收到簡單下拉式下拉式方塊的字元輸入。 最後,它會呼叫 ChildWindowFromPoint 函式,以擷取每個編輯控件的句柄。
為了將編輯控件子類別化,應用程式會呼叫 SetWindowLong 函式,將類別視窗程式的指標取代為應用程式定義 之 SubClassProc 函式的指標。 原始視窗程式的指標會儲存在全域變數 lpfnEditWndProc 中。
SubClassProc 會攔截 TAB、ENTER 和 ESC 鍵,並傳送應用程式定義的訊息來通知工具列視窗(WM_TAB、WM_ESC和WM_ENTER)。 SubClassProc 會使用 CallWindowProc 函式,將大部分訊息傳遞至原始視窗程式 lpfnEditWndProc。
// Get the edit window handle to each combo box.
pt.x = 1;
pt.y = 1;
hwndEdit1 = ChildWindowFromPoint(hwndCombo1, pt);
hwndEdit2 = ChildWindowFromPoint(hwndCombo2, pt);
// Change the window procedure for both edit windows
// to the subclass procedure.
lpfnEditWndProc = (WNDPROC) SetWindowLongPtr(hwndEdit1,
GWLP_WNDPROC, (LONG_PTR) SubClassProc);
SetWindowLongPtr(hwndEdit2, GWLP_WNDPROC, (LONG_PTR) SubClassProc);
處理WM_SETFOCUS訊息
當工具列視窗收到輸入焦點時,它會立即將焦點設定為工具列中的第一個下拉式方塊。 若要這樣做,此範例會呼叫 SetFocus 函式,以回應WM_SETFOCUS訊息。
case WM_SETFOCUS:
SetFocus(hwndCombo1);
break;
處理應用程式定義的訊息
當使用者按下下拉式方塊中的 TAB 鍵、ENTER 或 ESC 鍵時,SubClassProc 函式會將應用程式定義的訊息傳送至工具欄視窗。 WM_TAB訊息會傳送給 TAB 鍵、ESC 鍵的WM_ESC訊息,以及 ENTER 鍵的WM_ENTER訊息。
此範例會將 焦點設定為工具列中的下一個下拉式方塊,以處理WM_TAB 訊息。 它會將 焦點設定為主要應用程式視窗,以處理WM_ESC 訊息。
case WM_TAB:
if (GetFocus() == hwndEdit1)
SetFocus(hwndCombo2);
else
SetFocus(hwndCombo1);
break;
case WM_ESC:
hwndCombo = GetFocus() == hwndEdit1 ? hwndCombo1 : hwndCombo2;
// Clear the current selection.
SendMessage(hwndCombo, CB_SETCURSEL,
(WPARAM) (-1), 0);
// Set the focus to the main window.
SetFocus(hwndMain);
break;
為了回應 WM_ENTER 訊息,此範例可確保下拉式方塊目前的選取範圍有效,然後將焦點設定為主應用程式視窗。 如果下拉式方塊不包含目前的選取範圍,此範例會使用 CB_FINDSTRINGEXACT 訊息來搜尋符合選取範圍欄位內容的清單專案。 如果有相符專案,此範例會設定目前的選取範圍;否則,它會加入新的清單專案。
case WM_ENTER:
hwndCombo = GetFocus() == hwndEdit1 ? hwndCombo1 : hwndCombo2;
SetFocus(hwndMain);
// If there is no current selection, set one.
if (SendMessage(hwndCombo, CB_GETCURSEL, 0, 0)
== CB_ERR)
{
if (SendMessage(hwndCombo, WM_GETTEXT,
sizeof(achTemp), (LPARAM) achTemp) == 0)
break; // Empty selection field
dwIndex = SendMessage(hwndCombo,
CB_FINDSTRINGEXACT, (WPARAM) (-1),
(LPARAM) achTemp);
// Add the string, if necessary, and select it.
if (dwIndex == CB_ERR)
dwIndex = SendMessage(hwndCombo, CB_ADDSTRING,
0, (LPARAM) achTemp);
if (dwIndex != CB_ERR)
SendMessage(hwndCombo, CB_SETCURSEL,
dwIndex, 0);
}
break;
// .
// . Process additional messages.
// .
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
完整範例
以下是工具列的視窗程式,以及兩個下拉式方塊的子類別程式。
#define WM_TAB (WM_USER)
#define WM_ESC (WM_USER + 1)
#define WM_ENTER (WM_USER + 2)
// Global variables
HWND hwndMain;
WNDPROC lpfnEditWndProc; // Original wndproc for the combo box
// Prototypes
LRESULT CALLBACK SubClassProc( HWND, UINT, WPARAM, LPARAM );
/********************************************************
FUNCTION: ToolbarWindowProc
PURPOSE: Window procedure for the toolbar window
*********************************************************/
LRESULT CALLBACK ToolbarWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND hwndEdit1;
static HWND hwndEdit2;
static HWND hwndCombo1;
static HWND hwndCombo2;
POINT pt;
DWORD dwBaseUnits;
HWND hwndCombo;
DWORD dwIndex;
char achTemp[256]; // Temporary buffer
switch (msg)
{
case WM_CREATE:
// Create two combo box child windows.
dwBaseUnits = GetDialogBaseUnits();
hwndCombo1 = CreateWindow(L"COMBOBOX", L"",
CBS_DROPDOWN | WS_CHILD | WS_VISIBLE,
(6 * LOWORD(dwBaseUnits)) / 4,
(2 * HIWORD(dwBaseUnits)) / 8,
(100 * LOWORD(dwBaseUnits)) / 4,
(50 * HIWORD(dwBaseUnits)) / 8,
hwnd, NULL, NULL, NULL);
hwndCombo2 = CreateWindow(L"COMBOBOX", L"",
CBS_DROPDOWN | WS_CHILD | WS_VISIBLE,
(112 * LOWORD(dwBaseUnits)) / 4,
(2 * HIWORD(dwBaseUnits)) / 8,
(100 * LOWORD(dwBaseUnits)) / 4,
(50 * HIWORD(dwBaseUnits)) / 8,
hwnd, NULL, hInst, NULL);
// Get the edit window handle to each combo box.
pt.x = 1;
pt.y = 1;
hwndEdit1 = ChildWindowFromPoint(hwndCombo1, pt);
hwndEdit2 = ChildWindowFromPoint(hwndCombo2, pt);
// Change the window procedure for both edit windows
// to the subclass procedure.
lpfnEditWndProc = (WNDPROC) SetWindowLongPtr(hwndEdit1,
GWLP_WNDPROC, (LONG_PTR) SubClassProc);
SetWindowLongPtr(hwndEdit2, GWLP_WNDPROC, (LONG_PTR) SubClassProc);
break;
case WM_SETFOCUS:
SetFocus(hwndCombo1);
break;
case WM_TAB:
if (GetFocus() == hwndEdit1)
SetFocus(hwndCombo2);
else
SetFocus(hwndCombo1);
break;
case WM_ESC:
hwndCombo = GetFocus() == hwndEdit1 ? hwndCombo1 : hwndCombo2;
// Clear the current selection.
SendMessage(hwndCombo, CB_SETCURSEL,
(WPARAM) (-1), 0);
// Set the focus to the main window.
SetFocus(hwndMain);
break;
case WM_ENTER:
hwndCombo = GetFocus() == hwndEdit1 ? hwndCombo1 : hwndCombo2;
SetFocus(hwndMain);
// If there is no current selection, set one.
if (SendMessage(hwndCombo, CB_GETCURSEL, 0, 0)
== CB_ERR)
{
if (SendMessage(hwndCombo, WM_GETTEXT,
sizeof(achTemp), (LPARAM) achTemp) == 0)
break; // Empty selection field
dwIndex = SendMessage(hwndCombo,
CB_FINDSTRINGEXACT, (WPARAM) (-1),
(LPARAM) achTemp);
// Add the string, if necessary, and select it.
if (dwIndex == CB_ERR)
dwIndex = SendMessage(hwndCombo, CB_ADDSTRING,
0, (LPARAM) achTemp);
if (dwIndex != CB_ERR)
SendMessage(hwndCombo, CB_SETCURSEL,
dwIndex, 0);
}
break;
// .
// . Process additional messages.
// .
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
/********************************************************
FUNCTION: SubClassProc
PURPOSE: Process TAB and ESCAPE keys, and pass all
other messages to the class window
procedure.
*********************************************************/
LRESULT CALLBACK SubClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_KEYDOWN:
switch (wParam)
{
case VK_TAB:
SendMessage(hwndMain, WM_TAB, 0, 0);
return 0;
case VK_ESCAPE:
SendMessage(hwndMain, WM_ESC, 0, 0);
return 0;
case VK_RETURN:
SendMessage(hwndMain, WM_ENTER, 0, 0);
return 0;
}
break;
case WM_KEYUP:
case WM_CHAR:
switch (wParam)
{
case VK_TAB:
case VK_ESCAPE:
case VK_RETURN:
return 0;
}
}
// Call the original window procedure for default processing.
return CallWindowProc(lpfnEditWndProc, hwnd, msg, wParam, lParam);
}
相關主題