プレビュー機能を追加しよう
タグを追加していくHTMLエディタでは、現在HTMLでどのように見えているのか?が分からりません。そこで一旦ファイル保存し、通常ブラウザを起動して、調べていく必要があります。そこでHTMLエディタのほうで、一時的にファイルを保存し、ブラウザを自動的に立ち上げるようにしてあげればかなり便利になりますね。これがプレビュー機能です。この章では、シリアライゼーション(シリアル化)について軽く触れ、コーディングを進めていこうと思います。今回は結構すんなりとこなせるはずです。気楽にすすめていきましょう。

24.シリアル化とはなんでしょうか?
突然出てきた「シリアル化(シリアライゼーション)」と言う言葉ですが、この言葉について説明していきますね。
今作成中のエディタ(CEditView)では、編集中のドキュメント内容は、メモリ上に構築されているに過ぎないので、CEditViewが削除されると、ドキュメント内容は消えてしまいます。したがってドキュメントを永久保存するためには、ディスクに保存する必要があります。またドキュメントを開くときは、ディスクからドキュメントを読み込み、メモリ上に再構築できます。この保存データ作成処理を、"シリアル化" と呼びます。この逆の操作、つまりファイルからメモリ内にオブジェクトを構築する処理を逆シリアル化(デシリアライゼーション)と呼びます。

シリアライゼーションのビジョン


でもなんでこんな面倒くさい操作をやるんだろうなぁと、私も初め思っていたのです。CEditViewクラスのCEditを操作するポインタを取得すれば、CFileクラスで保存することは可能です。シリアル化の重要な点は以下の2つです。
オブジェクト自身が読み書きを自動的に行なう点
逆シリアル化でオブジェクトを再構築する点
よく分からいなぁと思う人も多いでしょうが、このオブジェクト自身による自動的な読み書きのおかげで、私たちはドキュメントを簡単に保存したり、開いたりしているわけです。例えばドキュメントを開くときには、本来こんな作業をしなくてはいけません。([ファイル]-[開く]の場合)
1.ファイル名を指定する
これは当たり前ですが、一応書いておきます
2.適切なドキュメントテンプレートを選択する
ドキュメントは、どのフレームとどのビューを使うか定義されています。この定義をドキュメントテンプレートといいます。したがってドキュメントテンプレートが1つなら何も問題はないのですが、アプリによっては、複数のドキュメントタイプやビュー、フレームをサポートすることもあります。例えば、1 つのアプリでテキストドキュメントグラフィックスドキュメントをサポートすることもあります。このようなアプリでは、[ファイル] メニューの [新規作成] を選択すると、ダイアログボックスにオープン可能なドキュメントタイプが一覧表示されます。したがってアプリは、選択されたファイルが、どのドキュメントタイプに適合するかを選択する必要があるのです。作成中のMyHtmlではmyhtml.cppのInitInstance内に以下の記述があります。
BOOL CMyHtmlApp::InitInstance()
{

	(中略)

	// アプリケーション用のドキュメント テンプレートを登録します。ドキュメント テンプレート
	//  はドキュメント、フレーム ウィンドウとビューを結合するために機能します。

	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CMyHtmlDoc),
		RUNTIME_CLASS(CMainFrame),       // メイン SDI フレーム ウィンドウ
		RUNTIME_CLASS(CMyHtmlView));
	AddDocTemplate(pDocTemplate);

	(中略)

}
ようするに、SDIといってきたのはシングルドキュメント(テンプレート)インターフェイスのことなのです。したがって開かれたHTMLファイルは、すべてこのテンプレートで開かれるために、テンプレートの選択は実際は行わなくてすみます。
3.フレーム、ドキュメント、ビューを作成します。
ここで作るの?とお思いでしょうが、開くファイルが変わればビュー・ドキュメントオブジェクトもかわります。MDIつまりマルチドキュメント(テンプレート)インターフェイスでは、それぞれのファイルごとドキュメントもビューも別ものということになります。したがって、先ほど選んだドキュメントテンプレートの記述にしたがったフレーム、ドキュメント、ビューを作成しなくてはなりません。MyHtmlでは、CMainFrameオブジェクト、CMyHtmlDocオブジェクト、CMyHtmlViewオブジェクトを作成します。
4.ファイルをオープンし、と同時にアーカイブオブジェクトを作成します。
アーカイブとは、シリアル化処理を行うものです。
5.メモリにファイル内容をストアします
ここでは作成したCMyHtmlDocオブジェクト、CMyHtmlViewオブジェクトにファイルデータを渡します。
てな作業を、プログラマーがやらなくてはならないのですよ。ただファイルをCFileでオープンするのと違って大変でしょう?メモリに「ビュー・ドキュメント・フレームオブジェクトを作成している」というのは、先ほども言ったオブジェクトを再構築することそのものです。

