Album不具合解決報告の闖入がありましたが、今回がECCSkeltonによるRTWEditorの最終回です。残りはUser.hとRTWEditorProc.hの二つです。
【User.h】
このファイルは、外部変数の宣言とメニュー、ツールバーボタンの状態設定の外部関数があります。
//////////////////////////////////////////
// User.h
// For RTWEditor
// Copyright (c) 08/30/2022 by ECCSkelton
//////////////////////////////////////////
//////////////////////////////
//ポップアップメニューハンドル
//////////////////////////////
HMENU g_hPopup;
//(解説:タブやリッチテキストコントロールの右クリックでポップアップメニューを出す為の記録用です。)
///////////////////////////////
//ドラッグアンドドロップ用変数
///////////////////////////////
bool g_ByFile;
CARG g_Arg;
CSTR g_FileName;
//(解説:順にファイル起動フラグ、コマンドライン引数取得用及びファイル名記録用です。)
//--------------------------------
// メニュー、ツールバー状態の変更
//--------------------------------
void ChangeMenuStatus(bool EnableFlag) {
HMENU hMenu = GetMenu(RTWEditor.GetHandle()); //メニューハンドルの取得
//メニューバー
EnableMenuItem(hMenu, 1, MF_BYPOSITION | (EnableFlag ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(hMenu, 2, MF_BYPOSITION | (EnableFlag ? MF_ENABLED : MF_GRAYED));
HMENU hFileMenu;
hFileMenu = GetSubMenu(hMenu, 0);
EnableMenuItem(hFileMenu, IDM_SAVE, MF_BYCOMMAND | (EnableFlag ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(hFileMenu, IDM_SAVEAS, MF_BYCOMMAND | (EnableFlag ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(hFileMenu, IDM_SETPRINT, MF_BYCOMMAND | (EnableFlag ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(hFileMenu, IDM_PRINT, MF_BYCOMMAND | (EnableFlag ? MF_ENABLED : MF_GRAYED));
DrawMenuBar(RTWEditor.GetHandle()); //Re-draw "&File" menu
//ツールバー(MAKELONGマクロは16bit整数2つをunsigned 32bit整数にする)
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_SAVE, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_PRINT, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_UNDO, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_CUT, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_COPY, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_PASTE, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_FIND, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_REPLACE, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_DELETE, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_LEFT, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_CENTER, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_RIGHT, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_FONT, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_LINDENT, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_LOUTDENT, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_RINDENT, MAKELONG(EnableFlag, 0));
SendMessageW(TBar.GetHandle(), TB_ENABLEBUTTON, IDM_ROUTDENT, MAKELONG(EnableFlag, 0));
}
//(解説:ここは純粋にWin32APIだけの記述です。引数を使ってメニューとツールバーボタンの状態を変えます。BCCSkelton版と異なるのは、タブを消去するメニュー(IDM_DELETE)を追加したことです。)
【RTWEditorProc.h】
基本的にRTWEditor.hで宣言したメンバー関数の定義部分です。単なるエディターなので余り難しいことはしていません。
//////////////////////////////////////////
// RTWEditorProc.h
// Copyright (c) 08/30/2022 by ECCSkelton
//////////////////////////////////////////
/////////////////////////////////
//主ウィンドウCMyWndの関数の定義
//ウィンドウメッセージ関数
/////////////////////////////////
bool CMyWnd::OnCreate(WPARAM wParam, LPARAM lParam) {
//コモンコントロールの初期化
InitCommonControls();
//(解説:ここでの注意点は、先ずツールバーにコモンコントロールのビットマップを使って登録した後、カスタムビットマップを登録追加することです。)
//ツールバー登録-Init(hWnd, hIinstance, ID, Style)-ツールチップを付ける
TBar.Init(m_hWnd, m_hInstance, TOOLBAR, WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS);
//ツールバーボタン用ビットマップ追加
TBar.AddBmp();
//(解説:bool引数のAddBmpはコモンコントロールのスタンダードビットマップを登録します。TRUE(規定値-省略可)の場合は"STD_XXX"のビットマップ、FALSEの場合”VIEW_XXX"のビットマップとなります。)
//ツールバーボタン追加
TBBUTTON tbb[26];
ZeroMemory(tbb, sizeof(tbb));
tbb[0].iBitmap = STD_FILENEW;
tbb[0].fsState = TBSTATE_ENABLED;
tbb[0].fsStyle = TBSTYLE_BUTTON;
tbb[0].idCommand = IDM_NEW;
tbb[1].iBitmap = STD_FILEOPEN;
tbb[1].fsState = TBSTATE_ENABLED;
tbb[1].fsStyle = TBSTYLE_BUTTON;
tbb[1].idCommand = IDM_OPEN;
tbb[2].iBitmap = STD_FILESAVE;
tbb[2].fsStyle = TBSTYLE_BUTTON;
tbb[2].idCommand = IDM_SAVE;
tbb[3].iBitmap = STD_PROPERTIES;
tbb[3].fsState = TBSTATE_ENABLED;
tbb[3].fsStyle = TBSTYLE_BUTTON;
tbb[3].idCommand = IDM_SETPRINT;
tbb[4].iBitmap = STD_PRINT;
tbb[4].fsStyle = TBSTYLE_BUTTON;
tbb[4].idCommand = IDM_PRINT;
tbb[5].fsStyle = TBSTYLE_SEP; //セパレーター
tbb[6].iBitmap = STD_UNDO;
tbb[6].fsStyle = TBSTYLE_BUTTON;
tbb[6].idCommand = IDM_UNDO;
tbb[7].iBitmap = STD_CUT;
tbb[7].fsStyle = TBSTYLE_BUTTON;
tbb[7].idCommand = IDM_CUT;
tbb[8].iBitmap = STD_COPY;
tbb[8].fsStyle = TBSTYLE_BUTTON;
tbb[8].idCommand = IDM_COPY;
tbb[9].iBitmap = STD_PASTE;
tbb[9].fsStyle = TBSTYLE_BUTTON;
tbb[9].idCommand = IDM_PASTE;
tbb[10].iBitmap = STD_FIND;
tbb[10].fsStyle = TBSTYLE_BUTTON;
tbb[10].idCommand = IDM_FIND;
tbb[11].iBitmap = STD_REPLACE;
tbb[11].fsStyle = TBSTYLE_BUTTON;
tbb[11].idCommand = IDM_REPLACE;
tbb[12].fsStyle = TBSTYLE_SEP; //セパレーター
//カスタムビットマップの追加
TBar.AddBmp(m_hInstance, MAKEINTRESOURCE(IDI_CUSTOM), 9);
//(解説:ここからはカスタムビットマップを登録して使用します。)
tbb[13].fsStyle = TBSTYLE_SEP; //セパレーター
tbb[14].iBitmap = TBar.m_id;
tbb[14].fsStyle = TBSTYLE_BUTTON;
tbb[14].idCommand = IDM_DELETE;
tbb[15].fsStyle = TBSTYLE_SEP; //セパレーター
tbb[16].iBitmap = TBar.m_id + 1;
tbb[16].fsStyle = TBSTYLE_BUTTON;
tbb[16].idCommand = IDM_LEFT;
tbb[17].iBitmap = TBar.m_id + 2;
tbb[17].fsStyle = TBSTYLE_BUTTON;
tbb[17].idCommand = IDM_CENTER;
tbb[18].iBitmap = TBar.m_id + 3;
tbb[18].fsStyle = TBSTYLE_BUTTON;
tbb[18].idCommand = IDM_RIGHT;
tbb[19].fsStyle = TBSTYLE_SEP; //セパレーター
tbb[20].iBitmap = TBar.m_id + 4;
tbb[20].fsStyle = TBSTYLE_BUTTON;
tbb[20].idCommand = IDM_FONT;
tbb[21].fsStyle = TBSTYLE_SEP; //セパレーター
tbb[22].iBitmap = TBar.m_id + 5;
tbb[22].fsStyle = TBSTYLE_BUTTON;
tbb[22].idCommand = IDM_LINDENT;
tbb[23].iBitmap = TBar.m_id + 6;
tbb[23].fsStyle = TBSTYLE_BUTTON;
tbb[23].idCommand = IDM_LOUTDENT;
tbb[24].iBitmap = TBar.m_id + 7;
tbb[24].fsStyle = TBSTYLE_BUTTON;
tbb[24].idCommand = IDM_RINDENT;
tbb[25].iBitmap = TBar.m_id + 8;
tbb[25].fsStyle = TBSTYLE_BUTTON;
tbb[25].idCommand = IDM_ROUTDENT;
TBar.AddButtons(26, tbb);
//ステータスバー登録-Init(hWnd, hIinstance, ID, (以下省略可)Style)
SBar.Init(m_hWnd, m_hInstance, STATUSBAR);
//ステータスバー区画設定
int sec[4] = {120, 210, 330, -1};
SBar.SetSection(4, sec);
//ステータスバー文字列設定
SBar.SetText(0, L"RTWEditor Version 1.0");
//(解説:1の区画にはファイルサイズ、2の区画にはキャロット位置、3の区画にはファイルパス名が入ります。)
//タブコントロールの作成とタグのフォント設定
m_Tab.Create(m_hWnd, m_hInstance, (HMENU)IDC_TAB);
m_Tab.SetFont(9, L"MS P明朝");
//(解説:今回の主役、メインウィンドウのクライアントエリアに張るタブコントロールの生成とフォント設定です。)
//ドラッグアンドドロップを許可する
DragAcceptFiles(m_hWnd, TRUE);
//メニューハンドルの取得
g_hPopup = GetSubMenu(GetMenu(m_hWnd), 1);
//(解説:タブコントロール、リッチエディットコントロールの右クリックでポップアップさせるメニューとしてメインメニューの「編集」を選択しています。)
//ファイル起動対応(g_ByFileが真の時、1回のみ)
if(g_ByFile) {
for(int i = 1; i < g_Arg.c(); i++) {
if(g_ExtChk.CheckExt(g_Arg.v(i), FILEFILTER)) //対象ファイルか否かチェック
AddTabEdit(g_Arg.v(i)); //タブの追加
else
MessageBoxW(m_hWnd, g_Arg.v(i), L"対象外のファイル", MB_OK | MB_ICONERROR);
}
g_ByFile = FALSE;
}
//(解説:ファイル起動フラグ(g_ByFile)により、対象ファイルの確認をEXTCHKクラスで選別し、共通の「タブを増やして、リッチテキストコントロールを貼る」ユーザー定義関数を呼びます。)
return TRUE;
}
bool CMyWnd::OnNotify(WPARAM wParam, LPARAM lParam) {
if(((LPNMHDR)lParam)->code == TTN_NEEDTEXT) { //ツールバーツールチップの表示
LPTOOLTIPTEXT lpTTText = (LPTOOLTIPTEXT)lParam;
lpTTText->hinst = m_hInstance;
switch(lpTTText->hdr.idFrom) {
case IDM_NEW:
lpTTText->lpszText = MAKEINTRESOURCE(String_00);
break;
case IDM_OPEN:
lpTTText->lpszText = MAKEINTRESOURCE(String_01);
break;
case IDM_SAVE:
lpTTText->lpszText = MAKEINTRESOURCE(String_02);
break;
case IDM_SETPRINT:
lpTTText->lpszText = MAKEINTRESOURCE(String_03);
break;
case IDM_PRINT:
lpTTText->lpszText = MAKEINTRESOURCE(String_04);
break;
case IDM_UNDO:
lpTTText->lpszText = MAKEINTRESOURCE(String_05);
break;
case IDM_CUT:
lpTTText->lpszText = MAKEINTRESOURCE(String_06);
break;
case IDM_COPY:
lpTTText->lpszText = MAKEINTRESOURCE(String_07);
break;
case IDM_PASTE:
lpTTText->lpszText = MAKEINTRESOURCE(String_08);
break;
case IDM_FIND:
lpTTText->lpszText = MAKEINTRESOURCE(String_09);
break;
case IDM_REPLACE:
lpTTText->lpszText = MAKEINTRESOURCE(String_10);
break;
case IDM_DELETE:
lpTTText->lpszText = MAKEINTRESOURCE(String_11);
break;
case IDM_LEFT:
lpTTText->lpszText = MAKEINTRESOURCE(String_12);
break;
case IDM_CENTER:
lpTTText->lpszText = MAKEINTRESOURCE(String_13);
break;
case IDM_RIGHT:
lpTTText->lpszText = MAKEINTRESOURCE(String_14);
break;
case IDM_FONT:
lpTTText->lpszText = MAKEINTRESOURCE(String_15);
break;
case IDM_LINDENT:
lpTTText->lpszText = MAKEINTRESOURCE(String_16);
break;
case IDM_LOUTDENT:
lpTTText->lpszText = MAKEINTRESOURCE(String_17);
break;
case IDM_RINDENT:
lpTTText->lpszText = MAKEINTRESOURCE(String_18);
break;
case IDM_ROUTDENT:
lpTTText->lpszText = MAKEINTRESOURCE(String_19);
break;
//(解説:ここまでは定番のツールバービットマップボタンのツールチップです。今回はストリングテーブルを使っています。)
default://hdr.idFromがタブコントロールのページ番号(0~)でツールチップ要求が入る為、
//タブコントロールのページ番号で他のコントロールでIDを設けてはいけない
if(lpTTText->hdr.idFrom < m_Tab.TabCount()) { //タブのツールチップ
lpTTText->lpszText = m_Tab.GetTitle(lpTTText->hdr.idFrom);
break;
}
//(解説:タブページは0からページ数-1のコントロールIDが付きますので、ツールバーと同じくここで処理します。コメントにあるように他のコントロールと重複しないように注意します。表示するのはタブタグに表示されるファイルパス名です。)
else
return FALSE;
}
return TRUE;
}
//タブのページ選択変更
else if(((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
//新たに選択されたタブのリッチエディットコントロールをm_Editでカプセル化する
m_Edit.SetHandle(m_Tab.GetCtrl());
m_Tab.FitSiblings((WPARAM)IDC_TAB);
SBar.SetText(1, L""); //バイト数をクリア
SBar.SetText(2, L""); //キャレット位置をクリア
SBar.SetText(3, m_Tab.GetTitle()); //ファイル名を変更
//(解説:ここでは、別のタブをクリックして選択した時の処理を書きます。m_EditというCREDITクラスのインスタンスをカプセルにし、新規に選ばれたタブに張り付けられたリッチテキストコントロールのハンドルを渡し、選択されている限り処理はm_Editを通じて行います。その後は再描画とステータスバーの表記変更です。)
}
else if(((NMHDR*)lParam)->code == NM_RCLICK) { //タブの右マウスボタン押し下げ通知
//ポップアップメニューの表示
PopupMenu();
//(解説:このポップアップメニュー処理はタブ部分(タブのタグ部分だけ)の右クリックに対応しています。)
}
//リッチエディットテキストの変更でバイト数とキャレット位置を表示
else if(((NMHDR*)lParam)->code == EN_SELCHANGE) {
WCHAR str[19]; //"(6桁)+行:(6桁)+桁" + NULL, //"xxxxxxxxxxxバイト" + NULL
wsprintfW(str, L"%dバイト", m_Edit.GetSize());
SBar.SetText(1, str);
wsprintfW(str, L"%d行:%d桁", m_Edit.GetPos()->y + 1, m_Edit.GetPos()->x + 1);
SBar.SetText(2, str);
//(解説:これはリッチテキストコントロール(m_Edit)のキャレットに移動があった場合の処理で、ステータスバー表記を行います。)
}
//リッチエディットコントロールからの通知はMSGFILTER構造体で受け取る
else if(((NMHDR*)lParam)->code == EN_MSGFILTER && ((MSGFILTER*)lParam)->msg == WM_RBUTTONUP) {
//ポップアップメニューの表示
PopupMenu();
//(解説:このポップアップメニュー処理はリッチテキストコントロール部分の右クリックに対応しています。)
}
else
return FALSE;
return TRUE;
}
bool CMyWnd::OnSize(WPARAM wParam, LPARAM lParam) {
//ツールバー、ステータスバーの自動調整
TBar.AutoSize();
SBar.AutoSize();
//現在のタブとそれのコントロールの自動調整
m_Tab.FitParent(SBar.GetHandle(), TBar.GetHandle());
//(解説:親のサイズ変更があった場合、親の新しいサイズに合わせて自分もサイズを変えるCTABクラスの関数です。)
return TRUE;
}
bool CMyWnd::OnClose(WPARAM wParam, LPARAM lParam) {
int ret = MessageBoxW(m_hWnd, L"終了します。\nタブ毎に確認しますか?(「はい」)\n(終了せずに戻る-「キャンセル」)",
L"終了確認", MB_YESNOCANCEL | MB_ICONINFORMATION);
if(ret == IDYES) {
//リッチエディットに変更があるかすべてのタブでチェック
for(int i = m_Tab.TabCount(); i > 0; i--) {
m_Tab.SetPage(i - 1); //最後のタブをカレントにする
if(!DelTabEdit()) //そのタブとコントロールを破棄する
return FALSE;
//(解説:FILOで保存確認の上、タブを閉め、リッチテキストコントロールを破壊するユーザー定義関数を呼んで終了します。)
}
//処理をするとDestroyWindow、PostQuitMessageが呼ばれる
return TRUE;
}
else if(ret == IDNO)
//(解説:これは一挙に終了です。)
return TRUE;
else
//そうでなければウィンドウではDefWindowProc関数をreturn、ダイアログではreturn FALSEとなる。
//(解説:これは終了しません。)
return FALSE;
}
bool CMyWnd::OnDropFiles(WPARAM wParam, LPARAM lParam) {
//ドラッグアンドドロップされたファイル名取得と処理
WCHAR fn[MAX_PATH];
//ドラッグアンドドロップされたファイルの数取得
int num = DragQueryFileW((HDROP)wParam, 0xFFFFFFFF, NULL, 0);
//ドラッグアンドドロップされたファイル名取得と処理
for(int i = 0; i < num; i++) {
DragQueryFileW((HDROP)wParam, i, fn, sizeof(fn));
//OnOpen()関数を開くファイルの数だけ繰り返す
if(g_ExtChk.CheckExt(fn, FILEFILTER)) { //対象ファイルか否かチェック
AddTabEdit(fn); //タブの追加
ChangeMenuStatus(TRUE);
SBar.SetText(3, fn);
}
else
MessageBoxW(m_hWnd, fn, L"対象外のファイル", MB_OK | MB_ICONERROR);
}
DragFinish((HDROP)wParam);
return TRUE;
//(解説:ワイド文字が使われているだけで、定番のドラッグアンドドロップ処理です。)
}
bool CMyWnd::OnGetMaxInfo(WPARAM wParam, LPARAM lParam) {
//典型的なウィンドウのサイズ制限処理
MINMAXINFO *pmmi;
pmmi = (MINMAXINFO*)lParam;
pmmi->ptMinTrackSize.x = MINW + 16; //クライアントエリア + 16
pmmi->ptMinTrackSize.y = MINH + 61; //クライアントエリア + 61
return FALSE; //処理はDefWndProcに任す
//(解説:メインウィンドウをMINWとMINHの最小サイズに制限する処理です。)
}
bool CMyWnd::OnOthers(UINT Msg, WPARAM wParam, LPARAM lParam) {
//CREDITクラスは文字列検索・置換用にユーザーメッセージを作るので、
//このような処理を行います。CREDITファイルを覗いてください。
if(Msg == m_Edit.m_frMsg)
m_Edit.FindReplace(lParam); //検索・置換処理
//(解説:CREDITクラスの文字列の検索・置換処理であるFindReplace関数を、既に登録したメッセージ(m_frMsg)の際に処理します。なお、ここはboolではなく、voidですね。汗;)
}
/////////////////////////////////
//主ウィンドウCMyWndの関数の定義
//メニュー項目、コントロール関数
/////////////////////////////////
bool CMyWnd::OnNew() {
//新しいタブにリッチエディットコントロールを張り付ける
AddTabEdit(NULL);
SetFocus(m_Edit.GetHandle());
return TRUE;
//(解説:コメント通りです。作成したリッチテキストコントロールにフォーカスを当てて、キャレットを表示させます。)
}
bool CMyWnd::OnOpen() {
if(!g_ByFile) {
//ファイルを開くダイアログ
WCHAR* fn = cmndlg.GetFileName(m_hWnd, FILEFILTER);
if(!fn) {
MessageBoxW(m_hWnd, L"操作はキャンセルされました", L"メッセージ", MB_OK | MB_ICONERROR);
return FALSE;
}
g_FileName = fn;
}
//(解説:ファイル起動の場合はg_FileNameにデータが入ってますが、そうでない場合はファイルを開くダイアログを使います。)
//新しいタブにリッチエディットコントロールを張り付けg_FileNameを読み込む
AddTabEdit(g_FileName.ToChar()); //SetFocusはこの中でやっている
//(解説:新規の場合AddTabEdit関数には"NULL"を渡しますが、ファイルを読み込ませる場合はファイル名を渡します。)
return TRUE;
}
bool CMyWnd::OnSave() {
WCHAR* fn = m_Tab.GetTitle();
//フォーカスのあるタブのリッチエディットコントロールのタイトルを読む
if(!lstrcmpW(fn, L"[無題]"))
OnSaveas();
//(解説:未保存の新規ファイル([無題])の場合は「名前を付けて保存」に飛びます。)
else
//フォーカスのあるタブのリッチエディットコントロールのデータを書き出す
m_Edit.SaveFile(fn);
return TRUE;
}
bool CMyWnd::OnSaveas() {
WCHAR* fn = cmndlg.GetFileName(m_hWnd, L"リッチテキストファイル(*.rtf)\0*.rtf\0総てのファイル(*.*)\0*.*\0\0", FALSE);
//(解説:保存するファイル形式のデフォルトはリッチテキストファイルです。)
if(!fn)
MessageBoxW(m_hWnd, L"操作はキャンセルされました", L"エラー", MB_OK | MB_ICONERROR);
else {
//フォーカスのあるタブのリッチエディットコントロールのデータを書き出す
m_Edit.SaveFile(fn);
SBar.SetText(3, fn); //(解説:ファイル名を変更します。)
}
return TRUE;
}
bool CMyWnd::OnSetprint() {
//フォーカスのあるタブのリッチエディットコントロール
return m_Edit.SetPrinter();
}
bool CMyWnd::OnPrint() {
//フォーカスのあるタブのリッチエディットコントロール
return m_Edit.Print(m_Tab.GetTitle());
}
//(解説:印刷関係は、CREDITクラスの関数によりダイアログを表示させて処理します。)
bool CMyWnd::OnExit() {
SendMessage(m_hWnd, WM_CLOSE, 0, 0);
return TRUE;
}
bool CMyWnd::OnUndo() {
m_Edit.SendMsg(EM_UNDO, 0, 0);
return TRUE;
}
bool CMyWnd::OnCut() {
m_Edit.SendMsg(WM_CUT, 0, 0);
return TRUE;
}
bool CMyWnd::OnCopy() {
m_Edit.SendMsg(WM_COPY, 0, 0);
return TRUE;
}
bool CMyWnd::OnPaste() {
m_Edit.SendMsg(WM_PASTE, 0, 0);
return TRUE;
}
//(解説:もともとリッチテキストコントロールはコピペとやり直し処理を織り込んでいるのでこのように簡素です。)
bool CMyWnd::OnSelall() {
CHARRANGE cr;
cr.cpMin = 0;
cr.cpMax = -1;
m_Edit.SendMsg(EM_EXSETSEL, 0, (LPARAM)&cr);
return TRUE;
}
//(解説:リッチテキストコントロール内の文字列の選択はCHARRANGE構造体を使って行います。0から-1(最後)までを選択する、という意味です。)
bool CMyWnd::OnFind() {
m_hDlg = m_Edit.m_hFRDlg = FindTextW(m_Edit.SetFRDlg(L'F'));
return TRUE;
}
bool CMyWnd::OnReplace() {
m_hDlg = m_Edit.m_hFRDlg = ReplaceTextW(m_Edit.SetFRDlg(L'R'));
return TRUE;
}
//(解説:既に解説を行った「文字列の検索・置換」処理です。)
bool CMyWnd::OnDelete() {
return DelTabEdit();
}
bool CMyWnd::OnFont() {
m_Edit.SelFont();
return TRUE;
}
//(解説:CREDITクラスのフォント選択ダイアログでフォントを選択する関数を呼んでいます。)
bool CMyWnd::OnLeft() {
m_Edit.Align(L'L');
return TRUE;
}
bool CMyWnd::OnCenter() {
m_Edit.Align(L'C');
return TRUE;
}
bool CMyWnd::OnRight() {
m_Edit.Align(L'R');
return TRUE;
}
bool CMyWnd::OnLindent() {
m_Edit.Indent(1);
return TRUE;
}
bool CMyWnd::OnLoutdent() {
m_Edit.Indent(2);
return TRUE;
}
bool CMyWnd::OnRindent() {
m_Edit.Indent(3);
return TRUE;
}
bool CMyWnd::OnRoutdent() {
m_Edit.Indent(4);
return TRUE;
}
//(解説:これらも元々リッチテキストコントロールにある左右中央寄せ、インデントの処理をCREDITクラスのメンバー関数で行っています。)
bool CMyWnd::OnBrief() {
MessageBoxW(m_hWnd,
L"RTWEditorはテキストやリッチテキスト用のエディターです。\n"\
"拡張子がリッチテキスト(*.rtf)の場合その形式で取り扱い、*.txt等"\
"その他の拡張子のファイルではテキストファイルとして取り扱います。\n"\
"起動はダブルクリックの他、ファイルをプログラムアイコンへドロップすることでも可能です。"\
"また起動後もドラッグアンドドロップでファイルを開くことができます。",
L"簡単な説明", MB_OK | MB_ICONINFORMATION);
return TRUE;
}
//(解説:RTWEditorの概要説明です。)
bool CMyWnd::OnShortcut() {
MessageBoxW(m_hWnd,
L"Ctrl+N-新規作成\nCtrl+O-ファイルを開く\nCtrl+S-ファイルの保存\nCtrl+P-印刷\nCtrl+X-終了\n\n"\
"Ctrl+U-元に戻す\nCtrl+T-切り取り\nCtrl+C-コピー\nCtrl+V-貼り付け\n\nCtrl+F-文字列の検索\n"\
"Ctrl+R-文字列の置換\n\nF1-ショートカットキーの解説\nF2-バージョン情報",
L"ショートカットキーの解説", MB_OK | MB_ICONINFORMATION);
return TRUE;
}
//(解説:アクセラレーターの説明です。)
bool CMyWnd::OnVer() {
versiondlg.DoModal(m_hWnd, L"IDD_VERSION", GetInstance());
return TRUE;
}
//(解説:バージョン表示ダイアログです。)
///////////////////
//ユーザー定義関数
///////////////////
bool CMyWnd::AddTabEdit(WCHAR* fn) {
//新しいタブに表示するリッチエディットコントロールの作成
if(!m_Edit.Create(L"", WS_CHILD | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL |
WS_HSCROLL | ES_NOHIDESEL | ES_MULTILINE | ES_WANTRETURN,
WS_EX_CLIENTEDGE, m_hWnd, m_EditID)) {
MessageBoxW(m_hWnd, L"リッチエディットコントロールが作れませんでした",
L"エラー", MB_OK | MB_ICONERROR);
return FALSE;
}
//リッチエディットコントロールからの特定通知(例:ENM_MOUSEEVENTS)を開始
m_Edit.FilterMsg(ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_SELCHANGE);
//リッチエディットコントロールのフォント設定
m_Edit.SetFont(11, L"MS 明朝");
m_Edit.SetCol(RGB(0, 0, 0));
//リッチエディットコントロールの文字色設定
if(!fn) //読み込むファイルが無い(指定ファイルパス、名ポインターがNULL)場合、「[無題]」にする
fn = L"[無題]";
else //読み込むファイルが有れば読み込む
m_Edit.LoadFile(fn);
//新しいタブを作成し、新規リッチエディットコントロールを付ける
if(!m_Tab.AddPage(m_EditID, IDI_DOC, fn)) {
MessageBoxW(m_hWnd, L"既にコントロールが作られているか、これ以上タブを設定できません",
L"エラー", MB_OK | MB_ICONERROR);
DestroyWindow(m_Edit.GetHandle()); //既に作成した新規リッチエディットコントロールを破棄
return FALSE;
}
//メニューとツールバーの状態を変更する
ChangeMenuStatus(TRUE);
//ステータスバーにファイル名を表示する
SBar.SetText(3, fn);
//次のリッチエディットコントロールIDの設定(ユニークにする為に、コントロールが削除されても永久欠番にする)
m_EditID++;
return TRUE;
}
//(解説:タブを増やし、リッチテキストコントロールを張り付け、ファイルがあればそれを読み込む処理のユーザー定義関数です。)
bool CMyWnd::DelTabEdit() {
int sel = m_Tab.GetPage();
if(sel == -1) {
MessageBoxW(m_hWnd, L"タブが選択されていません", L"エラー", MB_OK | MB_ICONSTOP);
return FALSE;
}
if(MessageBoxW(m_hWnd, L"選択されているタブを削除しますか?", L"削除確認", MB_YESNO | MB_ICONQUESTION) == IDYES) {
//ファイルが変更されていれば、保存するか否か確認する
if(SendMessage(m_Edit.GetHandle(), EM_GETMODIFY, 0, 0)) {
if(MessageBoxW(m_hWnd, L"ファイルが変更されています。保存しますか?", L"保存確認", MB_YESNO | MB_ICONQUESTION) == IDYES)
m_Edit.SaveFile(m_Tab.GetTitle());
}
m_Tab.DeletePage(); //現在の表示タブページで表示されている親のコントロールを破壊してくれる
//ステータスバーをクリアする
SBar.SetText(1, L"");
SBar.SetText(2, L"");
SBar.SetText(3, L"");
if(m_Tab.TabCount() == 0) { //すべてのタブがなくなったら
//メニューとツールバーの状態を変更する
ChangeMenuStatus(FALSE);
return TRUE;
}
else {
if(!m_Tab.SetPage(sel))
m_Tab.SetPage(sel - 1);
m_Edit.SetHandle(m_Tab.GetCtrl());
m_Tab.FitSiblings((WPARAM)IDC_TAB);
SBar.SetText(3, m_Tab.GetTitle());
return TRUE;
}
}
return FALSE;
}
//(解説:逆にファイル保存確認を行い、タブとリッチテキストコントロールを削除する処理です。メインウィンドウではスタータスバーの初期化、フォーカスを与えるタブの設定、すべてのタブがなくなったらメニューとツールバーの状態変更を行います。)
bool CMyWnd::PopupMenu() {
//ウインドウの位置情報を取得
RECT rec;
GetWindowRect(m_hWnd, &rec);
//ポップアップメニューの表示場所を設定
POINT pt;
GetCursorPos(&pt);
//ポップアップメニューの表示
return TrackPopupMenu(g_hPopup, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, pt.x, pt.y, 0, m_hWnd, &rec);
}
//(解説:タブとリッチテキストコントロールで共通のポップアップメニュー処理です。)
///////////////////////////////
//ユーザーダイアログの関数定義
//コントロール関数
///////////////////////////////
bool VERSIONDLG::OnIdok() {
versiondlg.EndModal(TRUE);
return TRUE;
}
//(解説:お馴染み、バージョン表示ダイアログです。)
いかがでしたでしょうか?元々MDIベースのリッチテキストエディタ―はちょっと時代遅れかな、と思い、タブベースのエディターを作りたかったのでECCSkeltonで組んでみました。(他の自作プログラム同様)現在私のちょちょっとしたメモ書き用のエディターで愛用していますが、RTEditorよりも使いやすいみたいです。