第305章 ツールバーなどを付ける


今回は、ツールバーとステータスバーを付けました。また、編集機能も 追加しました。



基本的には第258章と同じ要領で作れますが、エディットコントロールの 部分が少し違っています。ツールバーとエディットコントロールの境目が 影になって、エディットコントロールが少しくぼんだところにあるように見えます。



では、さっそくプログラムを見てみましょう。

// htmledit.h typedef struct _tagHData { char szTagNo[4]; char szContents[256]; } MYHTAG, *LPMYHTAG; typedef struct _tagImgData { char szFileName[MAX_PATH]; char szPath[MAX_PATH]; BOOL bPath; } MYIMGTAG, *LPMYIMGTAG; typedef struct _tagTableData { char szRow[8]; char szColumn[8]; char szTitle[64]; char szTitleAlign[16]; char szBorder[8]; BOOL bTitle; BOOL bBorder; } MYTABLETAG, *LPMYTABLETAG; typedef struct _tagFormData { char szMethod[8]; char szAction[64]; char szName[16]; char szID[16]; BOOL bMethod; BOOL bAction; BOOL bName; BOOL bID; } MYFORMTAG, *LPMYFORMTAG; typedef struct _tagInputData { char szType[16]; char szValue[64]; char szName[16]; char szID[16]; char szOnClick[64]; char szOnBlur[64]; char szOnChange[64]; char szOnFocus[64]; char szOnSubmit[64]; BOOL bValue; BOOL bName; BOOL bID; BOOL bClick; BOOL bBlur; BOOL bChange; BOOL bFocus; BOOL bSubmit; } MYINPUTTAG, *LPMYINPUTTAG;

typedefの部分が長くなったので、ヘッダファイルにまとめました。 中身は前章までと同じです。

