Page007

Document object の置き換え

前節までで、command line で指定された file を表示することはできるようになった。しかしながら、 program 起動後に file を読みたいことや、更に別の file を表示させたいことも多い。Windows program では、むしろその用法の方が多い。これを実装するには、current document の置き換えが必要になる。起動後の表示は empty document との置き換えと考えればよい。

前節の実装では、current document は pointer として保持していたので、その思想をそのまま延長すると、

  • current document を delete
  • 次の document を new して current document の pointer へ set

とすればよい。

しかしながら、例えば印刷とか、file への保存などを表示と同時に行いたい場合など単純に delete できない。どれが先に終了するかわからない複数の thread が同一 object に access するので、固定されたどれかの thread で消去するわけにはいかない。これを安全に実行するためには、各 thread 毎に object のコピーを持たせるのがよいが、画像などでは占有 memory が大きいことも想定され、非効率になることも考えられる。そこで、ここでは handle を使った方法で実装する。

ここでの source 類は filemyapp08.tgz として固めてある。

Document の handle 化

// mydoc.h
#ifndef MYDOC_H_INCLUDED
#define MYDOC_H_INCLUDED

#include "myconten.h"

namespace mylib
{

class CMyDoc
{
public:
	CMyDoc();
	CMyDoc(CMyContent* pContent);
	CMyDoc(const CMyDoc& src);
	virtual ~CMyDoc();
	CMyDoc& operator=(const CMyDoc& src);
	SIZE Size(HDC hdc);
	int Draw(HDC hdc, int x, int y, PAINTSTRUCT& ps);

protected:
	int* m_pCounter;
	CMyContent* m_pContent;
};

}	// namespace mylib
#endif	// MYDOC_H_INCLUDED

以下に実装を示すが、代入演算子で、自己代入の検査を行う部分が、m_pContent の比較ではなく、m_pCounter の比較であることに注意する。m_pContent は 0(NULL) に成り得るので、同一 object でなくとも互いに 0 で一致する可能性があるからである。一方、m_pCounter は必ず new するので、0 で一致することはない。

// mydoc.cpp

#include "mydoc.h"

namespace mylib
{

CMyDoc::CMyDoc() :
	m_pCounter(new int(1)), m_pContent(0)
{
}

CMyDoc::CMyDoc(CMyContent* pContent) :
	m_pCounter(new int(1)), m_pContent(pContent)
{
}

CMyDoc::CMyDoc(const CMyDoc& src) :
	m_pCounter(src.m_pCounter), m_pContent(src.m_pContent)
{
	(*m_pCounter)++;
}

CMyDoc::~CMyDoc()
{
	if(--(*m_pCounter) == 0)
	{
		delete m_pContent;
		delete m_pCounter;
	}
}

CMyDoc&
CMyDoc::operator=(const CMyDoc& src)
{
	if(m_pCounter == src.m_pCounter)
		return *this;

	if(--(*m_pCounter) == 0)
	{
		delete m_pContent;
		delete m_pCounter;
	}
	m_pContent = src.m_pContent;
	m_pCounter = src.m_pCounter;
	(*m_pCounter)++;
	return *this;
}

SIZE
CMyDoc::Size(HDC hdc)
{
	SIZE sz;
	if(m_pContent)
		sz = m_pContent->Size(hdc);
	else
	{
		sz.cx = 0;
		sz.cy = 0;
	}
	return sz;
}

int
CMyDoc::Draw(HDC hdc, int x, int y, PAINTSTRUCT& ps)
{
	int n;
	if(m_pContent)
		n = m_pContent->Draw(hdc, x, y, ps);
	else
		n = 0;
	return n;
}

} // namespace mylib

CMyApp class と CMyAppWin class の変更

上記変更に伴い従来 myapp.h の中で

public:
	CMyContent* m_pDoc;

としていた部分を

public:
	CMyDoc m_curDoc;

とする。また、これに伴い destructor 中での

	delete m_pDoc;

は不要となるので削除する。

Run 関数まわりは若干変更となるので全部示しておく。

int
CMyApp::Run(int nCmdShow)
{
	// Create Window
	CMyAppWin appwin(m_szAppTitle);

	// Create the document
	if(m_DocName.size() > 0)
	{
		std::vector<TCHAR>::const_iterator p = m_DocName.begin();
		switch(ContentType(&*p))
		{
		case CMyContent::TEXT_PLAIN:
			m_curDoc = CMyDoc((CMyContent*)(new CMyPlain(&*p)));
			break;
		case CMyContent::IMAGE_JPEG:
			m_curDoc = CMyDoc((CMyContent*)(new CMyDjpeg(&*p)));
			break;
		case CMyContent::IMAGE_BMP:
			m_curDoc = CMyDoc((CMyContent*)(new CMyBMP(&*p)));
			break;
		default:
			break;
		}
	}
	appwin.Show(nCmdShow);
	appwin.Update();

	POINT pt;
	pt.x = 0;
	pt.y = 0;
	HDC hdc = appwin.GetDC();
	SIZE sz = m_curDoc.Size(hdc);
	appwin.ReleaseDC(hdc);
	appwin.SetDrawSize(pt, sz);
	
	// Enter Message Loop
	MSG msg;
	while(GetMessage(&msg, 0, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return (int)msg.wParam;
}

一方、CMyAppWin の方は、OnPaint 関数が

BOOL
CMyAppWin::OnPaint()
{
	PAINTSTRUCT ps;
	HDC hdc = CMyWin::BeginPaint(&ps);
	g_pApp->m_curDoc.Draw(hdc, -m_ptOffset.x, -m_ptOffset.y, ps);
	CMyWin::EndPaint(&ps);
	return TRUE;
}

となるだけである。


添付ファイル: filemyapp08.tgz 13859件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2007-08-16 (木) 16:42:03 (75d)