第143章 RTFにタブを設定する


今回は,表題のとおりタブの設定をします。それと前回までの 不満点,不都合を多少解決します。 すでに作った関数もほんの少し合理的にします。



まずは、今まで作ったプログラムでは

(1)段落によって「右揃え」「左揃え」「中央揃え」などが  まちまちのときカーソル位置を他の段落に移してもボタンが対応していない (2)ツールバーをカスタマイズしたときボタンの押下状態が  何も押されていない状態になる (3)ツールバーをダブルクリックして、ボタンをカスタマイズする場合  「区切り」を挿入するとボタンが間延びしてしまう

という不具合がありました。これらを解決します。 ほかにもまだだ不具合・不満がありますが今回はとりあえず このくらいの点について改善してみます。

まずは、タブの設定ですが

1.PARAFORMAT構造体のdwMaskにPFM_TABSTOPSを加える 2.cTabCountメンバに設定したいタブの個数を指定する 3.rgxTabs配列メンバに設定したいタブ位置を格納する 4.リッチエディットコントロールにEM_SETPARAFORMATメッセージを送る

これで、現在選択されている段落にタブを設定することができます。 タブ位置はtwip単位であることに注意してください。 1440twipは1論理インチ(約2.54cm)、567twipは1論理cmです。 (第136章参照)

次に(1)の問題は選択されている段落が変わったら現在の段落の状態 を調べてボタンに反映すれば良いですね。通知メッセージに応答して解決します。

(2)についてはカスタマイズ後(1)と同じ処理をすれば解決です。

(3)メニューの「ツールバーのカスタマイズ」を実行すれば強制的に 直すようにしたので、ツールバーがダブルクリックされた時WM_LBUTTONDBLCLK メッセージがツールバーのプロシージャに行かないようにして、なおかつ 親ウィンドウにWM_COMMANDメッセージを送ってメニューから選択したのと 同じ状態を作ってやれば良いですね。手っ取り早い方法として ツールバーをサブクラス化してWM_LBUTTONDBLCLKを横取りします。 そして、親ウィンドウにWM_COMMANDメッセージを送ることにします。

では、プログラムを見てみます。

// rich14x.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 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 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 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 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"

メニューにタブの設定項目が増えました。タブの間隔は等間隔で なくても良いのですが、実際には等間隔にすることがほとんどなので 最初からメニューでいくつかの間隔幅を用意しました。

// rich14x.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 #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 *); LRESULT CALLBACK MyTabDlg(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyToolProc(HWND, UINT, WPARAM, LPARAM); 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); void RTF_SetTab(HWND, int); void RTF_GetTab(HWND); //現在の段落配置法を調べそのようにボタンを設定 void SetAlignmentButton(HWND, HWND); void SetButtonHV(HWND, HWND); char szClassName[] = "rich14x"; //ウィンドウクラス 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]; WNDPROC Org_ToolProc;//ツールバーのプロシージャ 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} };

CheckButtonState関数はあんまり意味がないのでやめました。 新たに段落の状態を取得してそれに見合ったボタン状態を作る関数を 作りました。

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); 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); //ボタンを復元してから次の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); 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); 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); 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); 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_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); SetButtonHV(hEdit, hTool); break; case IDM_HORIZONTAL: RTF_Horizontal(hEdit); SetButtonHV(hEdit, hTool); 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); IsPasteButtonAvailable(hEdit, hTool); SetButtonHV(hEdit, hTool); SetAlignmentButton(hEdit, hTool); } break; case IDM_2INCH: RTF_SetTab(hEdit, 2880); break; case IDM_INCH: RTF_SetTab(hEdit, 1440); break; case IDM_05INCH: RTF_SetTab(hEdit, 720); break; case IDM_2CM: RTF_SetTab(hEdit, 1134); break; case IDM_CM: RTF_SetTab(hEdit, 567); break; case IDM_05CM: RTF_SetTab(hEdit, 284); 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); 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のところでは、レジストリからボタンの配列を復元した後 ボタン状態を設定する4つの関数を呼び出しています。 このうちIsPasteButtonAvailable関数はWM_TIMERメッセージが来るたびに 呼ばれるのでここで呼ばなくても特に問題はありませんが、一応ボタン状態の 設定ということで呼んでおくことにしました。

そして、WM_CREATEの最後のところでツールバー(ウィンドウ)を サブクラス化しています。サブクラス化については 第36章を参照してください。

TBN_RESETのところでもボタン状態を設定する4つの関数を呼んでいます。

EN_SELCHANGEのところでも同じく呼んでいます。

IDM_CUSTOMIZEのところでも同じです。

新たにタブ関係(IDM_2INCHなど)のところでは すべてRTF_SetTab関数を呼んで済ませています。 RTF_SetTab関数については後述します。

プログラムを終了するときサブクラス化の解除を忘れないでください。

SetInitialFont, SetMyFont

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

BOOL SetCenter(HWND hEdit) { PARAFORMAT pf; memset(&pf, 0, sizeof(PARAFORMAT)); pf.cbSize = sizeof(PARAFORMAT); SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); pf.dwMask |= PFM_ALIGNMENT; pf.wAlignment = PFA_CENTER; SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf); SetFocus(hEdit); return TRUE; } BOOL SetLeft(HWND hEdit) { PARAFORMAT pf; memset(&pf, 0, sizeof(PARAFORMAT)); pf.cbSize = sizeof(PARAFORMAT); SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); pf.dwMask |= PFM_ALIGNMENT; pf.wAlignment = PFA_LEFT; SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf); SetFocus(hEdit); return TRUE; } BOOL SetRight(HWND hEdit) { PARAFORMAT pf; memset(&pf, 0, sizeof(PARAFORMAT)); pf.cbSize = sizeof(PARAFORMAT); SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); pf.dwMask |= PFM_ALIGNMENT; pf.wAlignment = PFA_RIGHT; SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf); SetFocus(hEdit); return TRUE; }

