2007년 4월 24일 화요일
2007년 4월 23일 월요일
MemDC를 이용한 비트맵 출력
// OnDraw(CDC* pDC) 내에서 경우
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
CBitmap bitmap;
bitmap.LoadBitmap(IDB_ME); // Bitmap 리소스
CBitmap *pOldBitmap = (CBitmap *)MemDC.SelectObject(&bitmap);
pDC->BitBlt(0, 0, 100, 100, &MemDC, 0, 0, SRCCOPY);
MemDC.SelectObject(pOldBitmap);
// End
별그리기 (CRgn)
// 다각형의 모양을 가지는 점들의 집합을 준비합니다.
// 여기는 별만 그리지만 삼각형도 똑 같습니다.
// 그리는 모양은 마음대로 바꾸세요.
CPoint points[11];
// 72' 씩 회전된 꼭지점으로 이루어진 점 생성
// 여기서 알아서 모양을 만드세요.
double Pi = 3.14159265359;
for ( int i = 0; i < 10; i += 2 )
{
// 별의 바깥쪽 꼭지점 (큰 반지름으로 만듬)
points[i].x = (long)(25*cos((double)(i*72*Pi)/360.0));
points[i].y = (long)(25*sin((double)(i*72*Pi)/360.0));
// 별의 안쪽 꼭지점 (작은 반지름으로 만듬)
points[i+1].x = (long)(10*cos((double)((i+1)*72*Pi)/360.0));
points[i+1].y = (long)(10*sin((double)((i+1)*72*Pi)/360.0));
}
// 끝점은 첫점과 같게 맞춤니다.
points[10] = points[0];
CRgn rgnStar;
rgnStar.CreatePolygonRgn(points, 11, WINDING);
// 클라이언트 영역을 가져옵니다.
CRect r;
GetClientRect(&r);
// 그림 그릴 브러시를 초기화합니다.
CBrush brush;
brush.CreateSolidBrush(RGB(0,0,0));
// 영역을 초기화 합니다.
CRgn rgn;
rgn.CreateRectRgn(0, 0, 0, 0);
rgn.CopyRgn(&rgnStar);
rgn.OffsetRgn(point.x, point.y);
// 별을 그립니다.
dc.FillRgn(&rgn, &brush);
데스크탑윈도우의 DC를 얻어서 사용하는 방법
Very simple, uhh~
CRect r;
GetClientRect(&r);
CClientDC desktopDC(GetDesktopWindow());
pDC->BitBlt(0, 0, r.Width(), r.Height(), &desktopDC, 0, 0, SRCCOPY);
2007년 4월 19일 목요일
Using DirectX with MFC (2)
DirectX는 제대로 설치되어 있다고 가정한다.
SDI로 App 를 생성하고 Document/View Architecture 를 Uncheck 한다.
기타 원하는 대로 만든다.
프로젝트가 생성이 되면 ChildView.h 및 ChildView.cpp 를 삭제한다.
DirectX 프로그래밍에서는 별도의 View가 필요가 없다.
MainFrm.h 에서
#include "ChildView.h"
를 삭제한다. 그 다음
CMainFrame 내의
CChildView m_wndView;
도 삭제한다.
CMainFrame::OnCreate() 내의
// create a view to occupy the client area of the frame
if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
{
TRACE0("Failed to create view window\n");
return -1;
}
부분을 삭제하고 대신
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
/////////////////////////////////////////////////////////////////////
// 여기에DirectX의초기화를수행한다.
/////////////////////////////////////////////////////////////////////
HWND hDevice, hFocus;
HRESULT hr;
hDevice = GetSafeHwnd();
hFocus = GetTopLevelParent() ->GetSafeHwnd();
GetClientRect(&m_rectClient);
// Create Direct3D object
m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
D3DDISPLAYMODE d3ddm;
m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
// D3DPRESENT_PARAMETERS 구조체의설정
::ZeroMemory(&m_d3dpp, sizeof(m_d3dpp));
m_d3dpp.Windowed = TRUE;
m_d3dpp.BackBufferCount = 1;
m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
m_d3dpp.EnableAutoDepthStencil = TRUE;
m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
m_d3dpp.hDeviceWindow = hDevice;
m_d3dpp.BackBufferWidth = m_rectClient.Width();
m_d3dpp.BackBufferHeight = m_rectClient.Height();
m_d3dpp.BackBufferFormat = d3ddm.Format;
m_d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
// 디바이스작성
hr = m_pD3D->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hFocus,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&m_d3dpp,
&m_pd3dDevice
);
m_pd3dDevice->SetDialogBoxMode(TRUE);
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
////////////////////////////////////////////////////////////////////
// 여기까지DirectX의초기화부분임
////////////////////////////////////////////////////////////////////
return 0;
}
와 같이 필요한 초기화를 수행한다.
CMainFrame::OnSetFocus() 함수를 삭제한다.
CMainFrame::OnCmdMsg() 함수를 삭제한다.
“stdafx.h” 에 다음 줄들을 추가한다.
그때 그때 필요한 부분을 알아서 추가해야 한다.
필요한 헤더 파일들과 링크할 라이브러리 파일들이다.
// Direct3D includes
#include
#include
#include
// DirectSound includes
#include
#include
#include
#pragma comment( lib, "dxerr.lib" )
#pragma comment( lib, "dxguid.lib" )
#if defined(DEBUG) defined(_DEBUG)
#pragma comment( lib, "d3dx9d.lib" )
#else
#pragma comment( lib, "d3dx9.lib" )
#endif
#pragma comment( lib, "d3d9.lib" )
#pragma comment( lib, "winmm.lib" )
#pragma comment( lib, "comctl32.lib" )
CMainFrame 의 헤더파일에 아래를 추가한다.
// Attributes
public:
CRect m_rectClient; // Client window size
IDirect3D9* m_pD3D; // The IDirect3D9 interface
IDirect3DDevice9* m_pd3dDevice; // D3D Device
D3DPRESENT_PARAMETERS m_d3dpp; // The present parameters.
bool m_bReady; // Is DX9 ready to render?
// Operations
public:
void Render(); // Render
Constructor에서 필요한 초기화를 수행한다.
CMainFrame::CMainFrame()
{
// 필요한초기화를수행한다.
m_pD3D = NULL;
m_pd3dDevice = NULL;
m_bReady = false;
}
ReleaseAllObject() 라는 함수를 하나 만들고 아래와 같이 추가한다.
void CMainFrame::ReleaseAllObject()
{
// DirectX가시동되었으면삭제
if ( m_pD3D != NULL )
{
if ( m_pd3dDevice != NULL)
{
m_pd3dDevice->Release();
m_pd3dDevice = NULL;
}
m_pD3D->Release();
m_pD3D = NULL;
}
}
WM_ACTIVATEAPP 의 Event handler 를 만들고 아래를 추가한다.
void CMainFrame::OnActivateApp(BOOL bActive, DWORD dwThreadID)
{
CFrameWnd::OnActivateApp(bActive, dwThreadID);
// 준비 완료
m_bReady = bActive;
}
WM_DESTROY 의 Event handler 를 만들어 주고 아래를 추가한다.
void CMainFrame::OnDestroy()
{
ReleaseAllObject();
CFrameWnd::OnDestroy();
// TODO: Add your message handler code here
}
당연히 Render() 함수도 구현해 준다.
void CMainFrame::Render()
{
m_pd3dDevice->Clear(
0,
NULL,
D3DCLEAR_TARGET D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0, 0, 0),
1.0f,
0
);
if(SUCCEEDED(m_pd3dDevice->BeginScene()))
{
m_pd3dDevice->EndScene();
}
m_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
이제 Test 겸 다음과 같이 실행해 본다.
void CMainFrame::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CFrameWnd::OnPaint() for painting messages
Render();
}
검은 색 화면이 나오면 일단 성공한 것이다.
Using DirectX with MFC
우선 “stdafx.h”에
// Direct3D includes
#include <d3d9.h>
#include <d3dx9.h>
#include <dxerr.h>
// DirectSound includes
#include <mmsystem.h>
#include <mmreg.h>
#include <dsound.h>
#pragma comment( lib, "dxerr.lib" )
#pragma comment( lib, "dxguid.lib" )
#if defined(DEBUG) || defined(_DEBUG)
#pragma comment( lib, "d3dx9d.lib" )
#else
#pragma comment( lib, "d3dx9.lib" )
#endif
#pragma comment( lib, "d3d9.lib" )
#pragma comment( lib, "winmm.lib" )
#pragma comment( lib, "comctl32.lib" )
를 추가한다. 그때 그때 필요한 헤더파일과 라이브러리를 포함해야 한다.
그리고 XXXView.h 파일을 열고 아래 내용들을 추가한다.
CRect m_rectClient; // Client window size
IDirect3D9* m_pD3D; // The IDirect3D9 interface
IDirect3DDevice9* m_pd3dDevice; // D3D Device
D3DPRESENT_PARAMETERS m_d3dpp; // The present parameters.
bool m_bReady; // Is DX9 ready to render?
void Render(); // Render
XXXView.cpp 파일을 열고 OnInitialUpdate() 함수를 override하고 아래 내용을 추가한다.
void XXXView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
HWND hDevice, hFocus;
HRESULT hr;
hDevice = GetSafeHwnd();
hFocus = GetTopLevelParent() ->GetSafeHwnd();
GetClientRect(&m_rectClient);
// Create Direct3D object
m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
D3DDISPLAYMODE d3ddm;
m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
// D3DPRESENT_PARAMETERS 구조체의설정
::ZeroMemory(&m_d3dpp, sizeof(m_d3dpp));
m_d3dpp.Windowed = TRUE;
m_d3dpp.BackBufferCount = 1;
m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
m_d3dpp.EnableAutoDepthStencil = TRUE;
m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
m_d3dpp.hDeviceWindow = hDevice;
m_d3dpp.BackBufferWidth = m_rectClient.Width();
m_d3dpp.BackBufferHeight = m_rectClient.Height();
m_d3dpp.BackBufferFormat = d3ddm.Format
m_d3dpp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
// 디바이스작성
hr = m_pD3D->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hFocus,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&m_d3dpp,
&m_pd3dDevice);
m_pd3dDevice->SetDialogBoxMode(TRUE);
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
m_bReady = TRUE;
}
Render() 함수는 아래와 같다.
void CeConsoleView::Render()
{
m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
if(SUCCEEDED(m_pd3dDevice->BeginScene()))
{
m_pd3dDevice->EndScene();
}
m_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
마지막으로 OnDraw() 함수에 아래 내용을 추가하면 준비는 완료
// TODO: add draw code for native data here
if( m_bReady )
Render();
2007년 4월 16일 월요일
Using DirectShow
Getting the SDK package
At the first stage, you have to download following DirectSDK which of version is
February 2005.
http://www.microsoft.com/downloads/details.aspx?FamilyID=8af0afa9-1383-44b4-bc8b-7d6315212323&DisplayLang=en
Then install the extra package in the appropriate directory.
Setting the environmental variables
In the VS.NET, select Tools>Options>VC++ Directories.
Add the include/lib directory in the "Include files" and "Library files".
You can find them in the combo box.
Using the SDK
Test with next code. If there's no error when compiling and excuting, all done.
#include <DShow.h>
#pragma comment(lib, "strmiids.lib")
void main(void)
{
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
// Initialize the COM library.
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return;
}
// Create the filter graph manager and query for interfaces.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
return;
}
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
// Build the graph. IMPORTANT: Change this string to a file on your system.
hr = pGraph->RenderFile(L"C:\\Example.avi", NULL);
if (SUCCEEDED(hr))
{
// Run the graph.
hr = pControl->Run();
if (SUCCEEDED(hr))
{
// Wait for completion.
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
// Note: Do not use INFINITE in a real application, because it
// can block indefinitely.
}
}
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
}
2007년 4월 12일 목요일
Sierpinski Carpet Demo
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
CRect clientRect;
GetClientRect(&clientRect);
SolidBrush brush(Color(255, 0, 0, 0));
SierpinskiCarpet3(g, brush, clientRect.Width()/2, clientRect.Height()/2, 120);
}
void CGdiplusDemoView::SierpinskiCarpet1(Graphics& g, SolidBrush& brush, int x, int y, int r)
{
if ( r <= 0 )
return;
SierpinskiCarpet1(g, brush, x-2*r, y+2*r, r/3);
SierpinskiCarpet1(g, brush, x-2*r, y, r/3);
SierpinskiCarpet1(g, brush, x-2*r, y-2*r, r/3);
SierpinskiCarpet1(g, brush, x, y+2*r, r/3);
SierpinskiCarpet1(g, brush, x, y-2*r, r/3);
SierpinskiCarpet1(g, brush, x+2*r, y+2*r, r/3);
SierpinskiCarpet1(g, brush, x+2*r, y, r/3);
SierpinskiCarpet1(g, brush, x+2*r, y-2*r, r/3);
g.FillRectangle(&brush, x-r/4, y-r/4, r/2, r/2);
}
void CGdiplusDemoView::SierpinskiCarpet2(Graphics& g, SolidBrush& brush, int x, int y, int r)
{
if ( r <= 0 )
return;
SierpinskiCarpet2(g, brush, x-2*r, y+2*r, r/2);
SierpinskiCarpet2(g, brush, x-2*r, y, r/2);
SierpinskiCarpet2(g, brush, x-2*r, y-2*r, r/2);
SierpinskiCarpet2(g, brush, x, y+2*r, r/2);
SierpinskiCarpet2(g, brush, x, y-2*r, r/2);
SierpinskiCarpet2(g, brush, x+2*r, y+2*r, r/2);
SierpinskiCarpet2(g, brush, x+2*r, y, r/2);
SierpinskiCarpet2(g, brush, x+2*r, y-2*r, r/2);
g.FillRectangle(&brush, x-r/4, y-r/4, r/2, r/2);
}
void CGdiplusDemoView::SierpinskiCarpet3(Graphics& g, SolidBrush& brush, int x, int y, int r)
{
if ( r <= 0 )
return;
SierpinskiCarpet3(g, brush, x-r, y+r, r/2);
SierpinskiCarpet3(g, brush, x+r, y+r, r/2);
SierpinskiCarpet3(g, brush, x-r, y-r, r/2);
SierpinskiCarpet3(g, brush, x+r, y-r, r/2);
g.FillRectangle(&brush, x-r/3, y-r/3, r/3, r/3);
}
2007년 4월 10일 화요일
CInternetSession, CHttpConnection, CHttpFile 예제
#include "stdafx.h"
#include "main.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
using namespace std;
void ParseCmdLine(int argc, TCHAR* argv[], TCHAR* envp[]);
void Say(CString status);
int TMainApp(int argc, TCHAR* argv[], TCHAR* envp[]) {
Say("Parsing command line...");
ParseCmdLine(argc, argv, envp);
Say("Allocating variables...");
CString m_sURL = "http://www.digital.go.kr/rss/fc_textxml.jsp?row=120&col=61®ion=7&locationcode=4111573000";
CInternetSession m_Session;
CHttpConnection* m_pHttpConnection=NULL;
CHttpFile* m_pHttpFile = NULL;
Say("Connecting...");
try {
m_pHttpConnection = m_Session.GetHttpConnection(m_sURL,(INTERNET_PORT)80, NULL, NULL);
if( m_pHttpConnection == NULL )
throw CString("Http connection failed");
m_pHttpFile = (CHttpFile*)m_Session.OpenURL(m_sURL);
if( !m_pHttpFile ) {
m_pHttpFile->Close();
delete m_pHttpFile;
throw CString("HttpFile connection failed");
}
}
catch ( CInternetException *pEx ) {
if ( m_pHttpFile) {
m_pHttpFile->Close();
delete m_pHttpFile;
}
if ( m_pHttpConnection ) {
m_pHttpConnection->Close();
delete m_pHttpConnection;
}
TCHAR lpszErrorMessage[255];
pEx->GetErrorMessage(lpszErrorMessage, 255);
pEx->Delete();
cout << lpszErrorMessage << endl;
return 1;
}
catch (CString e) {
cout << "Error : " << (LPCTSTR)e << endl;
cout << "Program aborted..." << endl;
return -1;
}
Say("Connection established.");
Say("Listing file...");
CString line;
while ( m_pHttpFile->ReadString(line) != NULL ) {
// line += "\r\n";
wcout << (LPCTSTR)line << endl;
}
Say("Listing complete");
Say("Shutdown process started");
Say("Deleting m_pHttpFile...");
if ( m_pHttpFile) {
m_pHttpFile->Close();
delete m_pHttpFile;
}
Say("Deleting m_pHttpConnection...");
if ( m_pHttpConnection ) {
m_pHttpConnection->Close();
delete m_pHttpConnection;
}
return 0;
}
void ParseCmdLine(int argc, TCHAR* argv[], TCHAR* envp[]) {
// if ( argc != 2 )
// throw CString(L"Usage : inet.exe ip_address");
}
void Say(CString status) {
cout << (LPCTSTR)status << endl;
}
2007년 4월 8일 일요일
MFC Using registry key
리지스트리 이용하기
Using registry key
InitInstance()에
...
SetRegistryKey(_T("My App"));
...
라고 하면
HKEY_CURRENT_USER\Software\My App\(Project name)
아래에 저장된다.
이것은 Demo only로 OnDraw에 이런 짓은 하지 말기를...
AfxGetApp()->WriteProfileXXX()
AfxGetApp()->GetProfileXXX()
함수 참조
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
CString sTest;
AfxGetApp()->WriteProfileString(L"Section", L"Entry", L"Value");
// Create font
FontFamily fontFamily(L"Arial");
Font font(&fontFamily, 24, FontStyleBold, UnitPixel);
// Create brush
SolidBrush brush(Color(255, 0, 0, 255));
// Center alignment
StringFormat stringFormat;
stringFormat.SetAlignment(StringAlignmentCenter);
stringFormat.SetLineAlignment(StringAlignmentCenter);
sTest = AfxGetApp()->GetProfileString(L"Section", L"Entry");
PointF pointF(100, 100);
g.DrawString(sTest, sTest.GetLength(), &font, pointF, &stringFormat, &brush);
}
GDI+ coordinate transform
이 예제는 Visual C++.NET programming Bible - Young Jin 에서 발췌한 것이다.
// OnInitialUpdate override
void CGdiplusDemoView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
SetTimer(0, 100, NULL);
}
// OnTimer override
void CGdiplusDemoView::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
Invalidate();
CView::OnTimer(nIDEvent);
}
#define R_SUN 50
#define R_EARTH 30
#define R_MOON 20
#define EARTH_TO_SUN 300
#define EARTH_TO_MOON 70
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
static int angleEarth, angleLunar;
CRect rect;
GetClientRect(rect);
Pen pen(Color(255, 0, 0, 0), 3);
SolidBrush brush(Color(255, 0, 0, 255));
// Create font
FontFamily fontFamily(L"Arial");
Font font(&fontFamily, 12, FontStyleBold, UnitPixel);
// Text output format
StringFormat stringFormat;
stringFormat.SetAlignment(StringAlignmentCenter);
stringFormat.SetLineAlignment(StringAlignmentCenter);
// Draw sun
g.ResetTransform();
g.TranslateTransform((REAL)rect.Width()/2, (REAL)rect.Height()/2);
g.DrawEllipse(&pen, -R_SUN, -R_SUN, 2*R_SUN, 2*R_SUN);
g.DrawString(L"SUN", 3, &font, PointF(0, 0), &stringFormat, &brush);
// Draw earth
g.RotateTransform((REAL)angleEarth);
g.TranslateTransform(EARTH_TO_SUN, 0);
g.DrawEllipse(&pen, -R_EARTH, -R_EARTH, 2*R_EARTH, 2*R_EARTH);
g.DrawString(L"EARTH", 5, &font, PointF(0, 0), &stringFormat, &brush);
// Draw moon
g.RotateTransform((REAL)angleLunar);
g.TranslateTransform(EARTH_TO_MOON, 0);
g.DrawEllipse(&pen, -R_MOON, -R_MOON, 2*R_MOON, 2*R_MOON);
g.DrawString(L"MOON", 4, &font, PointF(0, 0), &stringFormat, &brush);
angleEarth++;
angleLunar += 12;
}
GDI+ mapping mode
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
Pen pen(Color(255, 0, 0, 0), 3);
/*
enum Unit
{
UnitWorld, // 0 -- World coordinate (non-physical unit)
UnitDisplay, // 1 -- Variable -- for PageTransform only
UnitPixel, // 2 -- Each unit is one device pixel.
UnitPoint, // 3 -- Each unit is a printer's point, or 1/72 inch.
UnitInch, // 4 -- Each unit is 1 inch.
UnitDocument, // 5 -- Each unit is 1/300 inch.
UnitMillimeter // 6 -- Each unit is 1 millimeter.
};
*/
// Pixel mapping
g.SetPageUnit(UnitPixel);
g.DrawRectangle(&pen, 30, 30, 60, 60);
// Milimeter mapping
g.SetPageUnit(UnitMillimeter);
g.DrawRectangle(&pen, 30, 30, 60, 60);
}
GDI+ clipping region
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
// Create region
Point points[] = {
Point(10, 30), Point(200, 10), Point(150, 50), Point(170, 150)
};
GraphicsPath path;
path.AddPolygon(points, 4);
Region region(&path);
// Draw region
Pen pen(Color(255, 0, 0, 0));
g.DrawPath(&pen, &path);
// Clipping
g.SetClip(®ion);
// Display text
FontFamily fontFamily(L"Arial");
Font font(&fontFamily, 36, FontStyleBold, UnitPixel);
SolidBrush brush(Color(255, 255, 0, 0));
g.DrawString(L"Clipping", 20, &font, PointF(15, 25), &brush);
}
GDI+ text display
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
CRect rect;
GetClientRect(rect);
WCHAR string[] = L"Hi, I'm a man who used XT long time ago";
/*
enum FontStyle
{
FontStyleRegular = 0,
FontStyleBold = 1,
FontStyleItalic = 2,
FontStyleBoldItalic = 3,
FontStyleUnderline = 4,
FontStyleStrikeout = 8
};
enum Unit
{
UnitWorld, // 0 -- World coordinate (non-physical unit)
UnitDisplay, // 1 -- Variable -- for PageTransform only
UnitPixel, // 2 -- Each unit is one device pixel.
UnitPoint, // 3 -- Each unit is a printer's point, or 1/72 inch.
UnitInch, // 4 -- Each unit is 1 inch.
UnitDocument, // 5 -- Each unit is 1/300 inch.
UnitMillimeter // 6 -- Each unit is 1 millimeter.
};
*/
// Create font
FontFamily fontFamily(L"Arial");
Font font(&fontFamily, 24, FontStyleBold, UnitPixel);
// Create brush
SolidBrush brush(Color(255, 0, 0, 255));
// Center alignment
StringFormat stringFormat;
stringFormat.SetAlignment(StringAlignmentCenter);
stringFormat.SetLineAlignment(StringAlignmentCenter);
// Display text in the middle of the window
PointF pointF(rect.Width()/2, rect.Height()/2);
g.DrawString(string, (INT)wcslen(string), &font, pointF, &stringFormat, &brush);
// Adjust display quality
g.SetTextRenderingHint(TextRenderingHintClearTypeGridFit);
// Display text int the middle of the rectangle
RectF rectF(300, 20, 200, 100);
g.DrawString(string, (INT)wcslen(string), &font, rectF, &stringFormat, &brush);
Pen pen(Color(255, 255, 0, 0));
g.DrawRectangle(&pen, rectF);
}
GDI+ draw image
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
// Read image file, *.bmp, *.gif, *.png, *.jpg format supported
Image image(L"test.jpg");
int width = image.GetWidth();
int height = image.GetHeight();
// Display image
g.DrawImage(&image, 10, 10, width, height);
// Display distorted image
Point points[] = {
Point(250, 20), Point(150, 100), Point(300, 50)
};
g.DrawImage(&image, points, 3);
// Magnified display
g.SetInterpolationMode(InterpolationModeNearestNeighbor);
g.DrawImage(&image, 10, 150, width*2, width*2);
g.SetInterpolationMode(InterpolationModeHighQualityBilinear);
g.DrawImage(&image, 220, 150, width*2, width*2);
}
GDI+ paint with pattern brush
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
for ( int i = 0; i < HatchStyleTotal; i++ ) {
HatchBrush brush((Gdiplus::HatchStyle)i,
Color(255, 0, 0, 0), Color(255, 255, 255, 0));
g.FillRectangle(&brush, 20+(i%7)*90, 20+(i/7)*60, 80, 50);
}
}
GDI+ paint with gradient brush
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
LinearGradientBrush linearBrush(Point(50, 100), Point(250, 200), Color(255, 255 , 0, 0), Color(255, 0, 0, 255));
g.FillRectangle(&linearBrush, 50, 100, 200, 100);
GraphicsPath path;
path.AddEllipse(300, 100, 200, 100);
int count = 1;
PathGradientBrush pathBrush(&path);
pathBrush.SetCenterColor(Color(255, 255, 0, 0));
pathBrush.SetSurroundColors(&Color(255, 255, 255, 0), &count);
g.FillEllipse(&pathBrush, 300, 100, 200, 100);
}
GDI+ paint with brush(alpha blending)
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
SolidBrush brush(Color(128, 255, 0, 0));
g.FillRectangle(&brush, 50, 100, 200, 100);
brush.SetColor(Color(128, 0, 255, 0));
g.FillEllipse(&brush, 150, 150, 200, 100);
brush.SetColor(Color(128, 255, 255, 0));
g.FillPie(&brush, 50, 130, 200, 200, 135, 90);
brush.SetColor(Color(128, 0, 0, 255));
Point points[] = {
Point(80, 50), Point(170, 70), Point(220, 30),
Point(200, 110), Point(150, 90), Point(100, 150)
};
/*
enum FillMode
{
FillModeAlternate, // 0
FillModeWinding // 1
};
*/
g.FillClosedCurve(&brush, points, 6, FillModeAlternate, 1);
}
GDI+ line pattern
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
Pen pen(Color(255, 0, 0, 0), 3);
/*
enum DashStyle
{
DashStyleSolid, // 0
DashStyleDash, // 1
DashStyleDot, // 2
DashStyleDashDot, // 3
DashStyleDashDotDot, // 4
DashStyleCustom // 5
};
*/
// 실선
pen.SetDashStyle(DashStyleSolid);
g.DrawLine(&pen, 50, 50, 400, 50);
// 파선
pen.SetDashStyle(DashStyleDash);
g.DrawLine(&pen, 50, 100, 400, 100);
// 점선
pen.SetDashStyle(DashStyleDot);
g.DrawLine(&pen, 50, 150, 400, 150);
// 일점 쇄선
pen.SetDashStyle(DashStyleDashDot);
g.DrawLine(&pen, 50, 200, 400, 200);
// 이점 쇄선
pen.SetDashStyle(DashStyleDashDotDot);
g.DrawLine(&pen, 50, 250, 400, 250);
// 시작점을 5 픽셀 이동
pen.SetDashOffset(5);
g.DrawLine(&pen, 50, 260, 400, 260);
// 사용자 정의 패턴
REAL dashVals[4] = { 5, 1, 2, 1 };
pen.SetDashPattern(dashVals, 4);
g.DrawLine(&pen, 50, 310, 400, 310);
}
GDI+ line cap shape/join shape
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
Pen capPen(Color(255, 0, 0, 0), 5);
/*
enum LineCap
{
LineCapFlat = 0,
LineCapSquare = 1,
LineCapRound = 2,
LineCapTriangle = 3,
LineCapNoAnchor = 0x10, // corresponds to flat cap
LineCapSquareAnchor = 0x11, // corresponds to square cap
LineCapRoundAnchor = 0x12, // corresponds to round cap
LineCapDiamondAnchor = 0x13, // corresponds to triangle cap
LineCapArrowAnchor = 0x14, // no correspondence
LineCapCustom = 0xff, // custom cap
LineCapAnchorMask = 0xf0 // mask to check for anchor or not.
};
*/
// Line
capPen.SetStartCap(LineCapSquare);
capPen.SetEndCap(LineCapRound);
g.DrawLine(&capPen, 50, 50, 400, 50);
capPen.SetStartCap(LineCapTriangle);
capPen.SetEndCap(LineCapNoAnchor);
g.DrawLine(&capPen, 50, 100, 400, 100);
capPen.SetStartCap(LineCapSquareAnchor);
capPen.SetEndCap(LineCapRoundAnchor);
g.DrawLine(&capPen, 50, 150, 400, 150);
capPen.SetStartCap(LineCapDiamondAnchor);
capPen.SetEndCap(LineCapArrowAnchor);
g.DrawLine(&capPen, 50, 200, 400, 200);
/*
enum LineJoin
{
LineJoinMiter = 0,
LineJoinBevel = 1,
LineJoinRound = 2,
LineJoinMiterClipped = 3
};
*/
// Set line join style
Pen joinPen(Color(255, 0, 0, 0), 10);
joinPen.SetLineJoin(LineJoinBevel);
g.DrawRectangle(&joinPen, 50, 250, 100, 100);
joinPen.SetLineJoin(LineJoinMiter);
g.DrawRectangle(&joinPen, 180, 250, 100, 100);
joinPen.SetLineJoin(LineJoinRound);
g.DrawRectangle(&joinPen, 310, 250, 100, 100);
}
GDI+ Pen thickness/alignment
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
Pen blackPen(Color(255, 0, 0, 0), 1);
Pen greenPen(Color(255, 0, 255, 0), 10);
/*
!!! Only PenAlignmentCenter & PenAlignmentInset are defined
typedef enum {
PenAlignmentCenter = 0,
PenAlignmentInset = 1
} PenAlignment;
*/
// Draw line
/*
greenPen.SetAlignment(PenAlignmentLeft);
g.DrawLine(&greenPen, 50, 200, 200, 50);
g.DrawLine(&blackPen, 50, 200, 200, 50);
*/
greenPen.SetAlignment(PenAlignmentCenter);
g.DrawLine(&greenPen, 150, 200, 300, 50);
g.DrawLine(&blackPen, 150, 200, 300, 50);
/*
greenPen.SetAlignment(PenAlignmentRight);
g.DrawLine(&greenPen, 250, 200, 400, 50);
g.DrawLine(&blackPen, 250, 200, 400, 50);
*/
// Draw rectangle(closed curve
greenPen.SetAlignment(PenAlignmentInset);
g.DrawRectangle(&greenPen, 50, 250, 100, 100);
g.DrawRectangle(&blackPen, 50, 250, 100, 100);
greenPen.SetAlignment(PenAlignmentCenter);
g.DrawRectangle(&greenPen, 180, 250, 100, 100);
g.DrawRectangle(&blackPen, 180, 250, 100, 100);
/*
greenPen.SetAlignment(PenAlignmentOutset);
g.DrawRectangle(&greenPen, 310, 250, 100, 100);
g.DrawRectangle(&blackPen, 310, 250, 100, 100);
*/
}
GDI+ line/polygon/curve
먼저 GDI+ 를 사용하기 위한 기본 설정은
For the proper use of GDI+ refer
Using GDI+ in VS.NET 2005
를 참조한다.
1. Lines
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
Pen pen(Color(255, 0, 0, 0), 3); // Pen with thickness = 3
g.DrawLine(&pen, 50, 50, 500, 50);
g.DrawRectangle(&pen, 50, 100, 200, 100);
g.DrawEllipse(&pen, 300, 100, 200, 100);
g.DrawPie(&pen, 50, 250, 200, 200, 225, 90);
g.DrawArc(&pen, 300, 250, 200, 200, 225, 90);
}
2. Polygon and curves
void CGdiplusDemoView::OnDraw(CDC* pDC)
{
Graphics g(pDC->m_hDC);
Pen pen(Color(255, 0, 0, 0), 3);
// Set coordinates
Point points[] = {
Point(30, 30), Point(120, 50), Point(170, 10), Point(150, 90), Point(90, 70), Point(50, 130)
};
// Polygon
g.DrawPolygon(&pen, points, 6);
// Closed curve
for ( int i = 0; i < 6; i++ )
points[i].X += 200;
g.DrawClosedCurve(&pen, points, 6, 0.5f);
// Closed curve
for ( int i = 0; i < 6; i++ )
points[i].X += 200;
g.DrawClosedCurve(&pen, points, 6, 1);
// Opened curve
for ( int i = 0; i < 6; i++ ) {
points[i].X -= 400;
points[i].Y += 150;
}
g.DrawCurve(&pen, points, 6, 0);
// Opened curve
for ( int i = 0; i < 6; i++ )
points[i].X += 200;
g.DrawCurve(&pen, points, 6, 0.5);
// Opend curve
for ( int i = 0; i < 6; i++ )
points[i].X += 200;
g.DrawCurve(&pen, points, 6, 1);
}
2007년 4월 5일 목요일
MFC Collection Class
MFC Collection Class
Non-Template Version
Template Version
사용자 정의 클래스를 템플릿 컬렉션에 저장하기 위해서는
To store user-created class in the template collection
생성자 함수를 구현
implement constructor function
== 오버로딩
overload == operator
해야 한다.
CStringArray = CArray
CMapStringToString = CMap
템플릿 버전의 첫 번째는 데이타형을 두 번째는 전달되는 인자의 형을 의미한다.
The first type in the template denotes data type while sencond denotes type of parameter-passed
CArray
strings.Add("First");
strings.Add("Second");
2007년 4월 4일 수요일
VS.NET 에서 Build Number 자동 증가 (1)
빌드 넘버 자동 증가
Build number automatic increasement
VS 6.0 이용자들은 다음 링크 사용
For VS 6.0 users
http://www.support.microsoft.com/default.aspx?scid=kb;en-us;237870
VS.NET 2003, 2005 이용자들은 여기 적힌대로 적용한다.
현재 몇몇 매크로들이 제대로 작동을 하지 않아서 직접 약간 수정을 했다.
기본적인 방법은 대부분 같다. MFC 프로젝트를 기준으로 설명한다.
For VS.NET 2003, 2005 users, you just need to follow the explaination below.
프로젝트명은 MyProject라고 했다고 가정한다.
Let us assume the project name as MyProject.
MFC 프로젝트로 생성했다면 프로젝트 폴더에 MyProject.rc 와 \res 폴더에
MyProject.rc2 라는 파일을 연다. 그냥 Win32 Application으로 생성했다면
다른 MFC 프로젝트 폴더에서 \res 폴더를 그대로 카피해와서 MyProject.rc2
파일만 남기고 모두 지운다.(파일명을 바꾸어야 할 것이다.)
If you create MFC project, open up the MyProject.rc and
\res\MyProject.rc2 files. If you create Win32 Application project,
just copy the \res\xxxx.rc2 file from another MFC project folder and
rename it.
MyProject.rc 파일에서 다음 부분을 cut 한다.
Cut next section from MyProject.rc
////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
.
.
.
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
Win32App 프로젝트라면 MyProject.rc 파일에 다음 부분을 추가해야 한다.
Add next line if your project is Win32App.
...
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"#include ""res\\ProjectName.rc2"" // <------- Here
"\0"
END
...
MyProject.rc2 파일의 다음 위치에 paste 한다.
Paste the copied text in the MyProject.rc2.
...
////////////////////////////////////////////////////////
// Add manually edited resources here...
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
//
// Version
//
#include "VersionNo.h" // <------- Here
VS_VERSION_INFO VERSIONINFO
FILEVERSION FILEVER // <------- Here
PRODUCTVERSION PRODUCTVER // <------- Here
FILEFLAGSMASK 0x3fL
...
BEGIN
VALUE "FileDescription", "MyProject Application"
VALUE "FileVersion", STRFILEVER
// <------- Here
VALUE "InternalName", "MyProject"
VALUE "LegalCopyright", "Copyright (C) 2003"
VALUE "OriginalFilename", "MyProject.exe"
VALUE "ProductName", " MyProjectApplication"
VALUE "ProductVersion", STRPRODUCTVER
// <------- Here
END
...
VersionNo.h 라는 파일을 만들고 다음과 같은 내용으로 채운다. 일단 여기에
있는 내용을 그대로 옮기기 바란다.
Create a VersionNo.h file and copy and paste next 4 lines.
#define FILEVER 1,0,0,1
#define PRODUCTVER 1,0,0,1
#define STRFILEVER "1, 0, 0, 1"
#define STRPRODUCTVER "1, 0, 0, 1"
Tools->Macros->New Macro Project 를 실행한다.
Select Tools->Macros->New Macro Project
Macro Explorer 창이 나타날 것이다. "+" 키를 누르면 기본적으로 "Module1"
이라는 마크로가 있을 것이다. 이것을 원하는 이름으로 변경한다.
그것을 더블클릭하면 Macro IDE가 나타날 것이다.
It will open up "Macro Explorer" window. Press "+" in the macro project
and it displays "Module1". You can rename it to whatever you want.
Double click the module to open Macro IDE.
에디터 창에 있는 모든 내용을 지우고 다음으로 채워 넣는다.
Delete all existing code and copy and paste next code.
======= FROM NEXT ================================================
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Public Module IncreaseBuildNo
Function GetProjectDir(ByVal FullName)
Dim proj_path
proj_path = Split(StrReverse(FullName), "\", -1, 1)
Dim count
count = UBound(proj_path)
Dim full_path
full_path = ""
Dim i
For i = 1 To count
full_path = full_path & "\" & proj_path(i)
Next
GetProjectDir = StrReverse(full_path)
End Function
Sub ReplaceText(ByVal objSel As TextSelection, ByVal count As Integer, ByVal incrementby As Integer, ByVal Type As Integer)
'selection represents the TextSelection object
'count represents the position of the version number
'to be incremented
'incrementally represents a number that will be added
'to the existing version number
Dim strTemp As String
Dim i
strTemp = ""
objSel.EndOfLine()
If Type = 0 Then
For i = 1 To count
If strTemp.StartsWith(",") = True Then
Exit For
Else
objSel.CharLeft(True, 1)
strTemp = objSel.Text
End If
Next
strTemp = strTemp.Remove(0, 1)
strTemp = strTemp + incrementby
objSel.Text = "," & strTemp
Else
For i = 1 To count
If strTemp.StartsWith(" ") = True Then
Exit For
Else
objSel.CharLeft(True, 1)
strTemp = objSel.Text
End If
Next
strTemp = strTemp.Remove(0, 1)
strTemp = strTemp.Remove(strTemp.Length - 1, 1)
strTemp = strTemp + incrementby
objSel.Text = " " & strTemp & """"
End If
End Sub
Dim WithEvents bldevents As BuildEvents
Dim applicationObject As EnvDTE.DTE
Sub BuildDoneEvents()
Dim addInInstance As EnvDTE.AddIn
applicationObject = CType(Application, EnvDTE.DTE)
bldevents = CType(applicationObject.Events. _
BuildEvents, EnvDTE.BuildEvents)
End Sub
Private Sub bldevents_OnBuildDone(ByVal _
Scope As EnvDTE.vsBuildScope, _
ByVal Action As EnvDTE. _
vsBuildAction) Handles _
bldevents.OnBuildDone
'This event will be triggered after every build
'of a project
'Obtain the full path of the active project
Dim full_path
full_path = GetProjectDir(DTE.ActiveDocument.Path)
full_path = full_path & "VersionNo.h"
'Open the VersionNo.h file
Dim doc As Document
DTE.ItemOperations.OpenFile(full_path)
Dim objDoc As TextDocument
'Obtain the TextSelection object
objDoc = DTE.ActiveDocument.Object("TextDocument")
Dim objSel As TextSelection = _
DTE.ActiveDocument.Selection
objSel.StartOfDocument()
'Increment the version information
ReplaceText(objSel, 5, 1, 0)
objSel.LineDown()
objSel.StartOfLine()
ReplaceText(objSel, 5, 1, 0)
objSel.LineDown()
objSel.StartOfLine()
ReplaceText(objSel, 7, 1, 100)
objSel.LineDown()
objSel.StartOfLine()
ReplaceText(objSel, 7, 1, 100)
ActiveDocument.Save()
ActiveDocument.Close()
End Sub
End Module
======= TO HERE ==========================================
매크로를 저장하고 VS.NET으로 돌아 와서 Macro Explorer 에서 해당 모듈을
오른클릭해서 "Run" 을 선택해서 실행시킨다.
Save the macro and in the VS.NET, in the "Macro Explorer",
right-click it and choose "Run".
따라 하기만 하면 빌드할 때마다 VersionNo.h 파일의 Build 번호가 자동으로
증가할 것이다.
If nothing wrong, you can see the build number is increased after the build.
MFC 메시지를 이용한 통신
메시지를 이용한 통신
메시지를 보내는 데는 다음과 같이 두 가지 방법이 있다.
- SendMessage 함수를 이용하는 방법
- PostMessage 함수를 이용하는 방법
CWnd::SendMessage 함수
SendMessage 함수는 윈도우에 메시지를 보내는 함수로서 다음과 같이 정의되어 있다.
LRESULT SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);
이 함수는 매개변수로 메시지의 종류와 추가적인 정보를 담기 위한 wParam, lParam을
인자로 넣어 주도록 되어 있다. 또, 이 함수는 CWnd 클래스의 멤버 함수라는 점에
주목하자. CFrameWnd 클래스에서 SendMessage 함수를 호출하면 프레임 윈도우로
메시지가 날아가고 CView 클래스에서 SendMessage 함수를 호출하면 뷰 윈도우로
메시지가 날아 가게 된다.
그러나 CWnd 클래스에서 상속받지 않은 CWinApp 클래스나 CDocument 파생 클래스에
서는 SendMessage 함수를 호출할 수 없다. 만약 메인 프레임 클래스 밖에서 메인
프레임 윈도우로 메시지를 보내고 싶으면 다음과 같이 하면 된다.
AfxGetMainWnd()->SendMessage(..., ..., ...);
SendMessage 함수를 이용하여 어떤 윈도우에 WM_MOUSEMOVE 메시지를 보내면 마우스를
움직이지 않고도 마우스가 움직일 때 수행되는 동작을 하도록 할 수 있고 WM_KEYDOWN
메시지를 보내면 키보드를 누르지 않고도 키보드가 눌린 것처럼 동작을 시킬 수가
있다.
또한 메인 프레임 윈도우로 WM_COMMAND 메시지를 보내면 메뉴를 선택하지 않고도
메뉴가 선택됐을 때 하는 동작을 수행하도록 할 수 있다.
예를 들면,
AfxGetMainWnd()->SendMessage(WM_COMMAND, ID_FILE_OPEN);
이라고 메시지를 보내주면 프로그램은 사용자가 메뉴에서 파일 열기 항목을 선택했을
때와 똑같은 동작을 수행하게 된다.
CWnd::PostMessage 함수
SendMessage 함수와 비슷하게 메시지를 보내는 기능을 하는 함수로 PostMessage 함수가
있다.
BOOL PostMessage(UINT message, WPARAM wParam = 0, LPARAM = lParam = 0);
이 함수와 SendMessage 함수의 차이점은 메시지 큐를 거치느냐 아니냐 하는 것이다.
SendMessage 함수를 이용하여 메시지를 보내면 메시지가 메시지 큐를 거치지 않고
직접 메시지 처리기를 호출한다. 따라서, SendMessage 함수를 호출함과 동시에
해당하는 메시지 처리기가 호출된다.
반면 PostMessage 함수는 메시지를 메시지 큐에 넣어 주는 일만 한다. 따라서
PostMessage 함수를 이용하여 메시지를 보내주면 현재 수행되고 있는 함수가
완전히 끝나고, 메시지 큐에 쌓여 있던 메시지들의 처리기가 다 수행되고 난
후에야 PostMessage 함수로 보낸 메시지의 처리기가 호출된다.
MFC의 뼈대를 이루는 클래스들의 상호 참조
프로그램의 뼈대를 이루는 클래스들 간의 상호 참조
1. CWinApp 참조
AfxGetApp 함수는 CWinApp 파생클래스의 인스턴스 포인터를 반환해 준다.
CWinApp* AfxGetApp();
2. 메인 프레임 윈도우 참조
AfxGetMainWnd 함수는 메인 프레임 클래스의 인스턴스 포인터를 반환해 준다.
CWnd* AfxGetMainWnd();
3. 뷰에서 프레임 윈도우/다큐먼트 참조
뷰에서 다큐먼트 참조
CDocument* CView::GetDocument() const;
GetDocument()는 CView 클래스의 멤버 함수이다.
4. 뷰에서 자식 프레임 윈도우 참조
뷰 클래스에서 그 뷰를 둘러싸고 있는 프레임 윈도우를 참조하려면 GetParentFrame 함수를 사용한다.
프레임 윈도우는 비단 뷰뿐 아니라, 일반적인 윈도우를 둘러싸는 틀로써 사용될 수 있기 때문에
GetParentFrame 함수는 CWnd 클래스의 멤버 함수로 되어 있다. 물론 CView에서도 사용할 수 있다.
CFrameWnd* CWnd::GetParaentFrame() const;
단일 다큐먼트 프로그램에서는 메인 프레임 윈도우를 얻는 AfxGetMainWnd 함수와 GetParentFrame
함수의 반환값이 같다. 그러나 다중 다큐먼트 프로그램에서는 메인 프레임 윈도우의 포인터를
반환하는 AfxGetMainWnd 함수와 자식 프레임 윈도우의 포인터를 반환하는 GetParentFrame 함수가
서로 구별된다.
5. 다큐먼트에서 뷰/프레임 윈도우 참조
다큐먼트에서 뷰 참조
다큐먼트에서 뷰의 포인터를 얻으려면 GetFirstViewPosition 함수와 GetNextView 함수를 조합하여
사용하여야 한다. 다큐먼트에서 뷰를 참조하는 것이 함수 하나로 안되고 복잡해지는 이유는
하나의 다큐먼트에 여러 개의 뷰가 결합될 수 있기 때문이다.
다큐먼트에는 이와 연결된 뷰가 리스트로 관리되고 있다. GetFirstViewPosition 함수를 호출하면
첫 번째 뷰가 매달려 있는 포인터가 얻어지고 GetNextView를 반복 호출하면 다음 뷰들이 차례로
얻어진다. 다음은 다큐먼트와 연결된 모든 뷰 클래스를 차례로 얻어 뷰 클래스의 멤버 함수인
UpdateWindow 함수를 호출하는 예이다.
void CMyDoc::OnRepaintAllViews() {
POSITION pos = GetFirstViewPosition();
while ( pos != NULL ) {
CView* pView = GetNextView(pos);
pView->UpdateWindow();
}
}
다큐먼트에 뷰가 오직 하나만 연결되어 있는 경우에는 다음과 같이 간단하게 뷰 클래스의 인스턴스
포인터를 얻어낼 수 있다. m_viewList는 CDocument 클래스의 멤버 변수로서 뷰를 관리하는 리스트이다.
이것을 이용하여 GetHead 함수를 호출하면 리스트에 들어 있는 첫 번째 뷰가 얻어진다.
void CMyDoc::OnRepaintViews() {
CView* pView = m_viewList.GetHead();
pView->UpdateWindow();
}
다큐먼트에서 프레임 윈도우 참조
다큐먼트에서 프레임 윈도우를 직접 참조하는 일은 없다. 단일 다큐먼트 프로그램의 경우에는 그냥
AfxGetMainWnd 함수를 호출하면 되지만 다중 다큐먼트 프로그램의 경우에는 먼저 다큐먼트의
뷰를 얻고 그 뷰에서 자신을 포함하는 프레임 윈도우를 얻는 단계를 밟아야 한다.
6. 프레임 윈도우에서 뷰 참조
프레임 윈도우에서 뷰를 참조하려면 GetActiveView 함수를 사용한다.
CView* CFrameWnd::GetActiveView() const;
하나의 프레임 윈도우에는 분할 윈도우를 이용하여 두 개 이상의 뷰가 들어갈 수 있다.
GetActiveView 함수는 현재 프레임 윈도우와 연결된 뷰 중 활성화 된 것의 포인를 반환한다.
7. 프레임 윈도우에서 다큐먼트 참조
프레임 윈도우 클래스에서 다큐먼트 클래스를 참조하려면 GetActiveDocument 함수를 사용한다.
virtual CDocument* CFrameWnd::GetActiveDocument();
이 함수는 현재 프레임 윈도우와 연결된 다큐먼트 중 활성화 된 것의 포인터를 반환한다.
8. 다큐먼트 템플릿에서 다큐먼트/뷰/자식 프레임 윈도우 참조
다중 다큐먼트 프로그램에는 여러 개의 다큐먼트/뷰/자식 프레임 윈도우가 있을 수 있으며
다큐먼트 템플릿을 이용하면 이들 모두 하나하나 참조가 가능하다.
같은 타입의 클래스의 인스턴스가 두 개 이상 존재하는 것들은 모두 연결 리스트로
이루어져 있습니다. 연결 리스트에 매달려 있는 노드를 참조하는 함수는 모두 다음과 같은
형식으로 되어 있다.
POSITION pos = GetFirstXXXPosition();
while ( pos != NULL )
XXX xx = (XXX *)GetNextXXX( pos );
즉, 첫 번째 노드의 위치를 알려면 GetFirstXXXPosition 함수를 호출하면 되고, GetNextXXX
함수를 반복 호출함으로써 다음 노드를 참조할 수 있다.
다큐먼트 템플릿 얻기
예를 들어 CWinApp 클래스에 CMultiDocTemplate 이 두 개 매달려 있을 때, 두 번째
CMultiDoc 의 인스턴스를 얻고 싶으면 먼저 GetFirstDocTemplatePosition 함수를 호출하여
첫 번째 노드의 포인터를 얻은 후 GetNextDocTemplate 함수를 두 번 반복 호출하면 된다.
POSITION CWinApp::GetFirstDocTemplatePosition();
CDocTemplate* CWinApp::GetNextDocTemplate(POSITION& pos);
이 함수들이 모두 CWinApp 클래스의 멤버 함수이며 GetNextDocTemplate 함수의 반환값은
CDocTemplate 의 포인터이다.
다큐먼트 얻기
같은 방법으로 CMultiDocTemplate 클래스에 CDocument가 두 개 매달려 있을 때, 두 번째
CDocument의 인스턴스를 얻고 싶으면 먼저 GetFirstDocPosition 함수를 호출하여 첫 번째
노드의 포인터를 얻은 후 GetNextDoc 함수를 두 번 반복 호출하면 된다.
virtual POSITION CDocTemplate::GetFirstDocPosition();
virtual CDocument* CDocTemplate::GetNextDoc(POSITION& rPos);
이 함수들은 모두 CDocTemplate 클래스의 멤버함수이며 GetNextDoc 함수의 반환 값은
CDocument의 포인터이다.
뷰 얻기
역시 마찬가지 방법으로 CDocument 클래스에 CView가 두 개 매달려 있을 때 두 번째
CView의 인스턴스를 얻고 싶으면 먼저 GetFirstViewPosition 함수를 호출하여 첫 번째
노드의 포인터를 얻은 후 GetNextView 함수를 두 번 반복 호출하면 된다.
virtual POSITION CDocument::GetFirstViewPosition();
virtual CView* CDocument::GetNextView(POSITION& rPosition);
이 함수들은 모두 CDocument 클래스의 멤버 함수이며 GetNextView 함수의 반환 값은
CView의 포인터이다.
사용 예
예를 들어, 현재 프로그램에 존재하는 모든 뷰의 포인터를 얻어내고 Invalidate 함수를
호출하여 모든 뷰의 화면이 다시 그려지도록 하기 위해서는
void CMyClass::OnUpdateAllViews() {
CWinApp *pApp = AfxGetApp();
POSITION posTemplate = pApp->GetFirstDocTemplatePosition();
while ( posTemplate ) {
CDocTemplate* pTemplate = pApp->GetNextDocTemplate(posTemplate);
POSITION posDoc = pTemplate->GetFirstDocPosition();
while ( posDoc ) {
CDocument* pDoc = pTemplate->GetNextDoc(posDoc);
POSITION posView = pDoc->GetFirstViewPosition();
while ( posView ) {
CView* pView = pDoc->GetNextView(posView);
pView->Invalidate();
}
}
}
}
와 같이 하면 된다.