第145章 RTFの最大文字数の変更


リッチエディットコントロールではそのまま使っていると、 32キロバイトまでのファイルが限界です。 今回は、これを1メガまで拡張します。また限界まで来たときの 通知メッセージを捕まえます。

さらに、編集機能で「削除」がなかったのでこれをメニューと ツールバーのボタンに追加します。

また、ツールバー,ステータスバー,ルーラーの表示・非表示 を可能にします。

それと、ステータスバーに表示されるフォントの「ポイント」で 実際に使われているポイントより1ポイント低く表示されることが あったのでこれを改善します。

EM_EXLIMITTEXT wParam = 0; lParam = (LPARAM) (DWORD) cchTextMax;

このメッセージをエディットコントロールに送ってやると ユーザーはcchTextMaxバイトまで使うことができます。 これを0にするとデフォルトの32キロとなります。 これと第74章で出てきたEM_SETLIMITTEXTメッセージの違いについて 注意して下さい

ところで,限界以上にテキストを入力するとどうなるのでしょうか。 このメッセージで最大文字数を10バイトくらいの少ない 数値にして実験してみて下さい。これは、次の限界を超えたときの 通知メッセージの実験でも役に立ちます。

EN_MAXTEXT idEditCtrl = (int) LOWORD(wParam); //エディットコントロールのID hwndEditCtrl = (HWND) lParam; //エディットコントロールのハンドル

エディットコントロールに対して指定された文字数を超えて 挿入が起こり、切捨てが起こったときにその親に送られます。 また、ES_AUTOVSCROLLやES_AUTOHSCROLLを持たない コントロールに対して表示しきれない挿入が起こったときにも 発生します。

注意すべき点は、この通知メッセージは WM_COMMANDを通じて 受け取るということです。WM_COMMANDはすでにおなじみですが 念のためこれの副メッセージを書いておきます。

WM_COMMAND wNotifyCode = HIWORD(wParam); // 通知コード wID = LOWORD(wParam); // コントロールなどのID hwndCtl = (HWND) lParam; // コントロールのハンドル

EN_MAXTEXTはWM_COMMANDのHIWORD(wParam)を調べればよいことが わかります。

次に選択された文字列を削除するにはどうしたらよいのでしょうか。 実は第74章からの「メモ帳を作る」では出てきませんでした。 でも、これは簡単です。エディットコントロールにWM_CLEARを送れば解決します。

WM_CLEAR wParam = 0; lParam = 0;

これは、エディットコントロールだけでなく、コンボボックスに対しても 有効です。

さて、細かいことですがフォントのポイントはその高さ(twip)を20で割ることに よってえられます(第130章の最後のほう参照)。 しかし、たとえば筆者の環境でのMS ゴシックは高さが270twipで14ポイントです。 単純に整数の割り算で(高さ)/20で計算すると13ポイントとなり誤差が生じます。 そこで13.5を14に四捨五入することが必要となります。これもちょっとした 工夫でできます。

削除ボタンが増えました。 フォントをいじらないとMS ゴシックの14ポイント になりますが、今まではステータスバーに「13ポイント」と表示されていました。 これを修正しました。また、ツールバーなどを非表示にすることができます。



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