// htmledit05.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 "アプリケーションの終了(&X)", IDM_END END POPUP "編集(&E)" BEGIN MENUITEM "元に戻す(&U)", IDM_UNDO MENUITEM "切り取り(&T)", IDM_CUT MENUITEM "コピー(&C)", IDM_COPY MENUITEM "貼り付け(&P)", IDM_PASTE MENUITEM "削除(&D)", IDM_DELETE MENUITEM SEPARATOR MENUITEM "すべて選択(&L)", IDM_ALL END POPUP "挿入(&I)" BEGIN MENUITEM "基本項目入力(&B)...", IDM_BASICINPUT MENUITEM SEPARATOR POPUP "タグの挿入" BEGIN MENUITEM "<P>", IDM_P MENUITEM "<BR>", IDM_BR MENUITEM "<H*></H*>...", IDM_H MENUITEM "<IMG>...", IDM_IMAGE MENUITEM "<A HREF></A>...", IDM_A MENUITEM "<TABLE></TABLE>...", IDM_TABLE MENUITEM "<FORM></FORM>...", IDM_FORM MENUITEM "<INPUT>...", IDM_INPUT END POPUP "JavaScriptの挿入" BEGIN MENUITEM "<SCRIPT>", IDM_SCRIPT END END POPUP "ブラウザ(&B)" BEGIN MENUITEM "ブラウザ起動(&E)", IDM_BROWSER END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYBASICINPUT DIALOG DISCARDABLE 0, 0, 187, 121 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "基本項目入力" FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT1,39,7,141,14,ES_AUTOHSCROLL EDITTEXT IDC_EDIT2,39,27,141,14,ES_AUTOHSCROLL EDITTEXT IDC_EDIT3,39,47,141,14,ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,39,100,50,14 PUSHBUTTON "キャンセル",IDCANCEL,96,100,50,14 LTEXT "タイトル",IDC_STATIC,7,7,23,8 LTEXT "作者",IDC_STATIC,7,30,15,8 LTEXT "E-Mail",IDC_STATIC,7,47,20,8 CONTROL "色",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,35,76,23,10 CONTROL "壁紙",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,67,76,32, 10 GROUPBOX "背景",IDC_STATIC,26,67,133,26 CONTROL "指定しない",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,108, 76,46,10 END MYHTAG DIALOG DISCARDABLE 0, 0, 187, 93 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "見出しタグの挿入" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,40,72,50,14 PUSHBUTTON "キャンセル",IDCANCEL,95,72,50,14 COMBOBOX IDC_COMBO1,51,7,18,68,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "大きさ",IDC_STATIC,7,7,32,11 LTEXT "コンテンツ",IDC_STATIC,7,27,39,10 EDITTEXT IDC_EDIT1,51,27,129,32,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN END MYIMGTAG DIALOG DISCARDABLE 0, 0, 187, 91 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "イメージの挿入" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,43,70,41,14 PUSHBUTTON "キャンセル",IDCANCEL,101,70,41,14 CONTROL "パス付き",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,42,15 EDITTEXT IDC_EDIT1,50,7,107,16,ES_AUTOHSCROLL LTEXT "ファイル名",IDC_STATIC,7,33,38,11 EDITTEXT IDC_EDIT2,50,29,107,16,ES_AUTOHSCROLL PUSHBUTTON "参照",IDC_BUTTON1,160,31,20,15 CONTROL "画像を確認する",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,52,61,15 END MYTABLETAG DIALOG DISCARDABLE 0, 0, 95, 133 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "テーブルの挿入" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,112,33,14 PUSHBUTTON "キャンセル",IDCANCEL,46,112,33,14 LTEXT "行",IDC_STATIC,7,7,11,10 COMBOBOX IDC_COMBO1,29,7,23,58,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP LTEXT "列",IDC_STATIC,7,27,11,10 COMBOBOX IDC_COMBO2,29,25,23,55,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP CONTROL "BORDER",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,49,41,12 EDITTEXT IDC_EDIT1,51,48,34,14,ES_AUTOHSCROLL CONTROL "CAPTION",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,44,12 COMBOBOX IDC_COMBO3,51,67,34,45,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_EDIT2,17,89,71,14,ES_AUTOHSCROLL END MYFORMTAG DIALOG DISCARDABLE 0, 0, 187, 103 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "フォームの挿入" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,38,82,50,14 PUSHBUTTON "キャンセル",IDCANCEL,97,82,50,14 CONTROL "METHOD",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,47,12 COMBOBOX IDC_COMBO1,65,7,52,41,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP CONTROL "ACTION",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,25,43,12 EDITTEXT IDC_EDIT1,65,25,114,12,ES_AUTOHSCROLL CONTROL "NAME",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, 7,43,34,12 EDITTEXT IDC_EDIT2,65,43,114,12,ES_AUTOHSCROLL CONTROL "ID",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7, 61,32,12 EDITTEXT IDC_EDIT3,65,61,114,12,ES_AUTOHSCROLL END MYINPUTTAG DIALOG DISCARDABLE 0, 0, 135, 203 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "INPUTの挿入" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,17,182,50,14 PUSHBUTTON "キャンセル",IDCANCEL,71,182,50,14 LTEXT "TYPE",IDC_STATIC,7,7,24,9 COMBOBOX IDC_COMBO1,49,7,45,92,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP CONTROL "NAME",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, 7,48,35,14 CONTROL "ID",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7, 67,25,14 CONTROL "onClick",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,86,35,14 EDITTEXT IDC_EDIT4,49,87,75,13,ES_AUTOHSCROLL EDITTEXT IDC_EDIT2,49,49,75,13,ES_AUTOHSCROLL EDITTEXT IDC_EDIT3,49,67,75,13,ES_AUTOHSCROLL EDITTEXT IDC_EDIT1,49,29,75,13,ES_AUTOHSCROLL CONTROL "VALUE",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, 7,29,37,14 CONTROL "onBlur",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,105,36,14 EDITTEXT IDC_EDIT5,49,105,75,13,ES_AUTOHSCROLL CONTROL "onChange",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,124,40,14 EDITTEXT IDC_EDIT6,49,125,75,13,ES_AUTOHSCROLL CONTROL "onFocus",IDC_CHECK7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,143,37,14 EDITTEXT IDC_EDIT7,49,143,75,13,ES_AUTOHSCROLL CONTROL "onSubmit",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,162,40,14 EDITTEXT IDC_EDIT8,49,163,75,13,ES_AUTOHSCROLL END ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. MYICON ICON DISCARDABLE "htmledit.ico"

「元に戻す」「切り取り」「コピー」「貼り付け」「削除」「すべて選択」などの メニュー項目が増えました。

