第302章 タグを挿入する


今回は、タグを挿入するプログラムを考えます。 普通に考えると、エディットコントロールのある部分(キャレットのある部分)に 文字列を挿入するには、この部分より前方にある文字列に、挿入したい 文字列を付け加え、さらに後方の文字列を付け加えればよい、ということになります。 しかし、エディットコントロール関係のメッセージをざっと見てもなかなか ぴたっと来るものがありません。

そこで、クリップボードを利用して文字列を挿入するのはどうでしょうか。 これは、簡単そうですね。クリップボードに文字列があれば、これを 挿入するのはエディットコントロールに対して、WM_PASTEメッセージを送るだけです。 では、希望の文字列をクリップボードに送るにはどうしたらよいでしょうか。 第94章のようにしてもよいでしょう。 しかし、もっと簡単なずるい方法もあります。 エディットコントロールで、文字列が選択されているとき(反転表示されているとき) WM_COPYメッセージを送ると、この文字列がクリップボードに行きますね。 つまり、ダミーのエディットコントロールを作っておいて、これに挿入したい 文字列を書き込み、選択してWM_COPYコマンドを送ればよいのです。



メニューの「挿入」「<h*>」を選択すると、左の図のようなダイアログが でます。これで、見出しの大きさをコンボボックスから選択して、見出しの内容を エディットコントロールに書き込み、OKボタンを押すとhタグが挿入されます。



メニューの「挿入」「<IMG>」を選択すると、左の図のようなダイアログが でます。「参照」ボタンを押して表示したい画像ファイルを探します。 この時、「画像を確認する」にチェックがついていると、選択した画像が 表示されます。これは、gifとかjpgに関連づけられたソフトが立ち上がって 画像を表示するので、システムに関連づけがないと働きません。

「パス付き」にチェックを付けるとその横にあるエディットコントロールが 使用可能となり、ここに相対パスまたはhttpで始まる絶対パスを書き込むことが できます。当たり前ですがローカルの絶対パスを書いてはいけません。 このパスは手動で書きます。

このほかにも<P>や、<BR>タグも挿入できます。



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

// htmledit02.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "新規作成(&N)...", IDM_NEW MENUITEM "上書き保存(&S)", IDM_SAVE MENUITEM "名前を付けて保存(&A)...", IDM_SAVEAS MENUITEM SEPARATOR MENUITEM "アプリケーションの終了(&X)", IDM_END END POPUP "挿入(&I)" BEGIN MENUITEM "基本項目入力(&B)...", IDM_BASICINPUT MENUITEM SEPARATOR MENUITEM "<P>", IDM_P MENUITEM "<BR>", IDM_BR MENUITEM "<H*>", IDM_H MENUITEM "<IMG>", IDM_IMAGE END POPUP "ブラウザ(&B)" BEGIN MENUITEM "ブラウザ起動(&E)", IDM_BROWSER END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYBASICINPUT DIALOG DISCARDABLE 0, 0, 187, 93 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,72,50,14 PUSHBUTTON "キャンセル",IDCANCEL,96,72,50,14 LTEXT "タイトル",IDC_STATIC,7,7,23,8 LTEXT "作者",IDC_STATIC,7,25,15,8 LTEXT "E-Mail",IDC_STATIC,7,43,20,8 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

メニューとダイアログボックスのリソース・スクリプトです。

メニューの「基本項目入力」は「挿入」の所に移動しました。

メニューの「ブラウザ」「ブラウザ起動」で現在作成中のページを ブラウザで確認することができます。

// htmedit02.cpp #ifndef STRICT #define STRICT #endif #define ID_EDIT 100 #define ID_EDIT2 101 #define MY_BUF_SIZE 1024 * 64 - 1 #include <windows.h> #include <windowsx.h> #include "resource.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; 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); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL MySetHTML(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); char szClassName[] = "htmedit02"; //ウィンドウクラス char *lpszWinTitleOrg = "猫でもわかるHTMLエディタ[%s]"; char *lpszHead = "<HTML>\r\n<HEAD>\r\n<TITLE>"; char szTitle[64] = "タイトル"; char *lpszBody = "</TITLE>\r\n<HEAD>\r\n<BODY>\r\n"; char *lpszAddress = "<ADDRESS>"; char *lpszMailto = "<A HREF=\"mailto:"; char szEMail[256] = "webmaster@kumei.ne.jp"; char *lpszMailEnd = "\">"; char szName[64] = "Yasutaka Kumei"; char *lpszCloseA = "</A>"; char *lpszEnd = "</ADDRESS>\r\n</BODY>\r\n</HTML>"; char szFileName[MAX_PATH]; char szFileTitle[64];

ダミーのエディットコントロールを作るのでこのIDをID_EDIT2として 定義しておきました。

ダイアログボックスのプロシージャからデータをもらってくるために MYHTAGとかMYIMGTAGなどの構造体をtypedefしてみました。 これらのメンバをグローバル変数にしてしまってもよいです。 この場合、ダイアログ部分のプログラムの一部を修正してください。

いくつかの自作関数が増えたのでそのプロトタイプ宣言も増えています。

<BODY>タグの後ろに改行を入れることにしました。

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

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static HWND hEdit, hEdit_hide; HINSTANCE hInst; CREATESTRUCT *lpcs; char szWinTitle[64]; switch (msg) { case WM_CREATE: wsprintf(szWinTitle, lpszWinTitleOrg, "無題"); SetWindowText(hWnd, szWinTitle); lpcs = (CREATESTRUCT *)lp; hInst = lpcs->hInstance; hEdit = CreateWindow("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); hEdit_hide = CreateWindow("EDIT", "", WS_CHILD, 0, 0, 0, 0, hEdit, (HMENU)ID_EDIT2, hInst, NULL); SetFocus(hEdit); break; case WM_SIZE: MoveWindow(hEdit, 0, 0, LOWORD(lp), HIWORD(lp), TRUE); 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; MySetHTML(hEdit); SetFocus(hEdit); 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); } SetWindowText(hEdit, ""); 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>"); break; case IDM_BR: MyInsertTag(hEdit, hEdit_hide, "<BR>"); break; case IDM_H: MyInsertH(hEdit, hEdit_hide); break; case IDM_IMAGE: MyInsertIMG(hEdit, hEdit_hide); break; case IDM_BROWSER: if (strcmp(szFileName, "") == 0) { MessageBox(hWnd, "まだHTMLファイルが保存されていません", "Error", MB_OK); break; } ShellExecute(hWnd, "open", szFileName, NULL, NULL, SW_SHOWNORMAL); break; } 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); } 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メッセージが来たときに、ダミーのエディットコントロールも作っておきます。 どうせ見えないので、エディットコントロールのスタイルはWS_CHILDのみです。大きさも0でいいです。

メニューからIDM_P, _BR, _H, _IMAGEが選択されたら、それぞれのタグを挿入する 自作関数を呼びます。

メニューからIDM_BROWSERが選択されたら、ShellExecute関数でszFileNameを開きます。 これで、現在編集中のHTMLファイルをブラウザに表示することができます。 なお、ShellExecute関数については、第104章を参照してください。

プログラム終了時にはダミーのエディットコントロールも破棄します。

MySetHTML, MyBasicInput, MyBasicInputProc, MySaveAs, MySaveの各関数に変更はありません。

BOOL MyInsertTag(HWND hEdit1, HWND hEdit2, char *lpszTag) { SetWindowText(hEdit2, lpszTag); SendMessage(hEdit2, EM_SETSEL, (WPARAM)0, (LPARAM)-1); SendMessage(hEdit2, WM_COPY, 0, 0); SendMessage(hEdit1, WM_PASTE, 0, 0); return TRUE; }

エディットコントロールに文字列を挿入する関数です。

