ListBoxを使ってみる

ListBoxの使い方を勉強する.


ListBoxの項目を選択すると選択したものがStaticTextに反映されるっていうものを作る.

コード

typedef struct Window_ {
  int id;
  HWND handle;
} Window;

INT_PTR CALLBACK Dialog1Proc(HWND hDlg, UINT message,
			     WPARAM wParam, LPARAM lParam)
{
  UNREFERENCED_PARAMETER(lParam);
  static Window selection, selected;
  BOOL inited = FALSE;

  switch (message) {
  case WM_INITDIALOG:
    if (inited != TRUE) {  /* 初期化 */
      TCHAR items[][16] = { TEXT("C"), TEXT("C++"), TEXT("Perl"), TEXT("Python"),
			 TEXT("Ruby"), TEXT("Java"), TEXT("Javascript") };
      int i, items_len = sizeof (items) / sizeof(items[0]);
      selection.id = IDC_SELECTIONS_LIST;
      selection.handle = GetDlgItem(hDlg, selection.id);
      selected.id = IDC_SELECTED_ITEM_LABEL;
      selected.handle = GetDlgItem(hDlg, IDC_SELECTED_ITEM_LABEL);
      for (i = 0; i < items_len; i++) {  /* ListBoxの初期化 */
	SendMessage(selection.handle, LB_ADDSTRING, 0, (LPARAM) items[i]);
      }
      /* デフォルトの選択としてListBoxの0番目を選択 */
      SendMessage(selection.handle, LB_SETCURSEL, 0, 0);
    }
    return (INT_PTR)TRUE;
  case WM_COMMAND:
    switch (LOWORD(wParam)) {
    case IDC_SELECTIONS_LIST:  /* ListBoxにメッセージがとんできた */
      switch (HIWORD(wParam)) {
      case LBN_SELCHANGE:  /* ListBoxの選択が変化したよ(>_<) */
	LPTSTR t;
	int t_len, i;
	i = (int) SendMessage(selection.handle, LB_GETCURSEL, 0, 0);
	t_len = (int) SendMessage(selection.handle, LB_GETTEXTLEN, i, 0);
	t = (LPTSTR) calloc(sizeof(t[0]), t_len + 1);
	if (t == NULL) {
	  return FALSE;
	}
	SendMessage(selection.handle, LB_GETTEXT, i, (LPARAM) t);
	SetWindowText(selected.handle, t);
        free(t);
	break;
      }
      break;
    case IDOK:
    case IDCANCEL:
      PostQuitMessage(0);
      // return (INT_PTR)TRUE;
    }
    break;
  case WM_DESTROY:
    PostQuitMessage(0);
    break;
  }
  return (INT_PTR)FALSE;
}

実行結果

初期状態

f:id:kei10in:20080416015133j:image
"スタティック"のままになってる。+゚・(ノロ`)・゚+。
Cってなってほしい

Pythonを選択したよ

f:id:kei10in:20080416014124j:image
(*'ω')b

"スタティック"のままの原因

デフォルト項目への選択時にLBN_SELCHANGEが送られていないのが原因.
LBS_NOTIFYを設定してあるListBoxだと,マウスとかキーボードでListBoxの項目を選択したときには親ウィンドウにWM_COMMANDでLBN_SELCHANGEが送られる.
でも,LB_SETSELCHANGEしたときには送ってくれないから自分で送らなきゃいけない.


ということで初期化部分を修正

  case WM_INITDIALOG:
    if (inited != TRUE) {  /* 初期化 */
      TCHAR items[][16] = { TEXT("C"), TEXT("C++"), TEXT("Perl"), TEXT("Python"),
			 TEXT("Ruby"), TEXT("Java"), TEXT("Javascript") };
      int i, items_len = sizeof (items) / sizeof(items[0]);
      selection.id = IDC_SELECTIONS_LIST;
      selection.handle = GetDlgItem(hDlg, selection.id);
      selected.id = IDC_SELECTED_ITEM_LABEL;
      selected.handle = GetDlgItem(hDlg, IDC_SELECTED_ITEM_LABEL);
      for (i = 0; i < items_len; i++) {  /* ListBoxの初期化 */
	SendMessage(selection.handle, LB_ADDSTRING, 0, (LPARAM) items[i]);
      }
      /* デフォルトの選択としてListBoxの0番目を選択 */
      SendMessage(selection.handle, LB_SETCURSEL, 0, 0);
      /* ここを追加だよ(>_<) */
      SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(selection.id, LBN_SELCHANGE), 0);
    }
    return (INT_PTR)TRUE;

実行結果

f:id:kei10in:20080416020047j:image
できてるヽ(´ー`)ノ

まとめ

  • LB_SELCHANGEしたときにはLBN_SELCHANGEを送ってくれない
  • LBN_SELCHANGEの送り方は
    SendMessage(parantDlg, WM_COMMAND, MAKEPARAM(LISTID, LBN_SELCHANGE), 0);
  • WPARAMは MAKEWPARAM(下位,上位); でつくる.