// htmedit05.cpp #ifndef STRICT #define STRICT #endif #define ID_EDIT 100 #define ID_EDIT2 101 #define ID_TOOL1 102 #define ID_TOOL2 103 #define ID_TOOLMENU 104 #define ID_REBAR 104 #define ID_STATIC 105 #define ID_STATUS 106 #define MY_BUF_SIZE 1024 * 64 - 1 #define MY_MSG WM_USER #include <windows.h> #include <windowsx.h> #include "resource.h" #include "htmledit.h" #include <commctrl.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyBasicInputProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyHProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyImgProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyAProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyTableProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyFormProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyInputProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NewEditProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL MySetHTML(HWND, HWND); int MyBasicInput(HWND); BOOL MySaveAs(HWND); BOOL MySave(HWND); BOOL MyInsertTag(HWND, HWND, char *); BOOL MyInsertH(HWND, HWND); BOOL MyInsertIMG(HWND, HWND); BOOL MyGetFileTitle(HWND, HWND, BOOL); BOOL MyGetBodyColor(HWND); BOOL MyGetWallPaper(HWND); BOOL MyInsertA(HWND, HWND); BOOL MyGetHREFFile(HWND, HWND, BOOL); BOOL MyInsertTable(HWND, HWND); BOOL MyInsertForm(HWND, HWND); BOOL MyInsertInput(HWND, HWND); BOOL MyInsertScript(HWND, HWND); HWND MakeMyToolbar(HWND, int, TBBUTTON *, int); BOOL MyOpen(HWND, HWND); BOOL CheckMyMenu(HMENU, HWND, HWND); BOOL CanPaste(HWND); BOOL MySetStatusText(HWND, int, char *); char szClassName[] = "htmedit05"; //ウィンドウクラス char *lpszWinTitleOrg = "猫でもわかるHTMLエディタ[%s]"; char *lpszHead = "<HTML>\r\n<HEAD>\r\n" "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=x-sjis\">\r\n<TITLE>"; char szTitle[64] = "タイトル"; char *lpszBody1 = "</TITLE>\r\n</HEAD>\r\n<BODY"; char szBody2[256]; char *lpszBody3 =">\r\n"; char *lpszAddress = "<ADDRESS>"; char *lpszMailto = "<A HREF=\"mailto:"; char szEMail[256] = "webmaster@kumei.ne.jp"; char *lpszMailEnd = "\">"; char szAuthor[64] = "Yasutaka Kumei"; char *lpszCloseA = "</A>"; char *lpszEnd = "</ADDRESS>\r\n</BODY>\r\n</HTML>"; char szFileName[MAX_PATH]; char szFileTitle[64]; WNDPROC OrgEditProc; TBBUTTON tbButton1[] = { {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}, }; TBBUTTON tbButton2[] = { {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_DELETE, IDM_DELETE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, {STD_UNDO, IDM_UNDO, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0}, };

ツールバー、ステータスバー、レバーコントロールなどのID定義が増えました。

また、自分で定義したメッセージ(MY_MSG)があります。

typedef部分は全部ヘッダーファイルに行ったのでなくなりました。

自作ヘッダーファイルhtmledit.hをincludeしています。

コモンコントロールの前準備を忘れないでください。

前回までHTMLファイルの作者名をszNameグローバル変数に格納していましたが、 タグのアトリビュートのNAMEと紛らわしいのでszAuthorに変更したので注意してください。

ツールバーを作るので例によって、TBBUTTON構造体の変数がいくつか増えています。