// rich16.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 "段落書式(&P)" BEGIN MENUITEM "中央揃え(&C)", IDM_CENTER MENUITEM "左揃え(&L)", IDM_LEFT MENUITEM "右揃え(&R)", IDM_RIGHT MENUITEM SEPARATOR POPUP "タブの設定(&T)" BEGIN MENUITEM "2cm毎", IDM_2CM MENUITEM "1cm毎", IDM_CM MENUITEM "0.5cm毎", IDM_05CM MENUITEM SEPARATOR MENUITEM "2インチ毎", IDM_2INCH MENUITEM "1インチ毎", IDM_INCH MENUITEM "0.5インチ毎", IDM_05INCH END MENUITEM SEPARATOR MENUITEM "段落マーク付け(&M)", IDM_NUM END MENUITEM SEPARATOR MENUITEM "コピー(&C)", IDM_COPY MENUITEM "切り取り(&T)", IDM_CUT MENUITEM "貼り付け(&P)", IDM_PASTE MENUITEM "削除(&D)", IDM_DELETE MENUITEM SEPARATOR MENUITEM "すべて選択(&L)", IDM_ALL END POPUP "表示(&V)" BEGIN MENUITEM "背景色の変更(&B)", IDM_BACKCOLOR MENUITEM "ツールバーのカスタマイズ(&C)", IDM_CUSTOMIZE MENUITEM SEPARATOR MENUITEM "ツールバー(&T)", IDM_TOOL MENUITEM "ステータスバー(&S)", IDM_STATUS MENUITEM "ルーラー(&R)", IDM_RULER 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_DELETE MENUITEM "元に戻す", IDM_UNDO MENUITEM SEPARATOR MENUITEM "印刷", IDM_PRINT MENUITEM "プリンタの設定", IDM_PRNSET MENUITEM SEPARATOR MENUITEM "すべて選択", IDM_ALL MENUITEM SEPARATOR MENUITEM "背景色の変更", IDM_BACKCOLOR MENUITEM SEPARATOR POPUP "タブの設定" BEGIN MENUITEM "2cm毎", IDM_2CM MENUITEM "1cm毎", IDM_CM MENUITEM "0.5cm毎", IDM_05CM MENUITEM SEPARATOR MENUITEM "2インチ毎", IDM_2INCH MENUITEM "1インチ毎", IDM_INCH MENUITEM "0.5インチ毎", IDM_05INCH END MENUITEM SEPARATOR MENUITEM "段落マーク付け", IDM_NUM MENUITEM SEPARATOR MENUITEM "ツールバー", IDM_TOOL MENUITEM "ステータスバー", IDM_STATUS MENUITEM "ルーラー", IDM_RULER 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"

リソース・スクリプトもいつのまにか巨大になってしまいました。 「削除」「ツールバー」「ステータスバー」「ルーラー」の項目が 増えました。

次にソースの変更・追加を示します。

// rich16.cpp ...省略... char szClassName[] = "rich16"; //ウィンドウクラス ...省略... BOOL bToolVisible = TRUE, bStatusVisible = TRUE, bRulerVisible = TRUE; ...省略... 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_DELETE, IDM_DELETE, 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}, }; ...省略...

グローバル変数などの追加です。STD_DELETEボタン(バッテン印)が増えました。 セパレーターはうまい具合に変更なしですみました。

WinMain, InitApp, InitInstance