書き込みも同様で、アーカイブを作成してシリアライズをします。つまりこんな面倒くさい操作をすることになるのですが、MFCのドキュメントクラスには簡単に行える関数があります(これは便利)。しかし安易に使用するのでなくて、このようなシリアル化が背後で行われていることを知っているだけでもかなり大切だと思います。

25.さてコーディングですが
シリアル化のところを読んでいただいた人はもうお分かりだと思いますが、ドキュメントの管理はCMyHtmlDocクラスが行っています。この中でファイルに一時保存し、それをブラウザで表示させればいいのですね。まずはメニューを編集して、プレビューを動作させる関数を追加します。とりあえずリソースタブをクリック、メニューIDR_MAINFRAMEを開いておきましょう。
1.ポップアップの作成
[ファイル]や[編集]など一番上にくるメニューを追加します。プロパティのポップアップへのチェックを忘れないでください。キャプションは[ツールがいいでしょう。
2.プレビューメニューの追加
作成した[ツール]メニューの中に[プレビュー]を追加します。IDにはID_TOOL_PREVIEWをしておきましょう。
3.クラスウィザードで関数を追加
ID_TOOL_PREVIEWに関してメッセージCOMMANDをバインドします。この時、バインドするクラス(関数を記述するクラス)は、CMyHtmlDocクラスにします。
4.以下のコードを記述
void CMyHtmlDoc::OnToolPreview() 
{
	// CEditViewへのポインタの取得
	CMyHtmlView* pView = GetMyView();

	char	chDrv[_MAX_DRIVE];	// ドライブ名
	char	chDir[_MAX_DIR];	// ディレクトリ名
	CString 	strTempFile;

	// 現在編集中のドキュメントのパスを取得
	if(GetPathName().IsEmpty()){AfxMessageBox("ドキュメントを一度保存してください");return;}
	
	// 一時ファイル名の作成
	_splitpath(GetPathName(),chDrv,chDir,NULL,NULL);
	strTempFile =(CString)chDrv + (CString)chDir + "\\tmp_preview.html";

	// シリアル化
	OnSaveDocument(strTempFile);
	
	// 表示
	::ShellExecute(NULL,NULL,strTempFile,NULL,NULL,SW_SHOWNORMAL);	
}
最初にコードを表示してしまいましたが、いろいろ悩んだ挙句、初心者の(私もまだまだこの部類に入りますが)方に一番分かりやすいものとして、この方法で行くことにしました。何に悩んでいるかというと、一時ファイルのことです。

基本的に、一時ファイルは以下の3つの条件を満たすべきだと考えられます(Windowsのみ)。
一時フォルダに作成されること
一時ファイルは、一時フォルダ(通常WINDOWSフォルダにあるTEMPフォルダのことです)に作成されるべきです。
ファイル名がユニーク(一意)であること
ファイル名が重複すると、他のソフトウェアが使用している一時ファイルを書き換えてしまう可能性があるからです
ファイルの管理能力
作成した一時ファイルの管理は、作成した側であることに注意です。
そして、以下のような手順で行わなくてはなりません。
  1. 一時ファイル作成(ユニーク名を持ち)
  2. ブラウザで一時ファイル表示
  3. ブラウザが閉じられたことを検知
  4. 一時ファイル削除
これらを実現するためには、他のアプリケーションの終了を検知する必要性があります。これらは今作成しているHTMLエディタのレベルから考えれば少しむずかしいと判断し、ここまでやる必要はないなぁ と判断しました。

そこで今回は、tmp_preview.htmlというファイル名の一時ファイルを作成し、それをブラウザで表示する方法にしました。そして一時ファイルを作成する場所は、現在編集中のドキュメントの同じフォルダにしました。そうすれば、画像や相対リンクがかわらないので、ただ単にシリアル化すればよくなるからです。したがって余裕のある人は、プロセス管理の勉強もこめて自分でアレンジしてくださいね。ここでは、とりあえず動くプログラム(この動くってのが、初心者にとって非常に肝心です)を作成したのが、上記に記述したコードです。

簡単な解説ですが、
現在編集中のドキュメントのフルパスを取得
フルパスが空、つまり未保存の場合は、メッセージを出力して終了します。
フルパスからファイル名を取り除く
このフルパスからドライブとディレクトリのみ取り出します。これが一時ファイルの保存先となります。
一時ファイル名を決める
上の操作を施したものに、"\tmp_preview.html"を追加します。
シリアル化
すなわち、編集中の内容をアーカイバを通して保存します。
ブラウザで開く
作成した一時ファイルを通常使うブラウザで開きます。
さてプレビューがうまくできたでしょうか?このコードでは、tmp_preview.htmlというファイルは作成すると危険であるという制約条件がついていますけれども動作するはずなので(^^;)今回はこれをヨシとしておきましょう。でも逆にいうと、tmp_preview.htmlは消してもOKなので、使う側にとっては安心かもしれません。余裕のある人は、ユニークファイルの作成に挑戦してみてください。

[Next]
[Previous]
[Home]