WinMain, InitApp, InitInstanceの各関数に変更はありません。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static HWND hEdit, hEdit_hide, hTool1, hTool2, hRebar, hStatic, hStatus; HINSTANCE hInst; CREATESTRUCT *lpcs; char szWinTitle[64]; INITCOMMONCONTROLSEX ic; REBARINFO ri; REBARBANDINFO rbinfo; RECT rc; static int nClientX, nClientY, nRebarH, nStatusH; LPNMHDR lpnmhdr; int sb_size[3]; static HMENU hMenu; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES; InitCommonControlsEx(&ic); wsprintf(szWinTitle, lpszWinTitleOrg, "無題"); SetWindowText(hWnd, szWinTitle); lpcs = (CREATESTRUCT *)lp; hInst = lpcs->hInstance; hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_HSCROLL | WS_VSCROLL, 0, 0, 0, 0, hWnd, (HMENU)ID_EDIT, hInst, NULL); OrgEditProc = (WNDPROC)GetWindowLong(hEdit, GWL_WNDPROC); SetWindowLong(hEdit, GWL_WNDPROC, (LONG)NewEditProc); hEdit_hide = CreateWindow("EDIT", "", WS_CHILD, 0, 0, 0, 0, hEdit, (HMENU)ID_EDIT2, hInst, NULL); hStatic = CreateWindow("STATIC", "", WS_CHILD | WS_VISIBLE | SS_SUNKEN, 0, 0, 0, 0, hWnd, (HMENU)ID_STATIC, hInst, NULL); hRebar = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | RBS_BANDBORDERS | RBS_VARHEIGHT, 0, 0, 0, 0, hWnd, (HMENU)ID_REBAR, hInst, NULL); hTool1 = MakeMyToolbar(hRebar, 3, tbButton1, ID_TOOL1); hTool2 = MakeMyToolbar(hRebar, 5, tbButton2, ID_TOOL2); hStatus = CreateStatusWindow(WS_CHILD | WS_VISIBLE, "", hWnd, ID_STATUS); memset(&ri, 0, sizeof(REBARINFO)); ri.cbSize = sizeof(REBARINFO); ri.fMask = 0; ri.himl = NULL; SendMessage(hRebar, RB_SETBARINFO, 0, (LPARAM)&ri); memset(&rbinfo, 0, sizeof(REBARBANDINFO)); rbinfo.cbSize = sizeof(REBARBANDINFO); rbinfo.fMask = RBBIM_TEXT | RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE; rbinfo.fStyle = RBBS_CHILDEDGE; rbinfo.lpText = "ファイル"; rbinfo.hwndChild = hTool1; rbinfo.cxMinChild = 0; rbinfo.cyMinChild = 25; rbinfo.cx = 120; SendMessage(hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbinfo); GetWindowRect(hRebar, &rc); rbinfo.lpText = "編集"; rbinfo.hwndChild = hTool2; rbinfo.cxMinChild = 0; rbinfo.cyMinChild = 25; rbinfo.cx = (rc.right - rc.left) - rbinfo.cx; SendMessage(hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbinfo); hMenu = GetMenu(hWnd); SendMessage(hEdit, MY_MSG, 0, (LPARAM)hTool2); CheckMyMenu(hMenu, hEdit, hTool2); break; case WM_SIZE: nClientX = LOWORD(lp); nClientY = HIWORD(lp); MoveWindow(hStatic , 0, 0, nClientX, 2, TRUE); GetWindowRect(hRebar, &rc); nRebarH = rc.bottom - rc.top; GetWindowRect(hStatus, &rc); nStatusH = rc.bottom - rc.top; SendMessage(hRebar, WM_SIZE, wp, lp); sb_size[2] = nClientX; sb_size[1] = nClientX - 200; sb_size[0] = 300; SendMessage(hStatus, SB_SETPARTS, (WPARAM)3, (LPARAM)sb_size); SendMessage(hStatus, WM_SIZE, wp, lp); MoveWindow(hEdit, 0, nRebarH + 2, LOWORD(lp), HIWORD(lp) - (nRebarH + 2 + nStatusH), TRUE); SetFocus(hEdit); break; case WM_NOTIFY: switch (wp) { case ID_REBAR: lpnmhdr = (LPNMHDR)lp; switch (lpnmhdr->code) { case RBN_HEIGHTCHANGE: GetWindowRect(hRebar, &rc); nRebarH = rc.bottom - rc.top; MoveWindow(hEdit, 0, nRebarH + 2, nClientX, nClientY - nRebarH - 2 - nStatusH, TRUE); break; } break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_BASICINPUT: if (MyBasicInput(hEdit) == IDCANCEL) break; id = MessageBox(hWnd, "現在のソースファイルが置き換わりますがよろしいですか", "注意", MB_YESNO | MB_ICONQUESTION); if (id == IDNO) break; if (MySetHTML(hEdit, hEdit_hide)) MySetStatusText(hStatus, 0, "基本項目を入力しました"); break; case IDM_SAVEAS: MySaveAs(hEdit); wsprintf(szWinTitle, lpszWinTitleOrg, szFileTitle); SetWindowText(hWnd, szWinTitle); break; case IDM_NEW: if (SendMessage(hEdit, EM_GETMODIFY, 0, 0)) { id = MessageBox(hWnd, "変更を保存しますか", "注意", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) MySave(hEdit); } SendMessage(hEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1); SendMessage(hEdit, WM_CLEAR, 0, 0); strcpy(szFileName, ""); strcpy(szFileTitle, ""); wsprintf(szWinTitle, lpszWinTitleOrg, "無題"); SetWindowText(hWnd, szWinTitle); break; case IDM_SAVE: id = MessageBox(hWnd, "上書きしてもよろしいですか", "上書き保存", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { MySave(hEdit); wsprintf(szWinTitle, lpszWinTitleOrg, szFileTitle); SetWindowText(hWnd, szWinTitle); } break; case IDM_P: MyInsertTag(hEdit, hEdit_hide, "<P>"); MySetStatusText(hStatus, 0, "<P>タグを挿入しました"); break; case IDM_BR: MyInsertTag(hEdit, hEdit_hide, "<BR>"); MySetStatusText(hStatus, 0, "<BR>タグを挿入しました"); break; case IDM_H: if (MyInsertH(hEdit, hEdit_hide)) MySetStatusText(hStatus, 0, "<H>タグを挿入しました");; break; case IDM_IMAGE: if (MyInsertIMG(hEdit, hEdit_hide)) MySetStatusText(hStatus, 0, "イメージを挿入しました"); break; case IDM_BROWSER: if (strcmp(szFileName, "") == 0) { MessageBox(hWnd, "まだHTMLファイルが保存されていません", "Error", MB_OK); break; } if (ShellExecute(NULL, "open", szFileName, NULL, NULL, SW_SHOWNORMAL) > (HINSTANCE)32) { MySetStatusText(hStatus, 0, "ブラウザが起動しました"); } else { MySetStatusText(hStatus, 0, "ブラウザの起動に失敗"); } return 0; case IDM_A: if (MyInsertA(hEdit, hEdit_hide)) MySetStatusText(hStatus, 0, "<A>タグを挿入しました"); break; case IDM_TABLE: if (MyInsertTable(hEdit, hEdit_hide)) MySetStatusText(hStatus, 0, "テーブルを挿入しました"); break; case IDM_FORM: if (MyInsertForm(hEdit, hEdit_hide)) MySetStatusText(hStatus, 0, "<FORM>タグを挿入しました"); break; case IDM_INPUT: if (MyInsertInput(hEdit, hEdit_hide)) MySetStatusText(hStatus, 0, "<INPUT>タグを挿入しました"); break; case IDM_SCRIPT: if (MyInsertScript(hEdit, hEdit_hide)) MySetStatusText(hStatus, 0, "<SCRIPT>タグを挿入しました"); break; case IDM_OPEN: MyOpen(hEdit, hEdit_hide); 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_DELETE: SendMessage(hEdit, WM_CLEAR, 0, 0); break; case IDM_ALL: SendMessage(hEdit, EM_SETSEL, (WPARAM)0, (LPARAM)-1); break; } CheckMyMenu(hMenu, hEdit, hTool2); SetFocus(hEdit); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if (SendMessage(hEdit, EM_GETMODIFY, 0, 0)) { id = MessageBox(hWnd, "変更を保存しますか", "保存", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) MySave(hEdit); } SetWindowLong(hEdit, GWL_WNDPROC, (LONG)OrgEditProc); DestroyWindow(hTool1); DestroyWindow(hTool2); DestroyWindow(hRebar); DestroyWindow(hStatus); DestroyWindow(hEdit_hide); DestroyWindow(hEdit); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

メインウィンドウのプロシージャです。

WM_CREATEメッセージが来たら、コモンコントロールの前準備をします。 INITCOMMONCONTROLSEX構造体のdwICCメンバはICC_BAR_CLASSES | ICC_COOL_CLASSESに 設定します。たいていのコモンコントロールはInitCommonControlsExを忘れても、何とか動作しますが レバーコントロールはICC_COOL_CLASSESを忘れると表示されないようです。

前章まではエディットコントロールはCreateWindow関数で作っていましたが、今回は WS_EX_CLIENTEDGEスタイルを実現したいためにCreateWindowEx関数を使っていることに注意してください。 これで、ツールバーとエディットコントロールの境にくぼみの影ができます。

エディットコントロールを作ったらすぐにこれをサブクラス化します。これは、エディットコントロールに WM_KEYUPとWM_LBUTTONUPメッセージが来たことを知るためです(後述)。

レバーコントロール、ツールバー、ステータスバーを作ります。作り方の詳細は 第182章第61章第57章を参照してください。

また、メニューとツールバーの境にスタティックコントロール(hStatic)を置いて多少見栄えを良くしている点に 注意してください。

WM_SIZEメッセージが来たら、スタティックコントロール、レバーコントロールステータスバーの サイズや位置を調整します。ツールバーはレバーコントロールに乗っかっているので調整の 必要はありません。

レバーコントロールの高さが変化したら(1列になったり、2列になったりした時)RBN_HEIGHTCHANGE 通知メッセージが来るので、これを捕まえます。そして、エディットコントロールの位置、サイズを調整します。

WM_COMMANDメッセージが来たら、例によってメニューから選択されたコマンドを実行します。 しかし、この処理の最後の所を注目してください。CheckMyMenu、SetFocus関数が呼ばれています。 何かを実行したらメニュー項目の使用可否を調べてエディットコントロールにフォーカスを移しています。 この必要のないコマンドはbreakでなくてreturnすれば実行されません。

タグの挿入などが実行されたときは、その内容をステータスバーに表示するようにしました。 MySetStatusText関数については後述します。

編集関連のメニュー項目が増えています。また、今まではファイルをオープンできず不便だったので これもできるようにしました。

プログラム終了時にはエディットコントロールのサブクラス化を解除して、コントロール類を破棄します。

BOOL MySetHTML(HWND hEdit, HWND hEdit_hide) { char szBuf[1024*10]; strcpy(szBuf, lpszHead); strcat(szBuf, szTitle); strcat(szBuf, lpszBody1); strcat(szBuf, szBody2); strcat(szBuf, lpszBody3); strcat(szBuf, lpszAddress); strcat(szBuf, lpszMailto); strcat(szBuf, szEMail); strcat(szBuf, lpszMailEnd); strcat(szBuf, szAuthor); strcat(szBuf, lpszCloseA); strcat(szBuf, lpszEnd); SetWindowText(hEdit, ""); MyInsertTag(hEdit, hEdit_hide, szBuf); return TRUE; }

引数が増えました。今まではSetWindowText関数でエディットコントロールにszBufの内容を 表示していましたが、これだとEM_GETMODIFYメッセージを送っても反応しません。 そこで、MyInsertTag関数で貼り付けを実行しています。これだとEM_GETMODIFYメッセージを 送ると0以外が返ってきます。

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

LRESULT CALLBACK MyBasicInputProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hTitle, hName, hEMail, hWallPaper, hColor, hNotSpecify; static int nBack; //0:nothing 1:Color 2:WallPaper switch (msg) { case WM_INITDIALOG: strcpy(szBody2, ""); hTitle = GetDlgItem(hDlg, IDC_EDIT1); hName = GetDlgItem(hDlg, IDC_EDIT2); hEMail = GetDlgItem(hDlg, IDC_EDIT3); hWallPaper = GetDlgItem(hDlg, IDC_RADIO2); hColor = GetDlgItem(hDlg, IDC_RADIO1); hNotSpecify = GetDlgItem(hDlg, IDC_RADIO3); SetWindowText(hTitle, szTitle); SetWindowText(hName, szAuthor); SetWindowText(hEMail, szEMail); SetFocus(hTitle); switch (nBack) { case 0: Button_SetCheck(hNotSpecify, BST_CHECKED); break; case 1: Button_SetCheck(hColor, BST_CHECKED); break; case 2: Button_SetCheck(hWallPaper, BST_CHECKED); break; default: MessageBox(hDlg, "内部エラーです", "Error", MB_OK); break; } return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: Edit_GetText(hTitle, szTitle, sizeof(szTitle)); Edit_GetText(hName, szAuthor, sizeof(szAuthor)); Edit_GetText(hEMail, szEMail, sizeof(szEMail)); if (Button_GetCheck(hColor) == BST_CHECKED) { if (!MyGetBodyColor(hDlg)) break; nBack = 1; } if (Button_GetCheck(hWallPaper) == BST_CHECKED) { if (!MyGetWallPaper(hDlg)) break; nBack = 2; } if (Button_GetCheck(hNotSpecify) == BST_CHECKED) { nBack = 0; } EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } return FALSE; }

szName変数がszAuthorに変更となっています(前述)。

MySaveAs, MySave, MyInsertTag, MyInsertH, MyHProc, MyInsertIMG, MyImgProc, MyGetFileTitle, MyGetBodyColor, MyGetWallPaper, MyInsertA, MyAProc, MyGetHREFFile, MyInsertTable, MyTableProc, MyInsertForm, MyFormProc, MyInputProc, MyInsertInput, MyInsertScriptの各関数に変更はありません。

HWND MakeMyToolbar(HWND hWnd, int n, TBBUTTON *tbButton, int id) { HWND hTool; TBADDBITMAP tbab; int stdid, i; hTool = CreateToolbarEx(hWnd, WS_VISIBLE | WS_CHILD| CCS_NODIVIDER | CCS_NORESIZE | TBSTYLE_FLAT, id , 0, NULL, NULL, tbButton, 0, 0, 0, 0, 0, sizeof(TBBUTTON)); tbab.hInst = HINST_COMMCTRL; tbab.nID = IDB_STD_SMALL_COLOR; stdid = SendMessage(hTool, TB_ADDBITMAP, n, (LPARAM)&tbab); for (i = 0; i < n; i++) tbButton[i].iBitmap += stdid; SendMessage(hTool, TB_ADDBUTTONS, n, (LONG)tbButton); SendMessage(hTool, TB_AUTOSIZE, 0, 0); return hTool; }

ツールバーを作る関数です。引数のnはボタンの数、idはツールバーのIDです。

BOOL MyOpen(HWND hEdit, HWND hEdit_hide) { int id; OPENFILENAME ofn; HGLOBAL hMem; HANDLE hFile; DWORD dwFSizeHigh, dwFSize, dwAccBytes; char *lpszBuf, szWinTitle[64]; HWND hParent; if (SendMessage(hEdit, EM_GETMODIFY, 0, 0) && strcmp(szFileTitle, "無題") != 0) { id = MessageBox(hEdit, "変更を保存しますか", "注意", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) MySave(hEdit); } memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hEdit; ofn.lpstrFilter = "ソースファイル(htm, html)\0*.htm;*.html\0すべてのファイル(*.*)\0*.*\0\0"; ofn.lpstrFile = szFileName; ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFile = MAX_PATH; ofn.nMaxFileTitle = MAX_PATH; ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = "html"; ofn.lpstrTitle = "HTMLソースファイルのオープン"; if (!GetOpenFileName(&ofn)) return FALSE; hFile = CreateFile(szFileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { MessageBox(hEdit, "ファイルをオープンできません", "Error", MB_OK); return FALSE; } dwFSize = GetFileSize(hFile, &dwFSizeHigh); if (dwFSizeHigh != 0) { MessageBox(hEdit, "ファイルが大きすぎます", "Error", MB_OK); CloseHandle(hFile); return FALSE; } hMem = GlobalAlloc(GHND, dwFSize + 1); if (hMem == NULL) { MessageBox(hEdit, "メモリを確保できません", "Error", MB_OK); CloseHandle(hFile); return FALSE; } lpszBuf = (char *)GlobalLock(hMem); ReadFile(hFile, lpszBuf, dwFSize, &dwAccBytes, NULL); lpszBuf[dwFSize] = '\0'; SetWindowText(hEdit, ""); MyInsertTag(hEdit, hEdit_hide, lpszBuf); wsprintf(szWinTitle, lpszWinTitleOrg, szFileTitle); hParent = GetParent(hEdit); SetWindowText(hParent, szWinTitle); CloseHandle(hFile); GlobalUnlock(hMem); GlobalFree(hMem); SendMessage(hEdit, EM_SETMODIFY, (WPARAM)FALSE, 0); return TRUE; }

ファイルをオープンする関数です。オープンするファイルのサイズを調べてこれより1バイト多い メモリを確保しておきます。ファイルを読み込んで最後にヌル文字を追加しておきます。

また、読み込んだ内容をエディットコントロールに表示するときはSetWindowText関数を使わずに MyInsertTag関数を使っています。

BOOL CheckMyMenu(HMENU hMenu, HWND hEdit, HWND hTool2) { HWND hWnd; DWORD dwStart, dwEnd; UINT uOK, uNO; uOK = MF_BYCOMMAND | MF_ENABLED; uNO = MF_BYCOMMAND | MF_GRAYED; hWnd = GetParent(hEdit); if (CanPaste(hWnd)) { EnableMenuItem(hMenu, IDM_PASTE, uOK); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_PASTE, (LPARAM)MAKELONG(TRUE, 0)); } else { EnableMenuItem(hMenu, IDM_PASTE, uNO); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_PASTE, (LPARAM)MAKELONG(FALSE, 0)); } if (SendMessage(hEdit, EM_GETMODIFY, 0, 0)) { EnableMenuItem(hMenu, IDM_UNDO, uOK); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_UNDO, (LPARAM)MAKELONG(TRUE, 0)); } else { EnableMenuItem(hMenu, IDM_UNDO, uNO); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_UNDO, (LPARAM)MAKELONG(FALSE, 0)); } SendMessage(hEdit, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd); if (dwStart == dwEnd) { EnableMenuItem(hMenu, IDM_COPY, uNO); EnableMenuItem(hMenu, IDM_DELETE, uNO); EnableMenuItem(hMenu, IDM_CUT, uNO); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_COPY, (LPARAM)MAKELONG(FALSE, 0)); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_DELETE, (LPARAM)MAKELONG(FALSE, 0)); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_CUT, (LPARAM)MAKELONG(FALSE, 0)); } else { EnableMenuItem(hMenu, IDM_COPY, uOK); EnableMenuItem(hMenu, IDM_DELETE, uOK); EnableMenuItem(hMenu, IDM_CUT, uOK); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_COPY, (LPARAM)MAKELONG(TRUE, 0)); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_DELETE, (LPARAM)MAKELONG(TRUE, 0)); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_CUT, (LPARAM)MAKELONG(TRUE, 0)); } if (Edit_GetTextLength(hEdit) == 0) EnableMenuItem(hMenu, IDM_ALL, uNO); else EnableMenuItem(hMenu, IDM_ALL, uOK); return TRUE; }