の各関数に変更点はありません。 次にメインウィンドウのプロシージャを示します。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static HINSTANCE hRtLib; static HWND hEdit, hTool, hStatus, hRuler; DWORD dwEvent; MSGFILTER *pmf; HMENU hMenu, hSub; int x, y; POINT pt; int nToolH, nStatusH, nRulerH; RECT rc; LPTBNOTIFY lpTBn; int no; TBSAVEPARAMS tbs; LPNMHDR lpN; LPARAM mylp; switch (msg) { case WM_CREATE: InitCommonControls(); hTool = MakeMyToolbar(hWnd); InsertSep(hTool); hStatus = MakeMyStatusbar(hWnd); hRuler = MakeMyRuler(hWnd, 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); //リッチエディットコントロールの最大文字数のセット SendMessage(hEdit, EM_EXLIMITTEXT, 0, (LPARAM)1024*1024); //親ウィンドウへデータ(hEdit)のアタッチ SetWindowLong(hWnd, GWL_USERDATA, (LONG)hEdit); 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); //ボタンを復元してから次の4つの関数を呼んでボタン状態を設定 IsEditButtonAvailable(hEdit, hTool); IsPasteButtonAvailable(hEdit, hTool); SetButtonHV(hEdit, hTool); SetAlignmentButton(hEdit, hTool); SetTimer(hWnd, ID_MYTIMER, 500, NULL); Org_ToolProc = (WNDPROC)GetWindowLong(hTool, GWL_WNDPROC); SetWindowLong(hTool, GWL_WNDPROC, (LONG)MyToolProc); Org_StaticProc = (WNDPROC)GetWindowLong(hRuler, GWL_WNDPROC); SetWindowLong(hRuler, GWL_WNDPROC, (LONG)MyStaticProc); 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 <= 8) { lpTBn->tbButton = tbBut[no]; } if (no >= 9 && no <= 15) { lpTBn->tbButton = tbBmp[no - 9]; } if (no >= 16) 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, 9, (LPARAM)tbBut); SendMessage(hTool, TB_ADDBUTTONS, 7, (LPARAM)&tbBmp[0]); InsertSep(hTool); SetAlignmentButton(hEdit, hTool); SetButtonHV(hEdit, hTool); IsEditButtonAvailable(hEdit, hTool); IsPasteButtonAvailable(hEdit, 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); SetAlignmentButton(hEdit, hTool); //ルーラーの書き換え if(InvalidateRect(hRuler, NULL, TRUE)==0) MessageBeep(MB_ICONHAND); 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: if (bRulerVisible) nRulerH = 30; else nRulerH = 0; if (bToolVisible) { SendMessage(hTool, WM_SIZE, wp, lp); GetWindowRect(hTool, &rc); nToolH = rc.bottom - rc.top; } else { nToolH = 0; } if (bStatusVisible) { SendMessage(hStatus, WM_SIZE, wp, lp); GetWindowRect(hStatus, &rc); nStatusH = rc.bottom - rc.top; } else { nStatusH = 0; } MoveWindow(hRuler, 0, nToolH, LOWORD(lp), nRulerH, TRUE); MoveWindow(hEdit, 0, nToolH + nRulerH, LOWORD(lp), HIWORD(lp) - (nToolH + nStatusH + nRulerH), TRUE); SetFocus(hEdit); break; case WM_INITMENUPOPUP: RTF_CheckMenu(hEdit, (HMENU)wp); break; case WM_COMMAND: switch (HIWORD(wp)) { case EN_MAXTEXT: MessageBox(hWnd, "入力文字数の制限を越えました!", "警告!", MB_OK); SetFocus(hEdit); break; } 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); SetAlignmentButton(hEdit, hTool); break; case IDM_LEFT: SetLeft(hEdit); SetAlignmentButton(hEdit, hTool); break; case IDM_RIGHT: SetRight(hEdit); SetAlignmentButton(hEdit, hTool); 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_DELETE: SendMessage(hEdit, WM_CLEAR, 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); InvalidateRect(hRuler, NULL, TRUE); break; case IDM_VERTICAL: RTF_Vertical(hEdit); SetButtonHV(hEdit, hTool); InvalidateRect(hRuler, NULL, TRUE); break; case IDM_HORIZONTAL: RTF_Horizontal(hEdit); SetButtonHV(hEdit, hTool); InvalidateRect(hRuler, NULL, TRUE); 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, 9, (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); IsPasteButtonAvailable(hEdit, hTool); SetButtonHV(hEdit, hTool); SetAlignmentButton(hEdit, hTool); } break; case IDM_2INCH: RTF_SetTab(hEdit, 2880); InvalidateRect(hRuler, NULL, TRUE); break; case IDM_INCH: RTF_SetTab(hEdit, 1440); InvalidateRect(hRuler, NULL, TRUE); break; case IDM_05INCH: RTF_SetTab(hEdit, 720); InvalidateRect(hRuler, NULL, TRUE); break; case IDM_2CM: RTF_SetTab(hEdit, 1134); InvalidateRect(hRuler, NULL, TRUE); break; case IDM_CM: RTF_SetTab(hEdit, 567); InvalidateRect(hRuler, NULL, TRUE); break; case IDM_05CM: RTF_SetTab(hEdit, 284); InvalidateRect(hRuler, NULL, TRUE); break; case IDM_NUM: RTF_Num(hEdit); break; case IDM_TOOL: GetClientRect(hWnd, &rc); mylp = (LPARAM)MAKELONG(rc.right - rc.left, rc.bottom - rc.top); if (bToolVisible) { ShowWindow(hTool, SW_HIDE); bToolVisible = FALSE; } else { ShowWindow(hTool, SW_SHOW); bToolVisible = TRUE; } SendMessage(hWnd, WM_SIZE, (WPARAM)SIZE_RESTORED, mylp); break; case IDM_STATUS: GetClientRect(hWnd, &rc); mylp = (LPARAM)MAKELONG(rc.right - rc.left, rc.bottom - rc.top); SetFocus(hEdit); if (bStatusVisible) { ShowWindow(hStatus, SW_HIDE); bStatusVisible = FALSE; } else { ShowWindow(hStatus, SW_SHOW); bStatusVisible = TRUE; } SendMessage(hWnd, WM_SIZE, (WPARAM)SIZE_RESTORED, mylp); break; case IDM_RULER: GetClientRect(hWnd, &rc); mylp = (LPARAM)MAKELONG(rc.right - rc.left, rc.bottom - rc.top); if (bRulerVisible) { ShowWindow(hRuler, SW_HIDE); bRulerVisible = FALSE; } else { ShowWindow(hRuler, SW_SHOW); bRulerVisible = TRUE; } SendMessage(hWnd, WM_SIZE, (WPARAM)SIZE_RESTORED, mylp); 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: if(SetWindowLong(hTool, GWL_WNDPROC, (LONG)Org_ToolProc) == 0) MessageBox(NULL, "サブクラス化解除失敗", "失敗", MB_OK); if(SetWindowLong(hRuler, GWL_WNDPROC, (LONG)Org_StaticProc) == 0) MessageBox(NULL, "サブクラス化解除失敗(hStatic)", "失敗", MB_OK); 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; }

ボタンが増えたのでボタン関係のところが少し変更がありました。 また、ローカル変数のnRulerH(ルーラーの高さ)、mylpが追加されました。
リッチエディットコントロールを作ったすぐ後でEM_EXLIMITTEXTで最大文字数を 1メガまで増やしました。
ツールバー,ステータスバー、ルーラーの「表示」「非表示」でWM_SIZEのところの 計算が少し変わりました。内容はこの部分を読んでみればすぐにわかります。
WM_COMMANDのところで

switch (HIWORD(wp)) { case EN_MAXTEXT: MessageBox(hWnd, "入力文字数の制限を越えました!", "警告!", MB_OK); SetFocus(hEdit); break; }

としてEN_MAXTEXTを捕まえている点に注意して下さい。
IDM_DELETEのところでWM_CLEARメッセージを送っています。
IDM_RULER, IDM_STATUS, IDM_RLUERのところをよく見て下さい。 bXXXVisible変数によってShowWindow関数によってツールバーなどを表示したり 非表示にしたりしています。そのあと、エディットコントロールに大きさ 位置を調整しなくてはいけないので親ウィンドウのプロシージャに WM_SIZEメッセージを送っています。この時副メッセージもきちんと 設定しないとおかしなことになります。WPARAMはSIZE_RESTOREDにします。 LPARAMの下位は親ウィンドウの横幅、上位は高さにします。 この時LPARAMを作るにはMAKELONG(またはMAKELPARAM) マクロを使うと便利です。 MAKELONGマクロについては第69章を参照して下さい。

SetInitialFont, SetMyFont, SetCenter, SetLeft, SetRight,

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

void ClearCheck(HMENU hMenu) { CheckMenuItem(hMenu, IDM_LEFT, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_RIGHT, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_CENTER, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_05CM, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_CM, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_2CM, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_05INCH, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_INCH, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_2INCH, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_NUM, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_TOOL, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_STATUS, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_RULER, MF_BYCOMMAND | MF_UNCHECKED); return; }

ツールバー,ステータスバー、ルーラーの表示・非表示メニュー項目が 増えた分チェックはずしが増えました。

RTF_Save, RTF_SaveAs, MySaveProc, RTF_Open, MyReadProc

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

void RTF_CheckMenu(HWND hEdit, HMENU hMenu) { CHARRANGE cr; PARAFORMAT pf; SendMessage(hEdit, EM_EXGETSEL, 0, (LPARAM)&cr); if (cr.cpMin == cr.cpMax) { EnableMenuItem(hMenu, IDM_CUT, MF_GRAYED | MF_BYCOMMAND); EnableMenuItem(hMenu, IDM_COPY, MF_GRAYED | MF_BYCOMMAND); EnableMenuItem(hMenu, IDM_DELETE, MF_GRAYED | MF_BYCOMMAND); } else { EnableMenuItem(hMenu, IDM_CUT, MF_ENABLED | MF_BYCOMMAND); EnableMenuItem(hMenu, IDM_COPY, MF_ENABLED | MF_BYCOMMAND); EnableMenuItem(hMenu, IDM_DELETE, MF_ENABLED | MF_BYCOMMAND); } if (SendMessage(hEdit, EM_GETMODIFY, 0, 0)) { EnableMenuItem(hMenu, IDM_UNDO, MF_ENABLED | MF_BYCOMMAND); } else { EnableMenuItem(hMenu, IDM_UNDO, MF_GRAYED | MF_BYCOMMAND); } if (SendMessage(hEdit, EM_CANPASTE, 0, 0)) { EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED | MF_BYCOMMAND); } else { EnableMenuItem(hMenu, IDM_PASTE, MF_GRAYED | MF_BYCOMMAND); } if (SendMessage(hEdit, EM_GETOPTIONS, 0, 0) & ECO_VERTICAL) { EnableMenuItem(hMenu, IDM_VERTICAL, MF_GRAYED | MF_BYCOMMAND); EnableMenuItem(hMenu, IDM_HORIZONTAL, MF_ENABLED | MF_BYCOMMAND); } else { EnableMenuItem(hMenu, IDM_VERTICAL, MF_ENABLED | MF_BYCOMMAND); EnableMenuItem(hMenu, IDM_HORIZONTAL, MF_GRAYED | MF_BYCOMMAND); } memset(&pf, 0, sizeof(PARAFORMAT)); pf.cbSize = sizeof(PARAFORMAT); SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); ClearCheck(hMenu);//まずメニューのチェックを全部はずす switch (pf.wAlignment) { case PFA_LEFT: CheckMenuItem(hMenu, IDM_LEFT, MF_CHECKED | MF_BYCOMMAND); break; case PFA_RIGHT: CheckMenuItem(hMenu, IDM_RIGHT, MF_CHECKED | MF_BYCOMMAND); break; case PFA_CENTER: CheckMenuItem(hMenu, IDM_CENTER, MF_CHECKED | MF_BYCOMMAND); break; } if (pf.dwMask & PFM_TABSTOPS) { switch (pf.rgxTabs[0]) { case 2880: CheckMenuItem(hMenu, IDM_2INCH, MF_CHECKED | MF_BYCOMMAND); break; case 1440: CheckMenuItem(hMenu, IDM_INCH, MF_CHECKED | MF_BYCOMMAND); break; case 720: CheckMenuItem(hMenu, IDM_05INCH, MF_CHECKED | MF_BYCOMMAND); break; case 567: CheckMenuItem(hMenu, IDM_CM, MF_CHECKED | MF_BYCOMMAND); break; case 1134: CheckMenuItem(hMenu, IDM_2CM, MF_CHECKED | MF_BYCOMMAND); break; case 284: CheckMenuItem(hMenu, IDM_05CM, MF_CHECKED | MF_BYCOMMAND); break; } } if (pf.wNumbering == PFN_BULLET) { CheckMenuItem(hMenu, IDM_NUM, MF_CHECKED | MF_BYCOMMAND); bNum = TRUE; } else { bNum = FALSE; } if (bToolVisible) CheckMenuItem(hMenu, IDM_TOOL, MF_CHECKED | MF_BYCOMMAND); if (bStatusVisible) CheckMenuItem(hMenu, IDM_STATUS, MF_CHECKED | MF_BYCOMMAND); if (bRulerVisible) CheckMenuItem(hMenu, IDM_RULER, MF_CHECKED | MF_BYCOMMAND); return; }

