第142章 ツールバーをカスタマイズする


今回は,RTFエディタにつけたツールバーをカスタマイズ する方法について考えます。ツールバーをカスタマイズするに あたってはちょっと問題が生じます。何かというと、ボタンにテキスト が表示されていない状態でカスタマイズを行うと「区切り」を 挿入したときにボタンが縦長になりみっともない状態となります。 今回は,これを強制的に修正する方法についても考えてみます。



「表示」「ツールバーのカスタマイズ」で左のようなダイアログボックスを 表示します。これで、ボタンを削除したり追加したりします。



さて、通常のボタンの削除や追加は問題ないのですが「区切り」を追加すると・・・

左の図のようにボタンが間延びして何ともみっともない姿になります。 どうもテキストが1行入る分だけ縦長になるみたいです。



縦長問題はさておき、ツールバーをカスタマイズしても次回起動時に デフォルトに戻っていては面白くありません。そこでプログラム終了時に ツールバーのボタン状態を記録して、起動時に前回の状態を再現する 方法についても解説します。

まずはカスタマイズの方法です。

1.CreateToolbarExでツールバーを作るときにウィンドウスタイルに   CCS_ADJUSTABLEを加える。 2.さらに、TBSTYLE_ALTDRAGを加えるとAlt(Grph)キーを押してボタンを   ドラッグすることによりボタン位置を変更できるようになる 3.ツールバーに対してWM_CUSTOMIZEメッセージを送る 4.通知メッセージTBN_QUERYENSERT, TBN_QUERYDELETEに対してTRUEを返す 5.TBN_GETBUTTONINFOに対して、ボタン情報を与える 6.ダイアログの「リセット」に対応するためTBN_RESETメッセージを処理する   (ボタンをデフォルト状態に戻す) 7.必要に応じてTBN_CUSTHELP, TBN_BEGINADJUST, TBN_BEGINDRAG, TBN_ENDDRAG, TBN_ENDADJUST, TBN_TOOLBARCHANGEなどのに応答する

TBN_GETBUTTONINFOはTRUEを返している間どんどん飛んできます。これに対して FALSEを返すと飛んでこなくなります。つまりボタン情報を教えている間は TRUEを返し、教え終わったらFALSEを返すようにします。 たとえば,次のようになります。

... LPTBNOTIFY lpTBn; ... case TBN_GETBUTTONINFO: no = lpTBn->iItem; if (no <= 7) { lpTBn->tbButton = tbBut[no]; } if (no >= 8 && no <= 14) { lpTBn->tbButton = tbBmp[no - 8]; } if (no >= 15) return FALSE; lpTBn->pszText = ""; lpTBn->cchText = 0; return TRUE;

さて,新しく出てきたLPTBNOTIFYはTBNOTIFY構造体へのポインタ型です。