メニューやボタンの使用可否を調べる関数です。

貼り付けができるかどうかを調べてメニューやボタンの「貼り付け」の使用可否を決定します。 エディットコントロールではEM_CANPASTEメッセージが使えない(リッチエディットコントロールでは可能) ため、自作関数CanPaste(後述)で調べています。

エディットコントロールに変更があれば(EM_GETMODIFYを送って0以外が返ってくれば)IDM_UNDOを 使用可能にし、変更がなければ使用不可にします。

反転文字(選択されている文字列)があれば、IDM_COPY, IDM_DELETE, IDM_CUTを使えるようにし、 なければ使用不可にします。EM_GETSELメッセージを送って始まりと終わりの位置を 調べ、これが同じであれば反転文字は存在しないことになります。

エディットコントロールに表示されている文字列の長さを調べて、これが0なら「すべて選択」 は意味が無いので使用不可にします。

BOOL CanPaste(HWND hWnd) { HANDLE hMem; if (OpenClipboard(hWnd) == 0) { return FALSE; } hMem = GetClipboardData(CF_TEXT); if (hMem == NULL) { CloseClipboard(); return FALSE; } else { CloseClipboard(); return TRUE; } }

クリップボードにテキスト形式のデータがあるかどうかを調べる関数です。 クリップボードについては第94章を参照してください。