文字列が選択されている(CHARRANGE構造体のcpMinとcpMaxが異なる)時は メニュー項目の「削除」を有効にして、そうでないときは灰色表示で無効に しています。

また、グローバル変数のbXXXVisibleを調べて「ツールバー」「ステータスバー」 「ルーラー」の項目にチェックをつけるかどうか判定します。

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, ID_TOOLBAR, 9, (HINSTANCE)HINST_COMMCTRL, IDB_STD_SMALL_COLOR, tbBut, 9, 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; }

ボタンが増えた分,ちょっと変更になりました。

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, 14, (LPARAM)&tbSep); SendMessage(hTool, TB_INSERTBUTTON, 17, (LPARAM)&tbSep); SendMessage(hTool, TB_INSERTBUTTON, 21, (LPARAM)&tbSep); return; }

これも,ボタンが増えた関係上少し変更があります。

MakeMyStatusbar

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

void SetStatusFontInfo(HWND hStatus, HWND hEdit) { CHARFORMAT cf; char szFontSize[32]; int nFontSize; memset(&cf, 0, sizeof(CHARFORMAT)); cf.cbSize = sizeof(CHARFORMAT); SendMessage(hEdit, EM_GETCHARFORMAT, (WPARAM)TRUE, (LPARAM)&cf); nFontSize = cf.yHeight / 20; if (cf.yHeight % 20 >= 10) nFontSize++; SendMessage(hStatus, SB_SETTEXT, (WPARAM)0, (LPARAM)cf.szFaceName); wsprintf(szFontSize, "%d", nFontSize); strcat(szFontSize, " point"); SendMessage(hStatus, SB_SETTEXT, (WPARAM)1, (LPARAM)szFontSize); return; }

