1. 이벤트 시스템 큐
이벤트가 발생하면 이를 시스템 메시지 큐로 전달
전달된 메시지는 각 응용 프로그램 메시지 큐로 할당되는데,
이 때 이미 실행중인 응용 프로그램 메시지 큐에 각 적용시킨다.
계산기는 입력이 없으면 변화가 없기에, 메시지 큐가 비어있는 것 볼 수 있다.
뮤직 플레이어는 노래가 나와야 하기에 다른 응용 프로그램이 맨 위에 있어도 처리가 된다.
메모장의 경우는 입력을 현재 하고 있으므로 메시지 큐에 적용되어 처리되는 걸 볼 수 있다.
2. 멀티테스킹과 멀티스레딩
멀티태스킹: 운영체제가 여러 개의 응용 프로그램을 동시에 실행하는 것
멀티스레딩: 응용 프로그램 내부에서 여러 개의 실행 흐름(=스레드)을 동시에 진행하는 것
3. SDK 프로그램 개발환경
WM_CREATE : CreateWindow() 함수 호출
WM_LBUTTONDOWN : 클라이언트 영역에서 마우스 왼쪽 버튼을 누를 때
WM_PAINT : 클라이언트 영역에서 일부 또는 전체를 다시 그릴 필요가 있을 때
WM_DESTROY : 종료 버튼을 눌렀을 때
4. 디바이스 컨텍스트(DC, Device Context)
- GDI가 생성하고 관리하는 데이터 구조체
- 멀티태스킹 GUI 환경에서 발생할 수 있는 복잡한 상황들을 신경쓰지 않고 장치에 자유롭게 출력 가능
5. 무효 영역에서 WM_PAINT 메시지 발생 상황
- 윈도우가 생성될 때
- 윈도우의 크기가 변경될 때
- 윈도우가 최소화, 최대화 되었을 때
6. 명령어 - 8. 기본 입출력에서 중복됨
7. 펜, 브러쉬 그리기
CPen pen(PS_SOLID, 2, RGB(255, 0, 0)); // 폭이 2인 빨간색 펜
CPen* oldPen = pDC->SelectObject(&pen); // 펜 선택, 이전 펜 저장
pDC->Rectangle(100, 100, 200, 200); // 직사각형 그리기.
pDC->SelectObject(oldPen); // 이전 펜 복원
CBrush brush = brush.CreateSolidBrush(RGB(255, 0, 0)); // 빨간색 브러쉬
CBrush *oldBrush = pDC->SelectObject(&brush); // 브러쉬 선택, 이전 브러쉬 저장
pDC->Rectangle(100, 100, 200, 200); // 직사각형 그리기
pDC->SelectObject(oldBrush);
brush.DeleteObject();
8. 기본 입출력
pDC->Rectangle(100, 100, 200, 200); // 도형 출력
pDC->Ellipse(100, 100, 200, 200);
pDC->RoundRect(100, 100, 200, 200, 20, 20);
TextOut(100, 100 ,_T("Hello World")); // 텍스트 출력
CRect rect; // {left:100, right:100, top:200, bottom:200}
pDC->DrawText(_T("Hello World"), &rect, DT_CENTER | DT_VCENTER);
MoveTo(100, 100); // 100, 100 좌표로 이동
LineTo(200, 200); // 200, 200 좌표로 이동하면서 선 그리기
--------------------
View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { // 키보드 처리
if (nChar == VK_BACK) // Back 키 클릭 시
m_str.Delete(m_str.GetLength() - 1); // 내용 한 개씩 지우기
else
m_str.AppendChar(nChar); // 입력하기
Invalidate(); // 화면 동기화
CView::OnChar(nChar, nRepCnt, nFlags);
}
View::OnDraw(CDC* pDC) {
pDC->TextOutW(0, 0, m_str, m_str.GetLength());
}
--------------------
--------------------
View::OnLButtonDown(UINT nFlags, CPoint point) { // 마우스 클릭
m_ptStart = point;
CView::OnLButtonDown(nFlags, point);
}
View::OnMouseMove(UINT nFlags, CPoint point) { // 마우스 이동
if (nFlags & MK_LBUTTON) // 왼쪽 버튼 누르면
{
m_ptEnd = point;
Invalidate();
}
CView::OnMouseMove(nFlags, point);
}
View::OnLButtonUp(UINT nFlags, CPoint point) {
m_ptEnd = point;
Invalidate();
CView::OnLButtonUp(nFlags, point);
}
--------------------
SetROP2(int nDrawMode); // 래스터 연산
계산 방법: NOTXOR
흰색 = 11111111 11111111 11111111 (255, 255, 255)
빨간색 = 11111111 00000000 00000000 (255, 0, 0)
===================================
빨간색 = 11111111 00000000 00000000 (255, 0, 0)
9. 타이머
View::OnLButtonDown() {
SetTimer(1, 700, NULL);
SetTimer(2, 1000, &CProjectView::TimerProc);
CView::OnLButtonDown();
}
View::OnTimer(UINT nIDEvent) {
// 0.7초마다 수행
CView::OnTimer(nIDEvent);
}
CALLBACK CProjectView::
TimerProc (HWND hWnd, UINT nMsg, UINT_PRT nIDEvent, DWORD dwTime) {
// 1초 마다 수행
}
KillTimer(1); // 1번 타이머 정지
KillTimer(2); // 2번 타이머 정지
10. 비트맵
1. 비트맵을 읽어온다
2. LoadBitmap() 함수로 CBitmap 객체에 비트맵을 로드한다.
3. SelectObject() 함수로 사용할 비트맵을 memDC에서 선택한다.
4. memDC에 있는 비트맵을 BitBlt() 를 통해 전송하고, CreateCompatibleDC()로 반환한다.
5. pDC에서 화면으로 비트맵을 출력한다.
11. BitBlt, StretchBlt로 비트맵 화면에 띄우기
BitBlt(
int nXD, // 화면 출력 x 위치 number X Display
int nYD, // 화면 출력 y 위치 number Y Display
int nW, // 출력 너비 사이즈 number Width
int nH, // 출력 높이 사이즈 number Height
CDC memDC, // 이미지 사진 memory Device Context
int nXS, // 이미지 x 위치 number X Start
int nYS, // 이미지 y 위치 number Y Start
DWORD dwRop // SRCCOPY, SRCAND, SRCPAINT
);
StretchBlt(
int nXD, // 화면 출력 x 위치 | number X Display
int nYD, // 화면 출력 y 위치 | number Y Display
int nW, // 출력 너비 사이즈 | number Width
int nH, // 출력 높이 사이즈 | number Height
CDC memDC, // 이미지 사진 | memory Device Context
int nXS, // 이미지 x 위치 | number X Start
int nYS, // 이미지 y 위치 | number Y Start
int nWS, // 이미지 너비 사이즈 | number Width Size
int nHS, // 이미지 높이 사이즈 | number Height Size
DWORD dwRop // SRCCOPY, SRCAND, SRCPAINT
);
12. 더블 버퍼링
더블 버퍼링 없이 화면을 띄우면 기존에 있던 화면을 먼저 지우고, 하나씩 하나씩 그리게 된다.
하지만, 더블 버퍼링을 띄우면, 기존의 화면에서 새로운 화면(오프 스크린)을 새로 만들어,
모든 화면을 다 그려낸 후 기존 화면에 옮겨 그리는 방식이다.
CDC mdc; // DC 생성
CBitmap s_bit, l_bit, *oldbit;
mdc.CreateCompatibleDC(pDC); // 새 DC 생성
s_bit.LoadBitmap(IDB_BITMAP1); // 비트맵1 로드
l_bit.LoadBitmap(IDB_BITMAP2); // 비트맵2 로드
oldbit = mdc.SelectObject(&s_bit); // 비트맵1 선택
pDC->BitBlt(0, 0, 48, 48, &mdc, 0, 0, SRCCOPY); // 비트맵1 띄우기
mdc.SelectObject(&l_bit); // 비트맵2 선택
pDC->BitBlt(60, 0, 546, 331, &mdc, 0, 0, SRCCOPY); // 비트맵2 뜨위기
mdc.SelectObject(oldbit);
mdc.DeleteDC();
13. 옵션
- SRCAND: AND 연산자를 사용하여 대상 비트 맵과 소스 비트맵의 픽셀을 결합
- SRCCOPY: 소스 비트 맵을 대상 비트 맵에 복사
- SRCPAINT: OR 연산자를 사용하여 대상 비트맵과 소스 비트 맵의 픽셀을 결합
14. Document
데이터만 따로 관리하는 파일이라고 일단 이해함.
이를 통해 파일을 저장해서 값을 보관하고 있다 가 View로 불러올 수도 있다.
15. 데이터 View - Docu 교환
// View의 OnDraw 에서 Doc 선언을 통해 값을 불러올 수 있다.
MyDoc* pDoc = GetDocument(); // Doc 선언
for (int i = 0; i < pDoc->m_nCount; i++) {
pDC->Ellipse(pDoc->m_ptData[i].x - 10,
pDoc->m_ptData[i].y - 10,
pDoc->m_ptData[i].x + 10,
pDoc->m_ptData[i].y + 10); // Doc에 있는 x, y 좌표 불러옴
pDC->MoveTo(pDoc->m_ptData[i].x - 10, pDoc->m_ptData[i].y - 10);
pDC->LineTo(pDoc->m_ptData[i].x + 10, pDoc->m_ptData[i].y + 10);
pDC->MoveTo(pDoc->m_ptData[i].x - 10, pDoc->m_ptData[i].y + 10);
pDC->LineTo(pDoc->m_ptData[i].x + 10, pDoc->m_ptData[i].y - 10);
}
// View에서 Docu로 값 교환하는건 선언을 반대로 하면 된다.
pDoc->m.ptData[i].y = 10;
16. 파일 저장/로딩
Doc::Serialize(CArchive& ar) {
if (ar.IsStoring()) {
// TODO: 여기에 저장 코드를 추가합니다.
ar << m_nCount;
for (int i = 0; i < m_nCount; i++) {
ar << m_ptData[i];
}
}
else {
// TODO: 여기에 로딩 코드를 추가합니다.
ar >> m_nCount;
for (int i = 0; i < m_nCount; i++) {
ar >> m_ptData[i];
}
}
}