윈도우의 일반적인 세가지 특징
1. 윈도우는 화면상에 존재한다
메모리상에만 내부적으로 존재하는 것이 아니라 화면상에 나타나며 사용자의 눈에 보인다
숨겨지거나 가려지거나 일시적으로 가시 영역을 벗어나는 경우가 없지는 않지만 이 경우에도 당장 보이지 않을 뿐 여전히 화면 상에 있다
2. 그 모양은 반드시 직사각형이다
즉, 화면상의 좌상단 좌표를 가지고 높이 와 폭이 있으며 각 변끼리는 수직을 이룬다
둥근 모양이나 세모 모양의 윈도우도 만들 수 있지만 이 경우도 나머지 부분이 투명할 뿐이지 결국은 직사각형이다
3. 윈도우는 독립적으로 사용자와 상호작용을 할 수 있다
실행 결과를 화면에 출력하기도 하고 사용자로부터 입력을 받기도 한다
사용자로부터 명령을 처리하여 다시 화면으로 출력을 내보내거나 다른 윈도우로 재 입력을 보내기도 한다
윈도우가 상호작용을 한다는 말은 단순히 존재하기만 하는 것이 아니라 능동적인 동작을 한다는 얘기며 문법적으로 하자면 사용자로부터 또는 시스템으로부터 입력된 명령과 신호를 처리하는 메시지 처리 능력이 있다는 뜻이다
* 컨트롤
- 사용자와의 인터페이스를 이루는 도구
- 인터페이스를 이룬다는 말은 사용자로부터 명령과 입력을 받아들이고 출력결과를 보여준다
- 컨트롤은 입출력도구
- 프로그램은 실행 중에 끊임없이 사용자와 통신
- 컨트롤에 명령과 정보를 받아들이고 또한 컨트롤을 통해 실행 결과를 사용자에게 보고
- 버튼, 에디트, 리스트 박스, 콤보 박스, 스크롤 바, 스태틱
- 컨트롤도 하나의 윈도우
- 화면의 일정한 영역을 차지
- 자신의 고유 메시지를 처리할 수 있는 능력
- 메모장이나 탐색기 같은 진짜 윈도우처럼 타이틀 바나 경계선을 가지고 독립적으로 사용되는 것은 아님
- 보통 대화상자의 차일드 윈도우로 존재
- 윈도우를 만들 때는 WNDCLASS 형의 구조체를 정의하고 RegisterClass 함수로 등록한 후 CreateWindow 함수를 호출
- 그러나 컨트롤은 윈도우즈가 운영체제 차원에서 제공하기 때문에 윈도우 클래스를 등록할 필요 없이 미리 등록되어 있는 윈도우 클래스를 사용하기만 하면 된다
* DC (Device Context)
- 출력에 필요한 모든 정보를 가지는 데이터 구조체
* DC를 얻는 방법
1. GetDC() 를 사용하여 DC를 얻고 사용 후 ReleaseDC() 로 해제
- DC는 주로 하나의 윈도우와 연관되는 출력 정보를 가진다
- 그래서 인수로 어떤 윈도우에 대한 DC가 필요한가를 알려주어야 함
- GetDC() 는 hWnd가 가리키는 윈도우에 적당한 DC를 만들어 그 핸들을 리턴
- DC도 메모리를 차지하므로 할당 후 해제 원칙이 반드시 준수
HDC hdc = GetDC(hWnd);
각종 출력
ReleaseDC(hWnd, hdc);
2. 두 번째 얻는 방법은 WM_PAINT 메시지 루틴에서만 사용 가능
- BeginPaint()로 얻으며 핸들을 해제할 때는 EndPaint() 함수 사용
- PAINTSTRUCT 형의 구조체를 지역 변수로 선언하고 다음과 같이 사용
PAINTSTRUCT paintStruct;
HDC hdc;
WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
각종 출력
EndPaint(hWnd, &ps);
- PAINTSTRUCT 에는 그리기 속도를 비약적으로 향상시킬 수 있는 정보들이 있음
- 이 정보를 활용하는 방법에 대해서는 다음에 자세하게 배울 것
CKMSceneDataSeries *pSeries = g_Doc.m_pSceneData->GetDefaultSeries();
CKMVolume *pVol = pSeries->m_pVolume;
short *pVolData = (short*)(pVol->GetDataSource());
int nDim[3] = {pVol->m_nDim[0], pVol->m_nDim[1], pVol->m_nDim[2]};
m_fPixelSpacing[0] = (float)(pVol->m_fSpacing[0]);
m_fPixelSpacing[1] = (float)(pVol->m_fSpacing[1]);
m_fPixelSpacing[2] = (float)(pVol->m_fSpacing[2]);
m_volumeData->data.setValue(SbVec3i32(dimension), SbDataType(SbDataType::SIGNED_SHORT), 0, pData, SoSFArray::COPY);
m_volumeData->extent.setValue(-(spacing[0] * dimension[0])/2, -(spacing[1] * dimension[1])/2, -(spacing[2] * dimension[2])/2,
(spacing[0] * dimension[0])/2, (spacing[1] * dimension[1])/2, (spacing[2] * dimension[2])/2);
SbVec3i32 dimension = pVolumeData->data.getSize();
/*SoVolumeData* volumeData = new SoVolumeData();
short* rawData = (short*)m_pSceneData->GetDefaultSeries()->m_pVolume->GetDataSource();
int dimension[3] = { m_pVolume->m_nDim[0], m_pVolume->m_nDim[1], m_pVolume->m_nDim[2] };
float spacing[3] = { m_pVolume->m_fSpacing[0], m_pVolume->m_fSpacing[1], m_pVolume->m_fSpacing[2] };
volumeData->data.setValue(SbVec3i32(dimension), SbDataType(SbDataType::SIGNED_SHORT), 0, rawData, SoSFArray::COPY);
volumeData->extent.setValue(-(spacing[0] * dimension[0])/2, -(spacing[1] * dimension[1])/2, -(spacing[2] * dimension[2])/2,
( spacing[0] * dimension[0])/2, (spacing[1] * dimension[1])/2, (spacing[2] * dimension[2])/2);
m_pRootSeparator->addChild(volumeData);*/
#define SO_MOUSE_PRESS_EVENT(EVENT,BUTTON) \
(SoMouseButtonEvent::isButtonPressEvent(EVENT,SoMouseButtonEvent::BUTTON))
#define SO_MOUSE_RELEASE_EVENT(EVENT,BUTTON) \
(SoMouseButtonEvent::isButtonReleaseEvent(EVENT,SoMouseButtonEvent::BUTTON))