リストボックス2
リストボックスの基本的な操作は前ページを参照してください。
リストボックスのスタイル
リストボックスには以下のスタイルが指定できます。
定数 | 説明 |
---|---|
LBS_NOTIFY | LBN_SELCHANGE 、LBN_DBLCLK 、LBN_SELCANCEL 通知コードを親ウィンドウに通知する。 |
LBS_SORT | アイテムをアルファベット順に自動で並べ替える。 ただし LB_INSERTSTRING で追加したアイテムの並べ替えは行わない。 |
LBS_NOREDRAW | リストボックスへの変更を画面に反映しない。 反映させるには WM_SETREDRAW メッセージを送信する。 |
LBS_MULTIPLESEL | アイテムを複数選択可能にする。 アイテムをクリックする度に選択状態が切り替わる。 |
LBS_USETABSTOPS | タブ文字を展開する。 |
LBS_NOINTEGRALHEIGHT | リストボックスのサイズをCreateWindow関数の引数通りに作成する。 このスタイルを指定しない場合、高さが足りないために一部しか表示できないアイテムが発生しないようにシステムがリストボックスのサイズを調整する。 |
LBS_MULTICOLUMN | 複数列のリストボックスを作成する。 リストは水平にスクロールし、 WM_VSCROLL メッセージを無視する。 |
LBS_WANTKEYBOARDINPUT | リストボックスがフォーカスを持っているとき、キー入力に対して親ウィンドウにWM_VKEYTOITEM メッセージを送信する。 |
LBS_EXTENDEDSEL | ShiftキーまたはCtrlキーとマウスクリックの組み合わせ、またはマウスドラッグにより、複数項目の選択を可能にする。 |
LBS_DISABLENOSCROLL | 項目数にかかわらずスクロールバーを常に表示する。 (自動で非表示にしない) WS_VSCROLL またはWS_HSCROLL スタイルと同時に使用する。 |
LBS_NODATA | データを持てないリストボックスを作成する。 |
LBS_NOSEL | 項目を選択できないリストボックスを作成する。 |
LBS_STANDARD | LBS_NOTIFY 、LBS_SORT 、WS_VSCROLL 、WS_BORDER スタイルの組み合わせ |
LBS_OWNERDRAWFIXED | オーナードローリストボックスコントロール。 コントロール内の描画をプログラマ自身が行う。 |
LBS_OWNERDRAWVARIABLE | オーナードローリストボックスコントロール。 コントロール内の描画をプログラマ自身が行う。 |
LBS_HASSTRINGS | アイテムに文字列が含まれている。 オーナードローリストボックスコントロールで使用する。 それ以外ではこのフラグは既定でオン。 |
通知コード
リストボックスを操作するとWM_COMMAND
メッセージが発行され、WPARAMの上位ワードには以下の通知コードが格納されます。
通知コード | 説明 |
---|---|
LBN_SELCHANGE | アイテムの選択状態が変更されたとき |
LBN_DBLCLK | アイテムをダブルクリックしたとき |
LBN_SELCANCEL | アイテムの選択をキャンセルしたとき |
LBN_SETFOCUS | フォーカスを得たとき |
LBN_KILLFOCUS | フォーカスを失ったとき |
LBN_ERRSPACE | メモリ不足エラー |
太字で示している通知コードは既定では通知されません。
これらを受け取るにはウィンドウスタイルにLBS_NOTIFY
を指定します。
CreateWindowEx(
WS_EX_CLIENTEDGE,
L"LISTBOX", NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY,
10, 10, 100, 100,
hWnd, (HMENU)IDC_LIST1, hInst, NULL);
LBN_SELCHANGE
はユーザーの操作時に発生します。
プログラムからSendMessage関数で選択状態を変更したときなどには発生しません。
複数のアイテムの同時選択
リストボックスは標準ではひとつのアイテムしか選択状態にすることができません。
複数同時に選択できるリストボックスを作成するにはLBS_MULTIPLESEL
スタイルを追加します。
CreateWindowEx(
WS_EX_CLIENTEDGE,
L"LISTBOX", NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_MULTIPLESEL,
10, 10, 100, 100,
hWnd, (HMENU)IDC_LIST1, hInst, NULL);
このスタイルで作成されたリストボックスはアイテムを選択するごとに選択状態と非選択状態が切り替わります。
もしくはLBS_EXTENDEDSEL
スタイルでも複数項目の選択が可能になります。
こちらはCtrlキーやShiftキーを押しながらマウスクリック、またはマウスドラッグで複数項目を選択します。
Windowsエクスプローラーに近い操作方法です。
なお、複数同時に選択状態にできるため、例えばLB_GETCURSEL
などのメッセージでは正しく選択中のアイテム番号を取得することができません。
複数選択可能なスタイルではLB_GETSEL、LB_SETSELなどを使用します。
リストボックスのメッセージ
リストボックスは以下のメッセージを使用して操作します。
メッセージ | WPARAM | LPARAM | 戻り値 |
---|---|---|---|
LB_ADDSTRING | 0 | 追加する文字列 | 追加された位置を示すインデックス エラー発生時は LB_ERR またはLB_ERRSPACE (負数) |
末尾にアイテムを追加する。 | |||
LB_INSERTSTRING | インデックス | 追加する文字列 | 追加された位置を示すインデックス エラー発生時は LB_ERR またはLB_ERRSPACE |
インデックスを指定してアイテムを追加する。 インデックスに「-1」を指定すると末尾に追加される。 LBS_SORT スタイルを持つリストボックスでも並べ替えは行われない。 |
|||
LB_DELETESTRING | インデックス | 0 | 残りのアイテム数 存在しないインデックスを指定した場合は LB_ERR |
インデックスで指定したアイテムを削除する。 | |||
LB_RESETCONTENT | 0 | 0 | なし |
全てのアイテムを削除する。 | |||
LB_GETCOUNT | 0 | 0 | アイテム数 エラーが発生した場合は LB_ERR |
リストボックス内のアイテム数を取得する。 | |||
メッセージ | WPARAM | LPARAM | 戻り値 |
LB_SETSEL | TRUE :選択FALSE :選択解除 |
インデックス -1を指定するとすべてのアイテムに対して設定する |
エラーが発生した場合はLB_ERR |
インデックスで指定したアイテムの選択状態を設定する。 | |||
LB_SETCURSEL | インデックス | 0 | WPARAMが-1の場合、またはエラーが発生した場合はLB_ERR |
インデックスで指定したアイテムを選択する。 単一選択のリストボックスで有効。 |
|||
LB_GETSEL | インデックス | 0 | アイテムが選択状態ならば0以上を返す 非選択状態なら0を返す エラーが発生した場合は LB_ERR |
インデックスで指定したアイテムの選択状態を取得する。 | |||
LB_GETCURSEL | 0 | 0 | 現在選択されているアイテムのインデックス 選択アイテムがない場合は LB_ERR |
現在選択されているアイテムのインデックスを取得する。 単一選択のリストボックスで有効。 |
|||
LB_SELITEMRANGE | TRUE :選択FALSE :選択解除 |
下位ワード:選択する最初のアイテムのインデックス 上位ワード:選択する最後のアイテムのインデックス |
エラーが発生した場合はLB_ERR |
範囲を指定してアイテムの選択状態を設定する。 LPARAMはMAKELPARAMマクロで作成する。 |
|||
LB_SELITEMRANGEEX | 選択する最初のアイテムのインデックス | 選択する最後のアイテムのインデックス | エラーが発生した場合はLB_ERR |
範囲を指定してアイテムの選択状態を設定する。 WPARAMがLPARAMより小さいときは、アイテムが選択される。 WPARAMがLPARAMより大きいときは、アイテムが選択解除される。 |
|||
LB_SETANCHORINDEX | インデックス | 0 | 成功した場合は0 失敗した場合は LB_ERR |
アンカーとなるアイテムを設定する。 アンカーとは複数選択の起点となる項目のこと。 |
|||
LB_GETANCHORINDEX | 0 | 0 | インデックス |
アンカーとなるアイテムのインデックスを取得する。 | |||
LB_SETCARETINDEX | インデックス | TRUE :アイテムが一部でも表示されるようにスクロールFALSE :アイテムが完全に表示されるようにスクロール |
LB_OKAY (0)エラーが発生した場合は LB_ERR |
インデックスで指定したアイテムにフォーカスをセットし、アイテムが表示されるようにスクロールする。
単一選択リストボックスでは、現在選択されているアイテムがない場合はインデックスのアイテムにフォーカスがセットされる。 |
|||
LB_GETCARETINDEX | 0 | 0 | インデックス |
フォーカスを持つアイテムのインデックスを取得する。 単一選択リストボックスでは、現在選択されているアイテムのインデックスを取得する。 |
|||
LB_SELECTSTRING | 検索を開始するインデックス | 検索する文字列 | 見つかったアイテムのインデックス 見つからなかった場合は LB_ERR |
指定の文字列から始まるアイテムを検索し、選択状態にする。
検索はWPARAMで指定したインデックスから開始され、最後のアイテムに達すると最初のアイテムに戻り、WPARAMで指定したインデックスまで検索が続行される。 |
|||
LB_FINDSTRING | 検索を開始するインデックス | 検索する文字列 | 見つかったアイテムのインデックス 見つからなかった場合は LB_ERR |
指定の文字列から始まるアイテムを検索する。
検索はWPARAMで指定したインデックスから開始され、最後のアイテムに達すると最初のアイテムに戻り、WPARAMで指定したインデックスまで検索が続行される。 |
|||
LB_FINDSTRINGEXACT | 検索を開始するインデックス | 検索する文字列 | 見つかったアイテムのインデックス 見つからなかった場合は LB_ERR |
指定の文字列と一致するアイテムを検索する。
検索はWPARAMで指定したインデックスから開始され、最後のアイテムに達すると最初のアイテムに戻り、WPARAMで指定したインデックスまで検索が続行される。 |
|||
LB_GETSELCOUNT | 0 | 0 | 選択中のアイテムの数 単一選択リストボックスで使用した場合は LB_ERR |
選択中のアイテムの数を取得する。 単一選択リストボックスでは使用できない。 |
|||
LB_GETSELITEMS | 取得するアイテムの最大数 | 整数値を格納するバッファ | 取得したアイテムの数 単一選択リストボックスで使用した場合は LB_ERR |
選択中のアイテムのインデックスを全て取得し、バッファ(配列)に格納する。 単一選択リストボックスでは使用できない。 |
|||
LB_GETTOPINDEX | 0 | 一番上に表示中のアイテムのインデックス | |
現在表示されている中で一番上にあるアイテムのインデックスを取得する。 | |||
LB_SETTOPINDEX | インデックス | 0 | エラー発生時はLB_ERR |
インデックスで指定したアイテムができるだけ上部に表示されるようにスクロールする | |||
メッセージ | WPARAM | LPARAM | 戻り値 |
LB_GETTEXT | インデックス | 文字列を格納するバッファ | 取得した文字列の長さ (NULL文字除く) 存在しないインデックスを指定した場合は LB_ERR |
インデックスで指定したアイテムの文字列を取得する。 | |||
LB_GETTEXTLEN | インデックス | 0 | 文字列の長さ (NULL文字除く) 存在しないインデックスを指定した場合は LB_ERR |
インデックスで指定したアイテムの文字列の長さを取得する。 LB_GETTEXTメッセージで文字列を取得する前に必要なバッファを確保するのに使用すると良い。 |
|||
LB_SETTABSTOPS | LPARAMの配列の要素数 | タブ文字幅の配列 | 全てのタブ幅が設定されている場合はTRUE |
タブ文字の幅を設定する。 WPARAMが0の場合はデフォルトの幅(2)に設定され、LPARAMは無視される。 WPARAMが1の場合はすべてのタブ幅にLPARAMの先頭の要素の値が使用される。 WPARAMが2以上の場合はタブ幅にLPARAMの配列の値が順番に適用される。 |
|||
LB_SETITEMHEIGHT | 0 | 高さ(ピクセル単位) | 失敗した場合はLB_ERR |
すべての項目の高さを設定する。
|
|||
LB_GETITEMHEIGHT | 0 | 0 | 項目の高さ(ピクセル単位) エラーが発生した場合は LB_ERR |
すべての項目の高さを取得する。
|
|||
LB_SETCOLUMNWIDTH | 全ての列の幅(ピクセル数) | 0 | なし |
複数列リストボックスのすべての列の幅をピクセル単位で設定する。 | |||
LB_SETHORIZONTALEXTENT | 水平スクロール可能な幅 (ピクセル単位) |
0 | なし |
水平スクロール可能な幅をピクセル単位で設定する。 リストボックスはこのメッセージを送信しない限り、水平スクロールバーを表示したりスクロール幅を更新したりしない。 |
|||
LB_GETHORIZONTALEXTENT | 0 | 0 | 水平スクロール可能なピクセル数 |
水平スクロール可能な幅をピクセル単位で取得する。WS_HSCROLL スタイルの指定が必要。 |
|||
メッセージ | WPARAM | LPARAM | 戻り値 |
LB_SETITEMDATA | インデックス | アイテムに関連付けられる値 | エラー発生時はLB_ERR |
インデックスで指定したアイテムに特定の値を関連付ける。 この値は LB_GETITEMDATA メッセージで取得できる。 |
|||
LB_GETITEMDATA | インデックス | 0 | アイテムに関連付けられている値 |
インデックスで指定したアイテムに関連付けられている値を取得する。 | |||
LB_DIR | 検索対象を指定する定数 | 検索するパス (絶対パス/相対パス) |
最後に追加されたアイテムのインデックス。 エラー発生時は LB_ERR またはLB_ERRSPACE |
パス文字列および指定の属性に一致するファイル名やディレクトリ名を取得しリストボックスに追加する。
WPARAMは以下の定数の組み合わせて属性を指定する。 |
アイテム追加の高速化
リストボックスにアイテムを追加すると、リストボックスの再描画が発生します。
例えばリストボックスに一度に100個のアイテムを追加する処理をそのまま書くと、100回の再描画が行われることになります。
再描画はやや重たい処理なので、パソコンの処理速度によっては一時的に固まってしまう可能性があります。
大量のアイテムを追加する場合、追加処理の前にリストボックスにWM_SETREDRAW
メッセージを送信します。
このメッセージのWPARAMにFALSE
を指定することで、ウィンドウの描画処理を一時的に停止することができます。
コントロールの画面更新が停止するので高速にアイテムを追加できるようになります。
アイテム追加処理が終わったら、同じメッセージをWPARAMにTRUE
を指定して送信します。
(LPARAMは使用しません)
#pragma comment(lib, "winmm.lib")
#include <windows.h>
#include <strsafe.h>
//ウィンドウの生成等は省略
#define IDC_BUTTON1 100
#define IDC_BUTTON2 101
#define IDC_LIST1 1000
#define IDC_LIST2 1001
#define ITEM_LENGTH 1000 //追加するアイテムの数
#define ITEMTEXT_BUFFERSIZE 8
#define MSGTEXT_BUFFERSIZE 64
//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hList1, hList2;
static WCHAR items[ITEM_LENGTH][ITEMTEXT_BUFFERSIZE];
static WCHAR txt[MSGTEXT_BUFFERSIZE];
static DWORD time1, time2;
DWORD startTime;
HDC hdc;
PAINTSTRUCT ps;
RECT rt;
switch (message)
{
case WM_CREATE: //ウィンドウ作成
hList1 = CreateWindowEx(
WS_EX_CLIENTEDGE,
L"LISTBOX", NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL,
0, 0, 150, 200,
hWnd, (HMENU)IDC_LIST1, hInst, NULL);
hList2 = CreateWindowEx(
WS_EX_CLIENTEDGE,
L"LISTBOX", NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOREDRAW,
150, 0, 150, 200,
hWnd, (HMENU)IDC_LIST1, hInst, NULL);
CreateWindow(
L"BUTTON", L"Normal",
WS_CHILD | WS_VISIBLE,
0, 200, 150, 25,
hWnd, (HMENU)IDC_BUTTON1, hInst, NULL);
CreateWindow(
L"BUTTON", L"NoReDraw",
WS_CHILD | WS_VISIBLE,
150, 200, 150, 25,
hWnd, (HMENU)IDC_BUTTON2, hInst, NULL);
//表示用アイテムをITEM_LENGTH個作っておく
for (int i = 0; i < ITEM_LENGTH; i++) {
StringCchPrintf(items[i], ITEMTEXT_BUFFERSIZE, L"%d", i + 1);
}
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_BUTTON1: //通常の追加
startTime = timeGetTime();
SendMessage(hList1, LB_RESETCONTENT, 0, 0);
for (int i = 0; i < ITEM_LENGTH; i++) {
SendMessage(hList1, LB_ADDSTRING, 0, items[i]);
}
time1 = timeGetTime() - startTime;
InvalidateRect(hWnd, NULL, TRUE);
break;
case IDC_BUTTON2: //画面更新を停止して追加
startTime = timeGetTime();
SendMessage(hList2, WM_SETREDRAW, FALSE, 0); //更新停止
SendMessage(hList2, LB_RESETCONTENT, 0, 0);
for (int i = 0; i < ITEM_LENGTH; i++) {
SendMessage(hList2, LB_ADDSTRING, 0, items[i]);
}
SendMessage(hList2, WM_SETREDRAW, TRUE, 0); //更新再開
time2 = timeGetTime() - startTime;
InvalidateRect(hWnd, NULL, TRUE);
break;
}
break;
case WM_PAINT:
GetClientRect(hWnd, &rt);
rt.top = 230;
StringCchPrintf(txt, MSGTEXT_BUFFERSIZE,
L"更新停止なし: %dミリ秒\n更新停止あり: %dミリ秒\n",
time1, time2);
hdc = BeginPaint(hWnd, &ps);
DrawText(hdc, txt, -1, &rt, DT_WORDBREAK);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY: //ウィンドウの破棄
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
画面の左側には通常の方法でアイテムを追加するリストボックスを、右側にはWM_SETREDRAW
メッセージを利用してアイテムを追加するリストボックスを配置しています。
ボタンを押すとアイテムの追加処理が開始され、処理時間をtimeGetTime関数で計測します。
なお、右側のリストボックスはLBS_NOREDRAW
スタイル(更新の停止)を使用して作成していますが、これはリストボックスの初期状態を設定するだけです。
このスタイルを持たないリストボックスでもWM_SETREDRAW
メッセージを送信することで更新を停止することが可能です。
WM_SETREDRAW
メッセージはリストボックス以外にも使用可能です。
例えばエディットコントロールにループなどで大量のテキストを追記する場合にも利用できます。