LRESULT CALLBACK NewEditProc(HWND hEdit, UINT msg, WPARAM wp, LPARAM lp) { HWND hParent; static HWND hTool; HMENU hMenu; hParent = GetParent(hEdit); hMenu = GetMenu(hParent); switch (msg) { case MY_MSG: hTool = (HWND)lp; return 0; case WM_KEYUP: case WM_LBUTTONUP: CheckMyMenu(hMenu, hEdit, hTool); break; default: break; } return (CallWindowProc(OrgEditProc, hEdit, msg, wp, lp)); }

サブクラス化されたエディットコントロールのプロシージャです。

自作メッセージMY_MSGが来たらlpをhToolに保存しておきます。 ツールバーのウィンドウハンドルを知るために親のプロシージャで ツールバーを作ったときに送ったものです。

WM_KEYUPやWM_LBUTTONUPが来たらCheckMyMenu関数を呼んで メニュー項目やボタンの使用可否を決めます。この時、メッセージを 横取りしてしまっては本来の機能が損なわれるのでCallWindowProcに 返している点に注意してください。

BOOL MySetStatusText(HWND hStatus, int n, char *lpszBuf) { SendMessage(hStatus, SB_SETTEXT, (WPARAM)n, (LPARAM)lpszBuf); return TRUE; }

ステータスバーに文字列を表示する関数です。

今回は、ごちゃごちゃしたプログラムでしたが、内容はすでに 他の章でやったことばかりでした。


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

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