typedef struct { // tbn NMHDR hdr; int iItem; TBBUTTON tbButton; int cchText; LPTSTR pszText; } TBNOTIFY, FAR* LPTBNOTIFY;

というように定義されています。 さて、WN_NOTIFYのヘルプを今一度良く読んでみると、このときの lParamにはNMHDR構造体のポインタが来るが、ある通知メッセージの 時はさらに大きな構造体へのポインタが来る,と書いてあります。 つまり、この構造体がそうです。ツールバー関係のWM_NOTIFYの lParamはこの構造体へのポインタです。したがって次のように 場合分けするとわかりやすいです。

case WM_NOTIFY: if (wp == (WPARAM)ID_TOOLBAR) { lpTBn = (LPTBNOTIFY)lp; switch (lpTBn->hdr.code) { case TBN_QUERYINSERT: return TRUE; case TBN_QUERYDELETE: return TRUE; case ***: ........... } if (wp == (WPARAM)ID_RICH) { lpN = (LPNMHDR)lp; switch (lpN->code ) { case EN_SELCHANGE: //処理 break;

しかし、ここでlParamがTBNOTIFY構造体へのポインタであっても 1番目のメンバはNMHDR構造体です。(lParamがNMHDR構造体への ポインタでない時はその構造体の第1メンバはNMHDR構造体になっています。) ということは

if (((LPTBNOTIFY)lp)->hdr.idFrom == ID_TOOLBAR){...

このように場合分けしても良いですし、

if (((LPNMHDR)lp)->idFrom == ID_TOOLBAR){...

という書き方もできるわけです。(TBNOTIFYの最初のメンバがhdrなので lParamをLPNMHDRに型キャストしてこれのidFromメンバにアクセスしても 同じことになります。)したがってあるコントロールからの WM_NOTIFYのlParamがNMHDRへのポインタかどうかわからなくても 2番目の書き方をすれば場合分けができるということです。 この辺が,WM_NOTIFYメッセージの処理で頭がごちゃごちゃになる 原因でしょう。

さて、話をTBNOTIFY構造体に戻すと
hdrは通知情報(NMHDR)です。
iItemはボタンのインデックスです。
tbButtonはツールバーボタンに関する情報を格納するTBBUTTON構造体 へのポインタです。
cchTextはボタン内のテキスト文字数です。
pszTextはボタンのテキストです。

これで、TBN_GETBUTTONINFOでの処理の仕方がわかったかと思います。

次に,ボタン情報の保存と再現にはTB_SAVERESTOREメッセージを使います。

TB_SAVERESTORE wParam = (WPARAM) (BOOL) fSave; lParam = (LPARAM) (TBSAVEPARAMS *)ptbsp;

fSaveがTRUEの時は情報をレジストリに格納します。FALSEの時は,レジストリから 情報を読み出して復元します。
ptbspはTBSAVEPARAMS構造体へのポインタです。

TBSAVEPARAMS構造体は次のように定義されています。

typedef struct { // tbsr HKEY hkr; LPCTSTR pszSubKey; LPCTSTR pszValueName; } TBSAVEPARAMS;

hkrはレジストリーキーへのハンドルです。普通はHKEY_CURRENT_USERを使います。
pszSubKeyはサブキー名の文字列です。(普通はSoftware\\会社名\\ソフト名)
pszValueName値の名前です。

次に「リセット」ボタンが押されたときの処理ですが、

1.現在のボタンの数をTB_BUTTONCOUNTで知る 2.その数だけTB_DELETEBUTTONを送ってボタンを削除する 3.TB_ADDBUTTONSメッセージなどで初期状態を再現する

というよにします。さて、筆者はここで「リセット」するとたとえ ボタンが「間延び」していても正しい大きさに戻ることに 気がつきました。つまり、ボタンが間延びしているときは 現在のボタン情報をレジストリに格納して、ボタンを全部削除、 レジストリから情報を読み出して再現する、という方法を使えば 正常の大きさに戻ります。(かなり力づくの方法です。もっとスマートな やり方があるのかもしれません)

では、プログラムを見てみることにします。

// rich13.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "新規作成(&N)", IDM_NEW MENUITEM "開く(&O)", IDM_OPEN MENUITEM SEPARATOR MENUITEM "上書き保存(&S)", IDM_SAVE MENUITEM "名前をつけて保存(&A)", IDM_SAVEAS MENUITEM SEPARATOR MENUITEM "プリンターの設定(&U)", IDM_PRNSET MENUITEM "印刷(&P)", IDM_PRINT MENUITEM SEPARATOR MENUITEM "終了(&X)", IDM_END END POPUP "編集(&E)" BEGIN MENUITEM "元に戻す(&U)", IDM_UNDO MENUITEM SEPARATOR MENUITEM "横書き(&H)", IDM_HORIZONTAL MENUITEM "縦書き(&V)", IDM_VERTICAL MENUITEM SEPARATOR MENUITEM "フォントの変更(&F)", IDM_FONT POPUP "段落書式" BEGIN MENUITEM "中央揃え(&C)", IDM_CENTER MENUITEM "左揃え(&L)", IDM_LEFT MENUITEM "右揃え(&R)", IDM_RIGHT END MENUITEM SEPARATOR MENUITEM "コピー(&C)", IDM_COPY MENUITEM "切り取り(&T)", IDM_CUT MENUITEM "貼り付け(&P)", IDM_PASTE MENUITEM SEPARATOR MENUITEM "すべて選択(&L)", IDM_ALL END POPUP "表示(&V)" BEGIN MENUITEM "背景色の変更(&B)", IDM_BACKCOLOR MENUITEM "ツールバーのカスタマイズ(&C)", IDM_CUSTOMIZE END END MYPOPUP MENU DISCARDABLE BEGIN POPUP "ダミーです" BEGIN MENUITEM "新規作成", IDM_NEW MENUITEM "開く", IDM_OPEN MENUITEM SEPARATOR MENUITEM "上書き保存", IDM_SAVE MENUITEM "名前をつけて保存", IDM_SAVEAS MENUITEM SEPARATOR MENUITEM "横書き", IDM_HORIZONTAL MENUITEM "縦書き", IDM_VERTICAL MENUITEM SEPARATOR MENUITEM "フォントの変更", IDM_FONT MENUITEM SEPARATOR MENUITEM "左揃え", IDM_LEFT MENUITEM "右揃え", IDM_RIGHT MENUITEM "中央揃え", IDM_CENTER MENUITEM SEPARATOR MENUITEM "終了", IDM_END MENUITEM SEPARATOR MENUITEM "コピー", IDM_COPY MENUITEM "切り取り", IDM_CUT MENUITEM "貼り付け", IDM_PASTE MENUITEM "元に戻す", IDM_UNDO MENUITEM SEPARATOR MENUITEM "印刷", IDM_PRINT MENUITEM "プリンタの設定", IDM_PRNSET MENUITEM SEPARATOR MENUITEM "すべて選択", IDM_ALL MENUITEM SEPARATOR MENUITEM "背景色の変更", IDM_BACKCOLOR END END ///////////////////////////////////////////////////////////////////////////// // // Toolbar // ID_MYTOOLBAR TOOLBAR DISCARDABLE 16, 15 BEGIN BUTTON IDM_VERTICAL BUTTON IDM_HORIZONTAL BUTTON IDM_LEFT BUTTON IDM_CENTER BUTTON IDM_RIGHT BUTTON IDM_FONT BUTTON IDM_BACKCOLOR END ///////////////////////////////////////////////////////////////////////////// // // Bitmap // ID_MYTOOLBAR BITMAP DISCARDABLE "mytoolba.bmp"

「ツールバーのカスタマイズ」が増えています。右クリックメニューには あえて、これを付け加えていません。(項目が増えすぎて使いづらくなる)

// rich13.cpp #define STRICT #include <windows.h> #include <richedit.h> #include "resource.h" #include <commctrl.h> #define ID_TOOLBAR 100 #define ID_STATUS 101 #define ID_RICH 102 // ID番号を変更しました #define ID_MYTIMER 1000 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); DWORD CALLBACK MySaveProc(DWORD, LPBYTE, LONG, LONG *); DWORD CALLBACK MyReadProc(DWORD, LPBYTE, LONG, LONG *); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL SetInitialFont(HWND hWnd); BOOL SetMyFont(HWND); BOOL SetCenter(HWND); BOOL SetLeft(HWND); BOOL SetRight(HWND); void ClearCheck(HMENU);//段落書式のチェックをはずす void RTF_Save(HWND); void RTF_SaveAs(HWND); void RTF_Open(HWND); void RTF_CheckMenu(HWND, HMENU); void RTF_Print(HWND); void RTF_All(HWND); HDC GetPrintInfo(void); int PrinterSet(HWND); int RTF_AddPageNo(HDC, int); void RTF_SetWYSIWYG(HWND); void RTF_New(HWND); void RTF_Vertical(HWND); void RTF_Horizontal(HWND); void RTF_BackColor(HWND); void CheckButtonState(HWND); HWND MakeMyToolbar(HWND); void InsertSep(HWND); HWND MakeMyStatusbar(HWND hWnd); void SetStatusFontInfo(HWND, HWND); BOOL IsEditButtonAvailable(HWND, HWND); BOOL IsPasteButtonAvailable(HWND, HWND); void SetStatusClock(HWND); char szClassName[] = "rich13"; //ウィンドウクラス HINSTANCE hInst; DWORD dwMyMask; //CHARFORMATで使うマスク値 char szFName[MAX_PATH]; int nFileType = 1; //1:RTF 2:TXT 3:All char *szAppTitle = "猫でもわかるRTF"; PRINTER_INFO_5 prninfo[3]; TBBUTTON tbBut[] = { {STD_FILENEW, IDM_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {STD_FILEOPEN, IDM_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {STD_FILESAVE, IDM_SAVE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {STD_PRINT, IDM_PRINT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {STD_COPY, IDM_COPY, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {STD_CUT, IDM_CUT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {STD_PASTE, IDM_PASTE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {STD_UNDO, IDM_UNDO, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, }; TBBUTTON tbSep = {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0}; TBBUTTON tbBmp[] = { {0, IDM_VERTICAL, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {1, IDM_HORIZONTAL, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {2, IDM_LEFT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {3, IDM_CENTER, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {4, IDM_RIGHT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {5, IDM_FONT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {6, IDM_BACKCOLOR, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0} };

変更点は、リッチエディットコントロールのIDを他のコントロールと 同じようにID_RICHでdefineして見やすくしました。

MakeMyToolbar関数の中で区切りもいっしょにつけていましたが この区切りを独立した関数(InsertSep)にしました。

WinMain, InitApp, InitInstance

の各関数に変更点はありません。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static HINSTANCE hRtLib; static HWND hEdit, hTool, hStatus; DWORD dwEvent; MSGFILTER *pmf; HMENU hMenu, hSub; int x, y; POINT pt; int nToolH, nStatusH; RECT rc; LPTBNOTIFY lpTBn; int no; TBSAVEPARAMS tbs; LPNMHDR lpN; switch (msg) { case WM_CREATE: InitCommonControls(); hTool = MakeMyToolbar(hWnd); InsertSep(hTool); hStatus = MakeMyStatusbar(hWnd); CheckButtonState(hTool); hRtLib = LoadLibrary("RICHED32.DLL"); hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "RICHEDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE | WS_HSCROLL | WS_VSCROLL | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_NOHIDESEL, 0, 0, 0, 0, //とりあえず幅、高さ0のウィンドウを作る hWnd, (HMENU)ID_RICH,//統一性を図るためIDを変えました hInst, NULL); dwEvent = SendMessage(hEdit, EM_GETEVENTMASK, 0, 0); dwEvent |= ENM_MOUSEEVENTS | ENM_SELCHANGE; SendMessage(hEdit, EM_SETEVENTMASK, 0, (LPARAM)dwEvent); SetInitialFont(hEdit); //リッチエディットコントロールをWYSIWYGの幅にする //要するにプリンタにセットしてある用紙の幅に合わせる RTF_SetWYSIWYG(hEdit); tbs.hkr = HKEY_CURRENT_USER; tbs.pszSubKey = "Software\\Kumei\\rich13"; tbs.pszValueName = "Setting"; SendMessage(hTool, TB_SAVERESTORE, FALSE, (LPARAM)&tbs); SetStatusFontInfo(hStatus, hEdit); //ボタンを復元してから次の2つの関数を呼ぶこと IsEditButtonAvailable(hEdit, hTool); IsPasteButtonAvailable(hEdit, hTool); SetTimer(hWnd, ID_MYTIMER, 500, NULL); break; case WM_TIMER: IsPasteButtonAvailable(hEdit, hTool); SetStatusClock(hStatus); break; case WM_NOTIFY: if (wp == (WPARAM)ID_TOOLBAR) { lpTBn = (LPTBNOTIFY)lp; switch (lpTBn->hdr.code) { case TBN_QUERYINSERT: return TRUE; case TBN_QUERYDELETE: return TRUE; case TBN_GETBUTTONINFO: no = lpTBn->iItem; if (no <= 7) { lpTBn->tbButton = tbBut[no]; } if (no >= 8 && no <= 14) { lpTBn->tbButton = tbBmp[no - 8]; } if (no >= 15) return FALSE; lpTBn->pszText = ""; lpTBn->cchText = 0; return TRUE; case TBN_RESET: int i, b; b = SendMessage(hTool, TB_BUTTONCOUNT, 0, 0); for (i = 0; i < b; i++) SendMessage(hTool, TB_DELETEBUTTON, 0, 0); SendMessage(hTool, TB_ADDBUTTONS, 8, (LPARAM)tbBut); SendMessage(hTool, TB_ADDBUTTONS, 7, (LPARAM)&tbBmp[0]); InsertSep(hTool); break; } } if (wp == (WPARAM)ID_RICH) { lpN = (LPNMHDR)lp; switch (lpN->code ) { case EN_SELCHANGE: SetStatusFontInfo(hStatus, hEdit); //「切り取り」「コピー」が可能かどうか調査 IsEditButtonAvailable(hEdit, hTool); // 「張りつけ」可能かどうか IsPasteButtonAvailable(hEdit, hTool); break; case EN_MSGFILTER: pmf = (MSGFILTER *)lp; if (pmf->msg == WM_RBUTTONDOWN){ x = LOWORD(pmf->lParam); y = HIWORD(pmf->lParam); hMenu = LoadMenu(hInst, "MYPOPUP"); hSub = GetSubMenu(hMenu, 0); pt.x = (LONG)x; pt.y = (LONG)y; ClientToScreen(hEdit, &pt); TrackPopupMenu(hSub, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL); DestroyMenu(hMenu); } break; } } break; case WM_SIZE: SendMessage(hTool, WM_SIZE, wp, lp); SendMessage(hStatus, WM_SIZE, wp, lp); GetWindowRect(hTool, &rc); nToolH = rc.bottom - rc.top; GetWindowRect(hStatus, &rc); nStatusH = rc.bottom - rc.top; MoveWindow(hEdit, 0, nToolH, LOWORD(lp), HIWORD(lp) - (nToolH + nStatusH), TRUE); SetFocus(hEdit); break; case WM_INITMENUPOPUP: RTF_CheckMenu(hEdit, (HMENU)wp); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_ALL: RTF_All(hEdit); break; case IDM_FONT: SetMyFont(hEdit); SetStatusFontInfo(hStatus, hEdit); break; case IDM_CENTER: SetCenter(hEdit); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_CENTER, (LPARAM)MAKELONG(TBSTATE_PRESSED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_LEFT, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_RIGHT, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); break; case IDM_LEFT: SetLeft(hEdit); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_LEFT, (LPARAM)MAKELONG(TBSTATE_PRESSED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_CENTER, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_RIGHT, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); break; case IDM_RIGHT: SetRight(hEdit); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_RIGHT, (LPARAM)MAKELONG(TBSTATE_PRESSED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_LEFT, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_CENTER, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); break; case IDM_NEW: RTF_New(hEdit); break; case IDM_SAVE: RTF_Save(hEdit); break; case IDM_SAVEAS: RTF_SaveAs(hEdit); break; case IDM_OPEN: RTF_Open(hEdit); break; case IDM_COPY: SendMessage(hEdit, WM_COPY, 0, 0); break; case IDM_CUT: SendMessage(hEdit, WM_CUT, 0, 0); break; case IDM_PASTE: SendMessage(hEdit, WM_PASTE, 0, 0); break; case IDM_UNDO: SendMessage(hEdit, WM_UNDO, 0, 0); break; case IDM_PRINT: RTF_Print(hEdit); break; case IDM_PRNSET: PrinterSet(hEdit); RTF_SetWYSIWYG(hEdit); break; case IDM_VERTICAL: RTF_Vertical(hEdit); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_VERTICAL, (LPARAM)MAKELONG(TBSTATE_PRESSED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_HORIZONTAL, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); break; case IDM_HORIZONTAL: RTF_Horizontal(hEdit); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_HORIZONTAL, (LPARAM)MAKELONG(TBSTATE_PRESSED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_VERTICAL, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); break; case IDM_BACKCOLOR: RTF_BackColor(hEdit); break; case IDM_CUSTOMIZE: SendMessage(hTool, TB_CUSTOMIZE, 0, 0); { int b, i; tbs.hkr = HKEY_CURRENT_USER; tbs.pszSubKey = "Software\\Kumei\\rich13"; tbs.pszValueName = "Setting"; SendMessage(hTool, TB_SAVERESTORE, TRUE, (LPARAM)&tbs); b = SendMessage(hTool, TB_BUTTONCOUNT, 0, 0); for (i = 0; i < b; i++) SendMessage(hTool, TB_DELETEBUTTON, 0, 0); SendMessage(hTool, TB_ADDBUTTONS, 8, (LPARAM)tbBut); SendMessage(hTool, TB_ADDBUTTONS, 7, (LPARAM)tbBmp); tbs.hkr = HKEY_CURRENT_USER; tbs.pszSubKey = "Software\\Kumei\\rich13"; tbs.pszValueName = "Setting"; SendMessage(hTool, TB_SAVERESTORE, FALSE, (LPARAM)&tbs); //ツールバーをリストアしたときは必ず次の関数を呼ぶ IsEditButtonAvailable(hEdit, hTool); } break; } break; case WM_CLOSE: if (SendMessage(hEdit, EM_GETMODIFY, 0, 0)) { id = MessageBox(hWnd, "文書が変更されています。保存しますか。", "注意!", MB_YESNO); if (id == IDYES) RTF_Save(hEdit); } id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hEdit); DestroyWindow(hWnd); } else SetFocus(hEdit); break; case WM_DESTROY: tbs.hkr = HKEY_CURRENT_USER; tbs.pszSubKey = "Software\\Kumei\\rich13"; tbs.pszValueName = "Setting"; SendMessage(hTool, TB_SAVERESTORE, TRUE, (LPARAM)&tbs); if(KillTimer(hWnd, ID_MYTIMER) == 0) MessageBox(hWnd, "タイマーを正常に殺せませんでした", "Error", MB_OK | MB_ICONHAND); if(FreeLibrary(hRtLib) == 0) MessageBox(NULL, "ライブラリ開放失敗", "Error", MB_OK); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0L; }

プロシージャは長くなる一方です。
WM_CREATEメッセージが来たときの処理が少し変更になっています。
ツールバー,ステータスバー、リッチエディットコントロールを 作った後,レジストリで前回のボタン状態を復元しています。 IsEditButtonAvailable(自作)関数はこの後で読んでください。 で、ないと「コピー」「切り取り」ボタンが有効になってしまいます。

WM_NOTIFYメッセージの処理は最初の説明を読めばわかると思います。

IDM_CUSTOMIZEのところは本来SendMessage(...);だけで良いはずですが 間延びボタンを直すために{}でくくった部分を付け加えています。

WM_DESTROYメッセージのところでレジストリにボタン状態を 保存しています。

SetInitialFont, SetMyFont, SetCenter, SetLeft, SetRight, ClearCheck, RTF_Save, RTF_SaveAs, MySaveProc, RTF_Open, MyReadProc, RTF_CheckMenu, RTF_Print, PrinterSet, GetPrintInfo, RTF_All, RTF_AddPageNo, RTF_SetWYSIWYG, RTF_New, RTF_Vertical, RTF_Horizontal, RTF_BackColor,

の各関数に変更点はありません。

HWND MakeMyToolbar(HWND hWnd) { HWND hTool; HINSTANCE hInst; TBADDBITMAP tab; HBITMAP hBmp; int nIndex, i; hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); hTool = CreateToolbarEx(hWnd, WS_CHILD | WS_BORDER | WS_VISIBLE | CCS_ADJUSTABLE | TBSTYLE_ALTDRAG | TBSTYLE_WRAPABLE, ID_TOOLBAR, 8, (HINSTANCE)HINST_COMMCTRL, IDB_STD_SMALL_COLOR, tbBut, 8, 0, 0, 0, 0, sizeof(TBBUTTON)); hBmp = CreateMappedBitmap(hInst, ID_MYTOOLBAR, 0, NULL, 0); tab.hInst = NULL; tab.nID = (UINT)hBmp; nIndex = SendMessage(hTool, TB_ADDBITMAP, 7, (LPARAM)&tab); for (i = 0; i <= 6; i++) tbBmp[i].iBitmap += nIndex; SendMessage(hTool, TB_ADDBUTTONS, 7, (LPARAM)&tbBmp[0]); return hTool; }

区切りを挿入するところを省略しました。また、CreateToolbarExのスタイルに CCS_ADJUSTABLE | TBSTYLE_ALTDRAG | TBSTYLE_WRAPABLEを加えました。 前の2つは最初に解説しました。最後のは、ウィンドウが小さくて ボタンが全部表示されないときにボタンを複数行にわたって 表示するというものです。しかし、このとき下のほうが妙に広く開きます。 恐らくボタンにテキストが入っている計算がされているのだと思います。

void InsertSep(HWND hTool) { SendMessage(hTool, TB_INSERTBUTTON, 0, (LPARAM)&tbSep); SendMessage(hTool, TB_INSERTBUTTON, 4, (LPARAM)&tbSep); SendMessage(hTool, TB_INSERTBUTTON, 6, (LPARAM)&tbSep); SendMessage(hTool, TB_INSERTBUTTON, 10, (LPARAM)&tbSep); SendMessage(hTool, TB_INSERTBUTTON, 12, (LPARAM)&tbSep); SendMessage(hTool, TB_INSERTBUTTON, 15, (LPARAM)&tbSep); SendMessage(hTool, TB_INSERTBUTTON, 19, (LPARAM)&tbSep); return; }

初期状態のボタンに区切りを挿入します。

CheckButtonState, MakeMyStatusbar, SetStatusFontInfo, IsEditButtonAvailable, IsPasteButtonAvailable, SetStatusClock

に変更はありません。

さて、今回作ったプログラムを動かしていると次のような問題点が 起こります。メニューからプログラムをカスタマイズしたときは 良いのですが,ツールバーをダブルクリックしてカスタマイズしたときは 「間延び」問題が起こります。これを解決する方法を考えてみてください。 要するに、ツールバーがダプルクリックされたことを知る方法です。


[SDK第2部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 04/Sep/1998 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。