まず、ダミーのエディットコントロールに挿入したい文字列を表示します。(実際は見えませんが・・・)

次にこの文字列を選択します。EM_SETSELメッセージを送るときWPARAMを0にLPARAMを−1にすると エディットコントロールの最初から最後までを選択状態にすることができます。

ダミーのエディットコントロールにWM_COPYメッセージを送ると選択されている文字列を クリップボードに送ることができます。

あとは、本物のエディットコントロールにWM_PASTEメッセージを送るだけです。

BOOL MyInsertH(HWND hEdit, HWND hEdit_hide) { HINSTANCE hInst; MYHTAG myh; char szBuf[512]; hInst = (HINSTANCE)GetWindowLong(hEdit, GWL_HINSTANCE); if (DialogBoxParam(hInst, "MYHTAG", hEdit, (DLGPROC)MyHProc, (LPARAM)&myh) == IDCANCEL) return FALSE; strcpy(szBuf, "<H"); strcat(szBuf, myh.szTagNo); strcat(szBuf, ">"); strcat(szBuf, myh.szContents); strcat(szBuf, "</H"); strcat(szBuf, myh.szTagNo); strcat(szBuf, ">"); MyInsertTag(hEdit, hEdit_hide, szBuf); return TRUE; }

見出しタグを挿入する関数です。DialogBoxParam関数でプロシージャに 構造体myhのアドレスを知らせます。 DialogBoxParam関数について忘れてしまった人は 第195章を見て復習してください。

プロシージャではこの構造体のメンバに データを代入します。

DialogBoxParam関数が戻ってきたら挿入したい文字列を作ってMyInsertTag関数で 挿入してもらいます。

LRESULT CALLBACK MyHProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hCombo, hEditContents; static LPMYHTAG lpmyh; switch (msg) { case WM_INITDIALOG: lpmyh = (LPMYHTAG)lp; hCombo = GetDlgItem(hDlg, IDC_COMBO1); hEditContents = GetDlgItem(hDlg, IDC_EDIT1); ComboBox_AddString(hCombo, "1"); ComboBox_AddString(hCombo, "2"); ComboBox_AddString(hCombo, "3"); ComboBox_AddString(hCombo, "4"); ComboBox_AddString(hCombo, "5"); ComboBox_AddString(hCombo, "6"); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: ComboBox_GetText(hCombo, lpmyh->szTagNo, sizeof(lpmyh->szTagNo)); Edit_GetText(hEditContents, lpmyh->szContents, sizeof(lpmyh->szContents)); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } return FALSE; }

見出しタグを挿入するダイアログのプロシージャです。

WM_INITDIALOGメッセージが来たら、DialogBoxParam関数から送られてきたMYHTAG構造体の アドレスをstaticな変数にコピーしておきます。

OKボタンが押されたら、コントロールからテキストを取得してMYHTAG構造体の メンバに格納します。これでDialogBoxParam関数側ではデータを取得できます。

BOOL MyInsertIMG(HWND hEdit, HWND hEdit_hide) { HINSTANCE hInst; MYIMGTAG myimg; char szBuf[1024]; hInst = (HINSTANCE)GetWindowLong(hEdit, GWL_HINSTANCE); if (DialogBoxParam(hInst, "MYIMGTAG", hEdit, (DLGPROC)MyImgProc, (LPARAM)&myimg) == IDCANCEL) return FALSE; strcpy(szBuf, "<IMG SRC=\""); if (myimg.bPath) strcat(szBuf, myimg.szPath); strcat(szBuf, myimg.szFileName); strcat(szBuf, "\">"); MyInsertTag(hEdit, hEdit_hide, szBuf); return TRUE; }

IMGタグを挿入する関数です。

DialogBoxParam関数が戻ってきたら挿入する文字列を作ってMyInsertTag関数で挿入してもらいます。

