ツール バーをカスタマイズする方法
ほとんどの Windows ベースのアプリケーションでは、ツール バー コントロールを使用して、ユーザーにプログラム機能への便利なアクセスを提供します。 ただし、静的ツールバーでは、使用可能なすべてのツールを効果的に表示するにはスペースが小さすぎるなど、いくつかの欠点があります。 この問題の解決策は、アプリケーションのツール バーをユーザーがカスタマイズできるようにすることです。 そうすると、ユーザーは必要なツールのみを表示するように選択できるため、個人のワークスタイルに合わせて整理できます。
Note
ダイアログ ボックスのツール バーはカスタマイズできません。
カスタマイズできるようにするには、ツール バー コントロールを作成するときに、共通コントロールのスタイル フラグ CCS_ADJUSTABLE を含めます。 カスタマイズの基本的な方法は 2 つあります。
- カスタマイズ ダイアログ ボックス。 このシステム提供のダイアログ ボックスは、最も簡単な方法です。 これを使用すると、アイコンを追加、削除、移動できるグラフィカル ユーザー インターフェイスがユーザーに提供されます。
- ドラッグ アンド ドロップ ツール。 ドラッグ アンド ドロップ機能を実装すると、ツール バー上の別の場所にツールを移動したり、ツール バーの外にドラッグして削除したりできます。 ユーザーはすばやく簡単にツール バーを整理できますが、ツールを追加することはできません。
アプリケーションのニーズに応じて、いずれか一方または両方の方法を実装できます。 これらの 2 つのカスタマイズ方法のどちらも、[キャンセル] または [元に戻す] ボタンなど、ツール バーを以前の状態に戻すための組み込みのメカニズムは提供されません。 ツール バー コントロール API を明示的に使用して、カスタマイズ前のツール バーの状態を保存する必要があります。 必要に応じて、この保存された情報を後で使用して、ツール バーを元の状態に復元することができます。
知っておくべきこと
テクノロジ
前提条件
- C/C++
- Windows ユーザー インターフェイス プログラミング
手順
カスタマイズ ダイアログ ボックス
カスタマイズ ダイアログ ボックスは、ツール バー コントロールによって提供され、ツールの追加、移動、削除を簡単に行う手段をユーザーに提供します。 ユーザーは、ツール バーをダブルクリックすることでこれを起動できます。 アプリケーションでは、ツール バー コントロールに TB_CUSTOMIZE メッセージを送信することで、プログラムによってカスタマイズ ダイアログ ボックスを起動できます。
次の図に、ツール バーのカスタマイズ ダイアログ ボックスの例を示します。
右側のリスト ボックスのツールは、現在ツール バーに表示されているツールです。 このリストには、最初は、ツール バーの作成時に指定したツールが含まれています。 左側のリスト ボックスには、ツール バーに追加できるツールが含まれています。 アプリケーションは、(自動的に表示される区切り記号を除いて) そのリストを表示する役割を担います。
ツール バー コントロールは、親ウィンドウに TBN_BEGINADJUST 通知コードを送信し、続いて TBN_INITCUSTOMIZE 通知コードを送信することにより、カスタマイズ ダイアログ ボックスを起動することをアプリケーションに通知します。 ほとんどの場合、アプリケーションはこれらの通知コードに応答する必要はありません。 ただし、[ツール バーのカスタマイズ] ダイアログ ボックスに [ヘルプ] ボタンを表示しない場合は、TBNRF_HIDEHELP を返すことにより TBN_INITCUSTOMIZE を処理します。
次に、ツール バー コントロールは、以下の順序で 3 つの一連の通知コードを送信することにより、ダイアログ ボックスを初期化するために必要な情報を収集します。
- ツール バーの各ボタンに対する TBN_QUERYINSERT 通知コード。これにより、ボタンを挿入できる位置を判別します。 通知メッセージで指定されたボタンの左側にボタンが挿入されないようにするには、FALSE を返します。 すべての TBN_QUERYINSERT 通知コードに対して FALSE を返した場合は、ダイアログ ボックスは表示されません。
- 現在ツール バーに表示されている各ツールに対する TBN_QUERYDELETE 通知コード。 ツールを削除できる場合は TRUE を返し、削除できない場合は FALSE を返します。
- 使用可能なボタンのリストを表示するための、一連の TBN_GETBUTTONINFO 通知コード。 リストにボタンを追加するには、通知コードと共に渡される NMTOOLBAR 構造体に入力し、TRUE を返します。 追加できるツールがそれ以上ない場合は、FALSE を返します。 既にツール バーに表示されているボタンの情報も返すことができることに注意してください。その場合、それらのボタンはリストに追加されません。
ダイアログ ボックスが表示され、ユーザーはツール バーのカスタマイズを開始できます。
ダイアログ ボックスが開いているときは、アプリケーションは、ユーザーのアクションに応じてさまざまな通知コードを受け取る可能性があります。
- TBN_QUERYINSERT。 ユーザーがツール バー上のツールの位置を変更したか、ツールを追加しました。 ツールがその場所に挿入されるのを防ぐには、FALSE を返します。
- TBN_DELETINGBUTTON。 ユーザーがツール バーからツールを削除しようとしています。
- TBN_CUSTHELP。 ユーザーが [ヘルプ] ボタンをクリックしました。
- TBN_TOOLBARCHANGE。 ユーザーがツールを追加、移動、または削除しました。
- TBN_RESET。 ユーザーが [リセット] ボタンをクリックしました。
ダイアログ ボックスが破棄された後、アプリケーションは TBN_ENDADJUST 通知コードを受信します。
次のコード例は、ツール バーのカスタマイズを実装する方法の 1 つを示しています。
// The buttons are stored in an array of TBBUTTON structures.
//
// Constants such as STD_FILENEW are identifiers for the
// built-in bitmaps that have already been assigned as the toolbar's
// image list.
//
// Constants such as IDM_NEW are application-defined command identifiers.
TBBUTTON allButtons[] =
{
{ MAKELONG(STD_FILENEW, ImageListID), IDM_NEW, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"New" },
{ MAKELONG(STD_FILEOPEN, ImageListID), IDM_OPEN, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Open"},
{ MAKELONG(STD_FILESAVE, ImageListID), IDM_SAVE, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Save"},
{ MAKELONG(STD_CUT, ImageListID), IDM_CUT, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Cut" },
{ MAKELONG(STD_COPY, ImageListID), IDM_COPY, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Copy"},
{ MAKELONG(STD_PASTE, ImageListID), IDM_PASTE, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Paste"}
};
// The following appears in the window's message handler.
case WM_NOTIFY:
{
switch (((LPNMHDR)lParam)->code)
{
case TBN_GETBUTTONINFO:
{
LPTBNOTIFY lpTbNotify = (LPTBNOTIFY)lParam;
// Pass the next button from the array. There is no need to filter out buttons
// that are already used—they will be ignored.
int buttonCount = sizeof(allButtons) / sizeof(TBBUTTON);
if (lpTbNotify->iItem < buttonCount)
{
lpTbNotify->tbButton = allButtons[lpTbNotify->iItem];
return TRUE;
}
else
{
return FALSE; // No more buttons.
}
}
break;
case TBN_QUERYINSERT:
case TBN_QUERYDELETE:
return TRUE;
}
}
ドラッグ アンド ドロップ ツール
ユーザーは、Shift キーを押しながらボタンを別の場所にドラッグすることで、ツール バーのボタンの配置を変更することもできます。 ドラッグ アンド ドロップ プロセスは、ツール バー コントロールによって自動的に処理されます。 ドラッグ中はボタンのゴースト画像が表示され、ドロップ後にツール バーの配置が変更されます。 ユーザーはこの方法でボタンを追加することはできませんが、ツール バーの外にドロップすることでボタンを削除できます。
ツール バー コントロールは通常、この操作を自動的に実行しますが、アプリケーションに対して 2 つの通知コードも送信します。TBN_QUERYDELETE と TBN_QUERYINSERT です。 ドラッグ アンド ドロップ プロセスを制御するには、以下のようにこれらの通知コードを処理します。
- TBN_QUERYDELETE 通知コードは、ユーザーがボタンの移動を試みた直後、ゴースト ボタンが表示される前に送信されます。 ボタンが移動されないようにするには、FALSE を返します。 TRUE を返した場合は、ユーザーはツールを移動することも、ツール バーの外にドロップして削除することもできます。 ツールを移動できる場合は、削除が可能です。 ただし、ユーザーがツールを削除した場合は、ツール バー コントロールはアプリケーションに TBN_DELETINGBUTTON 通知コードを送信します。その時点で、ボタンを元の位置に挿入し直し、結果として削除を取り消すことができます。
- TBN_QUERYINSERT 通知コードは、ユーザーがツール バーにボタンをドロップしようとしたときに送信されます。 移動中のボタンが、通知で指定されたボタンの左側にドロップされないようにするには、FALSE を返します。 ユーザーがツール バーの外にツールをドロップした場合は、この通知コードは送信されません。
ユーザーが Shift キーを押さずにボタンをドラッグしようとした場合、ツール バー コントロールはドラッグ アンド ドロップ操作を処理しません。 ただし、アプリケーションに TBN_BEGINDRAG 通知コードを送信してドラッグ操作の開始を示し、TBN_ENDDRAG 通知コードを送信して操作の終了を示します。 この形式のドラッグ アンド ドロップを有効にする場合は、アプリケーションでこれらの通知コードを処理し、必要なユーザー インターフェイスを指定して、変更を反映するようにツール バーを変更する必要があります。
ツール バーの保存と復元
ツール バーをカスタマイズするプロセスでは、ツール バーを元の状態に復元できるように、アプリケーションで情報を保存することが必要になる場合があります。 ツール バーの状態の保存または復元を開始するには、lParam を TRUE に設定して、TB_SAVERESTORE メッセージをツール バー コントロールに送信します。 このメッセージの lParam 値は、保存操作または復元操作を要求しているかどうかを指定します。 メッセージが送信された後、保存操作または復元操作を処理する方法は 2 つあります。
- 共通コントロール バージョン 4.72 以前の場合、TBN_GETBUTTONINFO ハンドラーを実装する必要があります。 ツール バー コントロールは、復元時に各ボタンに関する情報を要求するために、この通知コードを送信します。
- バージョン 5.80 には、保存と復元のオプションが含まれています。 プロセスの開始時点、および各ボタンが保存または復元されるときに、アプリケーションは TBN_SAVE 通知コードまたは TBN_RESTORE 通知コードを受信します。 このオプションを使用するには、通知ハンドラーを実装して、ツール バーの状態を正常に保存または復元するために必要なビットマップと状態情報を提供する必要があります。
ツール バーの状態は、シェル定義データのブロックとアプリケーション定義データのブロックが交互に並んだ構成のデータ ストリームに保存されます。 アプリケーションがストリームの先頭に配置できるグローバル データの省略可能なブロックと共に、1 種類につき 1 つのデータ ブロックが、ボタンごとに保存されます。 保存プロセス中に、TBN_SAVE ハンドラーが、アプリケーション定義ブロックをデータ ストリームに追加します。 復元プロセス中に、TBN_RESTORE ハンドラーは、各ブロックを読み取り、ツール バーの再構築に必要な情報をシェルに提供します。
TBN_SAVE 通知の処理方法
最初の TBN_SAVE 通知コードは、保存プロセスの開始時点で送信されます。 ボタンが保存される前に、NMTBSAVE 構造体のメンバーは、次の表に示すように設定されます。
メンバー | 設定 |
---|---|
iItem | –1 |
cbData | シェル定義データに必要なメモリの量。 |
cButtons | ボタンの数。 |
pData | アプリケーション定義データに必要なメモリの計算量。 通常、一部のグローバル データと各ボタンのデータを含めます。 その値を cbData に加算し、それをすべて保持するのに十分なメモリを pData に割り当てます。 |
pCurrent | データ ストリーム内の最初の未使用バイト。 グローバルなツール バー情報が不要な場合は、データ ストリームの先頭をポイントするように pCurrent = pData を設定します。 グローバルなツール バー情報が必要な場合は、pData に保存してから、戻る前に pCurrent をデータ ストリームの未使用部分の先頭に設定します。 |
グローバルなツール バー情報を追加する場合は、データ ストリームの先頭に配置します。 データ ストリームの未使用部分の先頭をポイントするように、pCurrent をグローバル データの末尾に進めてから、戻ります。
戻った後で、シェルがボタン情報の保存を開始します。 最初のボタンのシェル定義データを pCurrent 保存してから、pCurrent を未使用部分の先頭に進めます。
各ボタンが保存された後に、TBN_SAVE 通知コードが送信され、これらのメンバーが以下のように設定された状態で NMTBSAVE が返されます。
メンバー | 設定 |
---|---|
iItem | ボタン番号の、ゼロから始まるインデックス番号。 |
pCurrent | データ ストリーム内の最初の未使用バイトへのポインター。 ボタンに関する追加情報を保存する場合は、pCurrent によってポイントされた位置に保存し、その後で、データ ストリームの未使用部分の先頭をポイントするように pCurrent を更新します。 |
TBBUTTON | 保存しようとするボタンについて記述する TBBUTTON 構造体。 |
この通知コードを受信したら、ボタン固有の必要な情報がある場合は、それを TBBUTTON から抽出する必要があります。 ボタンを追加するときは、TBBUTTON の dwData メンバーを使用して、アプリケーション固有のデータを保持できます。 データ ストリームの pCurrent にデータを読み込みます。 pCurrent をデータの末尾に進め、ストリームの未使用部分の先頭に再びポイントさせてから、戻ります。
その後で、シェルは次のボタンに進み、情報を pData に追加します。pCurrent を進め、TBBUTTON を読み込み、再び TBN_SAVE 通知コードを送信します。 このプロセスは、すべてのボタンが保存されるまで続行されます。
保存されたツール バーの復元
復元プロセスは、基本的に保存プロセスを逆に実行します。 最初に、アプリケーションが、NMTBRESTORE 構造体の iItem メンバーが –1 に設定された TBN_RESTORE 通知コードを受信します。 cbData メンバーには pData のサイズが設定され、cButtons にはボタン数が設定されます。
通知ハンドラーが、保存時に pData の先頭に配置されたグローバル情報を抽出し、pCurrent を、シェル定義データの最初のブロックの先頭に進める必要があります。 cBytesPerRecord に、ボタン データを保存するために使用されたデータ ブロックのサイズを設定します。 cButtons にボタン数を設定し、戻ります。
次の NMTBRESTORE は、1 番目のボタンに関するものです。 pCurrent メンバーは、ボタン データの最初のブロックの先頭をポイントし、iItem にはボタンのインデックスが設定されています。 そのデータを抽出し、pCurrent を進めます。 データを TBBUTTON に読み込み、戻ります。 復元されたツール バーからボタンを省略するには、TBBUTTON の idCommand メンバーをゼロに設定します。 シェルは、残りのボタンについてこのプロセスを繰り返します。 NMTBSAVE メッセージと NMTBRESTORE メッセージに加えて、TBN_RESET などのメッセージを使用してツール バーの保存と復元を実行することもできます。
次のコード例では、ツール バーがカスタマイズされる前に保存し、アプリケーションが TBN_RESET メッセージを受信したらツール バーを復元します。
int i;
LPNMHDR lpnmhdr;
static int nResetCount;
static LPTBBUTTON lpSaveButtons;
LPARAM lParam;
switch( lpnmhdr->code)
{
case TBN_BEGINADJUST: // Begin customizing the toolbar.
{
LPTBNOTIFY lpTB = (LPTBNOTIFY)lparam;
// Allocate memory for the button information.
nResetCount = SendMessage(lpTB->hdr.hwndFrom, TB_BUTTONCOUNT, 0, 0);
lpSaveButtons = (LPTBBUTTON)GlobalAlloc(GPTR, sizeof(TBBUTTON) * nResetCount);
// In case the user presses reset, save the current configuration
// so the original toolbar can be restored.
for(i = 0; i < nResetCount; i++)
{
SendMessage(lpTB->hdr.hwndFrom,
TB_GETBUTTON, i,
(LPARAM)(lpSaveButtons + i));
}
}
return TRUE;
case TBN_RESET:
{
LPTBNOTIFY lpTB = (LPTBNOTIFY)lparam;
int nCount, i;
// Remove all of the existing buttons, starting with the last one.
nCount = SendMessage(lpTB->hdr.hwndFrom, TB_BUTTONCOUNT, 0, 0);
for(i = nCount - 1; i >= 0; i--)
{
SendMessage(lpTB->hdr.hwndFrom, TB_DELETEBUTTON, i, 0);
}
SendMessage(lpTB->hdr.hwndFrom, // Restore the saved buttons.
TB_ADDBUTTONS,
(WPARAM)nResetCount,
(LPARAM)lpSaveButtons);
}
return TRUE;
case TBN_ENDADJUST: // Free up the memory you allocated.
GlobalFree((HGLOBAL)lpSaveButtons);
return TRUE;
}
関連トピック