フォントの高さを20で割って、あまりが10以上のときは ポイント数に1をたすようにしました。(四捨五入)

BOOL IsEditButtonAvailable(HWND hEdit, HWND hTool) { CHARRANGE cr; SendMessage(hEdit, EM_EXGETSEL, 0, (LPARAM)&cr); if (cr.cpMin == cr.cpMax){ SendMessage(hTool, TB_ENABLEBUTTON, IDM_CUT, FALSE); SendMessage(hTool, TB_ENABLEBUTTON, IDM_COPY, FALSE); SendMessage(hTool, TB_ENABLEBUTTON, IDM_DELETE, FALSE); return FALSE; } else { SendMessage(hTool, TB_ENABLEBUTTON, IDM_CUT, TRUE); SendMessage(hTool, TB_ENABLEBUTTON, IDM_COPY, TRUE); SendMessage(hTool, TB_ENABLEBUTTON, IDM_DELETE, TRUE); return TRUE; } }

文字列が選択されているときは「削除」ボタンを有効に、そうでないときは 無効にしています。

IsPasteButtonAvailable, SetStatusClock, RTF_SetTab, SetAlignmentButton, SetButtonHV, MyToolProc, RTF_Num, MakeMyRuler, MyStaticProc

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

今回はちょっとした付け足しでした。最初からビシッと計画をたてて プログラムを作っているとこのような付け足しは生じません。 しかし、プログラムを書いていくうちに「ああしたい」「こうしたい」 という欲求が増えたり、思いがけない不具合が生じて追加・変更が 生じるものです。特にツールバーのボタンを増やした時に、どの関数を 変更しなくてはいけないかを知ることは重要です。


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

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