たいした変更ではないのですが、今まではdwMaskメンバは PFM_ALIGNMENTしかありませんでした。しかし、今回は タブを設定することも考慮して

pf.dwMask |= PFM_ALIGNMENT;

というようにしました。

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, MakeMyToolbar, InsertSep, MakeMyStatusbar, SetStatusFontInfo, SetStatusFontInfo, IsPasteButtonAvailable, SetStatusClock,

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

// タブの設定 void RTF_SetTab(HWND hEdit, int unit) { PARAFORMAT pf; int i; memset(&pf, 0, sizeof(PARAFORMAT)); pf.cbSize = sizeof(PARAFORMAT); SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); pf.dwMask |= PFM_TABSTOPS; pf.cTabCount = MAX_TAB_STOPS; for (i = 0; i < MAX_TAB_STOPS; i++) pf.rgxTabs[i] = unit * (i + 1); SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf); SetFocus(hEdit); return; }

タブの設定をする関数です。unitにあけたい間隔をtwip単位で 設定します。あとは、最初の説明を読めばわかると思います。 MAX_TAB_STOPSはrichedit.hで次のように定義されています。

#define MAX_TAB_STOPS 32

// 現在の段落の配置法(center, right, left)を調べてボタンに反映 void SetAlignmentButton(HWND hEdit, HWND hTool) { PARAFORMAT pf; memset(&pf, 0, sizeof(PARAFORMAT)); pf.cbSize = sizeof(PARAFORMAT); SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf); //一度すべてのボタンを使用可能にする SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_LEFT, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_RIGHT, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_CENTER, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); //wAlignmentを調べて押下状態にする switch (pf.wAlignment) { case PFA_RIGHT: SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_RIGHT, (LPARAM)MAKELONG(TBSTATE_PRESSED, 0)); break; case PFA_LEFT: SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_LEFT, (LPARAM)MAKELONG(TBSTATE_PRESSED, 0)); break; case PFA_CENTER: SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_CENTER, (LPARAM)MAKELONG(TBSTATE_PRESSED, 0)); break; } return; }

現在の段落が「左揃え」か「右揃え」か「中央揃え」かを 調べてそのボタンを押下状態に設定します。

//縦書きか横書きかを調べてボタンをそのように設定 void SetButtonHV(HWND hEdit, HWND hTool) { UINT opt; opt = SendMessage(hEdit, EM_GETOPTIONS, 0, 0); if (opt & ECO_VERTICAL) { SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_VERTICAL, (LPARAM)MAKELONG(TBSTATE_PRESSED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_HORIZONTAL, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); } else { SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_VERTICAL, (LPARAM)MAKELONG(TBSTATE_ENABLED, 0)); SendMessage(hTool, TB_SETSTATE, (WPARAM)IDM_HORIZONTAL, (LPARAM)MAKELONG(TBSTATE_PRESSED, 0)); } return; }

「縦書き」か「横書き」かを調べてボタンに反映させます。

//サブクラス化したツールバープロシージャ LRESULT CALLBACK MyToolProc(HWND hSTool, UINT msg, WPARAM wp, LPARAM lp) { HWND hParent; switch (msg) { case WM_LBUTTONDBLCLK: hParent = FindWindow("rich14x", "猫でもわかるRTF"); if (hParent == NULL) { MessageBox(hSTool, "メインウィンドウを取得できません", "Error!", MB_OK | MB_ICONHAND); return(CallWindowProc(Org_ToolProc, hSTool, msg, wp, lp)); } SendMessage(hParent, WM_COMMAND, (WPARAM)IDM_CUSTOMIZE, 0); break; default: return(CallWindowProc(Org_ToolProc, hSTool, msg, wp, lp)); } return 0; }

ツールバー(ウィンドウ)をサブクラス化してWM_LBUTTONDBLCLKメッセージを 横取りします。ところで親ウィンドウ(メインウィンドウ)のハンドルを 知るにはどうしたら良いでしょうか。いくつか方法がありますが(親のハンドルを グローバル変数にコピーしておくなど)ここでは、FindWindow関数を 使ってみることにしました。

HWND FindWindow( LPCTSTR lpClassName, // クラス名 LPCTSTR lpWindowName // ウィンドウの名前 );

lpClassNameにはクラス名を、lpWindowNameにはウィンドウ名を 指定するとそのウィンドウのハンドルを返します。 子ウィンドウは探しません。条件に合うウィンドウがない場合は NULLを返します。

さて、親のハンドルがわかった後親にWM_COMMANDメッセージを 送りますがこのときWPARAMとかLPARAMはどうしたらよいのでしょうか。 ここでは単にWPARAMにIDM_CUSTOMIZEを設定しておきました。 これがWndProcに行くと、switch (msg)でWM_COMMANDに振り分けられ さらにswitch (LOWORD(wp))でIDM_CUSTOMIZEに振り分けられます。

さて、まだほかにもいろいろ不満はありますがきりがないですね。


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

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