LRESULT CALLBACK MyImgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hButton, hPath, hFile, hCheck, hImg; static LPMYIMGTAG lpimg; static BOOL bImg, bPath; switch (msg) { case WM_INITDIALOG: lpimg = (LPMYIMGTAG)lp; hButton = GetDlgItem(hDlg, IDC_BUTTON1); hCheck = GetDlgItem(hDlg, IDC_CHECK1); hPath = GetDlgItem(hDlg, IDC_EDIT1); hFile = GetDlgItem(hDlg, IDC_EDIT2); hImg = GetDlgItem(hDlg, IDC_CHECK2); if (bImg) Button_SetCheck(hImg, BST_CHECKED); else Button_SetCheck(hImg, BST_UNCHECKED); if (bPath) { EnableWindow(hPath, TRUE); Button_SetCheck(hCheck, BST_CHECKED); } else { EnableWindow(hPath, FALSE); Button_SetCheck(hCheck, BST_UNCHECKED); } return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: Edit_GetText(hFile, lpimg->szFileName, MAX_PATH); if (Button_GetCheck(hCheck) == BST_CHECKED) { Edit_GetText(hPath, lpimg->szPath, MAX_PATH); lpimg->bPath = TRUE; } else { strcpy(lpimg->szPath, ""); lpimg->bPath = FALSE; } EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; case IDC_CHECK1: if (Button_GetCheck(hCheck) == BST_CHECKED) { EnableWindow(hPath, TRUE); bPath = TRUE; } else { EnableWindow(hPath, FALSE); bPath = FALSE; } return TRUE; case IDC_BUTTON1: MyGetFileTitle(hDlg, hFile, bImg); return TRUE; case IDC_CHECK2: if (Button_GetCheck(hImg) == BST_CHECKED) bImg = TRUE; else bImg = FALSE; return TRUE; } return FALSE; } return FALSE; }

IMGタグを挿入するダイアログのプロシージャです。

WM_INITDIALOGメッセージが来たら、MYIMGTAG構造体のアドレスを staticな変数に格納しておきます。

IDC_CHECK1(「パス付き」)がチェックされたら、その横のエディットコントロールを 使用可能にし、チェックがはずされたら使用不能にします。

IDC_BUTTON1(「参照」ボタン)が押されたらMyGetFileTitle関数を呼んで、 イメージファイルのファイル名を取得します。

IDC_CHECK2(「画像を確認する」)がチェックされたらbImgをTRUEにして、 チェックがはずされたらFALSEにします。

BOOL MyGetFileTitle(HWND hDlg, HWND hFile, BOOL bImg) { OPENFILENAME ofn; char szFileTitle[MAX_PATH], szFileName[MAX_PATH]; szFileTitle[0] = '\0'; szFileName[0] = '\0'; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hDlg; ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrFile = szFileName; ofn.nMaxFile = MAX_PATH; ofn.lpstrFilter = "gifファイル\0*.gif\0jpegファイル\0*.jpg;*.jpeg\0すべてのファイル\0*.*\0\0"; ofn.Flags = OFN_HIDEREADONLY; if (!GetOpenFileName(&ofn)) return FALSE; SetWindowText(hFile, szFileTitle); if (bImg) { if (ShellExecute(hDlg, "open", szFileName, NULL, NULL, SW_SHOWNORMAL) <= (HINSTANCE)32) { MessageBox(hDlg, "画像を表示できません", "Error", MB_OK); return FALSE; } } return TRUE; }

画像ファイルのファイル名を取得する関数です。

GetOpenFileName関数のダイアログでOKボタンが押されたら、 szFileTitleをIMGタグを挿入するダイアログの「ファイル名」のエディットコントロールに 表示します。

また、bImgがTRUEであれば、ShellExecute関数を利用して選択された画像ファイルを 表示します。

画像の表示ははW3Cでは、<OBJECT>タグが推奨されていますが、まだ一般には<IMG>タグが 使われていますね。

今回のプログラムを使って、簡単なホーム・ページを作ってみてください。プログラムから挿入できない タグは手動で書き込んでください。


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

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