[[Page007]]

* Document object の置き換え [#xc3591ec]
前節までで、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 類は &ref("myapp08.tgz") として固めてある。
ここでの source 類は &ref("myapp08.tgz"); として固めてある。

** Document の handle 化 [#ga18882c]
 // 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 の変更 [#g40dfc59]
上記変更に伴い従来 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;
 }

となるだけである。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS