반응형

프로그램내용 :  선분 그리기 + 대화상자 기반 UI


-------------------------------------------------------------------------------------------

평가 :

- 사용자가 그린 선분들을 저장하고 다시 그린다(WM_PAINT처리) ---- C

- 대화상자의 콤보박스가 작동한다. ---- B

- 대화상자의 스크롤바가 작동한다.      ---- B+

- 대화상자의 미리보기완성           ---- A

#include <windows.h>
#include <tchar.h> //_ttoi
#include "resource.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("Mouse");

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
	, LPSTR lpszCmdParam, int nCmdShow)
{
	HWND hWnd;
	MSG Message;
	WNDCLASS WndClass;
	g_hInst = hInstance;

	WndClass.cbClsExtra = 0;
	WndClass.cbWndExtra = 0;
	WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	WndClass.hInstance = hInstance;
	WndClass.lpfnWndProc = WndProc;
	WndClass.lpszClassName = lpszClass;
	WndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
	WndClass.style = CS_HREDRAW | CS_VREDRAW;// | CS_DBLCLKS;
	RegisterClass(&WndClass);

	hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, (HMENU)NULL, hInstance, NULL);
	ShowWindow(hWnd, nCmdShow);

	while (GetMessage(&Message, NULL, 0, 0)) {
		TranslateMessage(&Message);
		DispatchMessage(&Message);
	}
	return (int)Message.wParam;
}
//선의 위치, 색, 굵기 저장

void PaintWindow(HWND hwnd, int iColor, int iWidth)//선을 그리는 함수
{

	HPEN		hpen;
	HDC         hdc;


	hdc = GetDC(hwnd);
	hpen = CreatePen(PS_SOLID, iWidth, iColor);
	hpen = (HPEN)SelectObject(hdc, hpen);
	MoveToEx(hdc, 10, 10, NULL);
	LineTo(hdc, 130, 10);
	DeleteObject(SelectObject(hdc, hpen));
	ReleaseDC(hwnd, hdc);
}

void PaintTheBlock(HWND hCtrl, int iColor, int iFigure)//선을 지우고 다시 그리는 함수
{
	InvalidateRect(hCtrl, NULL, TRUE); // Dialog box의 윈도우 프로스져인 AboutDlgProc이 아니라 
	UpdateWindow(hCtrl);               // static control의 숨겨진 WndProc으로 WM_PAINT 전달
	PaintWindow(hCtrl, iColor, iFigure);
}
typedef struct _line {
	POINT p[2];
	COLORREF pColor;
	int pWidth;
} line;

line lines[1000];
int iLines;
int sx, sy, oldx, oldy;
COLORREF iCurrentPenColor = RGB(0, 0, 255);
int iCurrentPenWidth = 8;
TCHAR* Items[] = { TEXT("Red"), TEXT("Green"), TEXT("Blue") };//콤보박스에 넣을 문자열
HWND hCombo, hWidth, hPaint;//윈도우 호출 시 사용 핸들 

//대화상자

BOOL CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	int j;
	static COLORREF iColor;
	static int iWidth;
	switch (iMessage) {
	case WM_INITDIALOG:
		iColor = iCurrentPenColor;//iColor의 값은 iCorrentColor의 
		iWidth = iCurrentPenWidth;
		//자식 윈도우를 사용할 수 있는 핸들 지정
		hPaint = GetDlgItem(hDlg, IDC_STATIC2);
		SetFocus(GetDlgItem(hDlg, iColor));//현재 iColor의 색을 포커스 함
		hCombo = GetDlgItem(hDlg, IDC_COMBO1);
		hWidth = GetDlgItem(hDlg, IDC_SCROLLBAR1);
		//스크롤 바의 범위, 초기 스크롤바 커서 위치
		SetScrollRange(hWidth, SB_CTL, 0, 20, TRUE);
		SetScrollPos(hWidth, SB_CTL, iCurrentPenWidth, TRUE);
		//콤보 박스에 문자열 넣기
		for (int i = 0; i < 3; i++) {
			SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)Items[i]);
		}
		if (iCurrentPenColor == RGB(0, 0, 255))
			SetDlgItemText(hDlg, IDC_COMBO1, TEXT("Blue"));
		if (iCurrentPenColor == RGB(255, 0, 0))
			SetDlgItemText(hDlg, IDC_COMBO1, TEXT("Red"));
		if (iCurrentPenColor == RGB(0, 255, 0))
			SetDlgItemText(hDlg, IDC_COMBO1, TEXT("Green"));
		SetDlgItemInt(hDlg, IDC_STATIC1, iWidth, FALSE);

		return TRUE;
	case WM_HSCROLL:
		iWidth = GetScrollPos((HWND)lParam, SB_CTL);

		switch (LOWORD(wParam)) {//자식
		case SB_LINELEFT://임시저장된값에서
			iWidth = max(0, iWidth - 1); //최소제어 0 
			break;
		case SB_LINERIGHT:
			iWidth = min(20, iWidth + 1);//최대제어 255
			break;
		case SB_PAGELEFT://스크롤의 오른쪽빈바
			iWidth = max(0, iWidth - 5);
			break;
		case SB_PAGERIGHT:
			iWidth = min(20, iWidth + 5);
			break;
		case SB_THUMBTRACK://끌었을때
			iWidth = HIWORD(wParam);//임지시저장 값은 커서 현재위치
			break;
		}
		
		SetScrollPos((HWND)lParam, SB_CTL, iWidth, TRUE);
		SetDlgItemInt(hDlg, IDC_STATIC1, iWidth, NULL);
		iCurrentPenWidth = iWidth;
		PaintTheBlock(hPaint, iColor, iWidth);
		return TRUE;
	case WM_COMMAND://부모(대화상자)
		switch (LOWORD(wParam)) {
		case IDOK://자식(OK버튼)
			iCurrentPenColor = iColor;
			EndDialog(hDlg, IDOK);
			return TRUE;
		case IDCANCEL://자식(취소)
			EndDialog(hDlg, IDCANCEL);
			return TRUE;
		case IDC_COMBO1:
			switch (HIWORD(wParam))
			{
			case CBN_SELCHANGE:
				j = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
				if (j == 0)
				{
					iColor = RGB(255, 0, 0);
				}
				if (j == 1)
				{
					iColor = RGB(0, 255, 0);
				}
				if (j == 2)
				{
					iColor = RGB(0, 0, 255);
				}
				PaintTheBlock(hPaint, iColor, iWidth);
				break;
			}
			return TRUE;



		}
	case WM_PAINT:
		InvalidateRect(hDlg, NULL, TRUE);
		PaintTheBlock(hPaint, iColor, iWidth);

		break;
	}
	return FALSE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{

	static BOOL bNowDraw = FALSE;
	HPEN hPen;
	HDC hdc;
	PAINTSTRUCT ps;
	switch (iMessage) {
	case WM_CREATE:
		return 0;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDM_MENU:
			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DlgProc);
			break;
		}
		return 0;
	case WM_LBUTTONDOWN:
		lines[iLines].pColor = iCurrentPenColor;
		lines[iLines].pWidth = iCurrentPenWidth;
		sx = LOWORD(lParam);
		sy = HIWORD(lParam);
		oldx = sx;
		oldy = sy;
		lines[iLines].p[0].x = sx;
		lines[iLines].p[0].y = sy;
		bNowDraw = TRUE;
		return 0;
	case WM_MOUSEMOVE:
		if (bNowDraw) {
			hdc = GetDC(hWnd);
			SetROP2(hdc, R2_NOTXORPEN);
			hPen = CreatePen(PS_SOLID, iCurrentPenWidth, iCurrentPenColor);
			hPen = (HPEN)SelectObject(hdc, hPen);
			MoveToEx(hdc, sx, sy, NULL);
			LineTo(hdc, oldx, oldy);
			oldx = LOWORD(lParam);
			oldy = HIWORD(lParam);
			MoveToEx(hdc, sx, sy, NULL);
			LineTo(hdc, oldx, oldy);
			ReleaseDC(hWnd, hdc);
		}
		return 0;
	case WM_LBUTTONUP:
		bNowDraw = FALSE;
		hdc = GetDC(hWnd);
		hPen = CreatePen(PS_SOLID, iCurrentPenWidth, iCurrentPenColor);
		hPen = (HPEN)SelectObject(hdc, hPen);
		MoveToEx(hdc, sx, sy, NULL);
		LineTo(hdc, oldx, oldy);
		lines[iLines].p[1].x = oldx;
		lines[iLines].p[1].y = oldy;
		iLines++;
		ReleaseDC(hWnd, hdc);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		for (int i = 0; i < iLines; i++)
		{
			hPen = CreatePen(PS_SOLID, lines[i].pWidth, lines[i].pColor);
			hPen = (HPEN)SelectObject(hdc, hPen);
			MoveToEx(hdc, lines[i].p[0].x, lines[i].p[0].y, NULL);
			LineTo(hdc, lines[i].p[1].x, lines[i].p[1].y);
		}
		EndPaint(hWnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

전역변수

typedef struct _line {
	POINT p[2];
	COLORREF pColor;
	int pWidth;
} line;

line lines[1000];
int iLines;
int sx, sy, oldx, oldy;
COLORREF iCurrentPenColor = RGB(0, 0, 255);
int iCurrentPenWidth = 8;
TCHAR* Items[] = { TEXT("Red"), TEXT("Green"), TEXT("Blue") };//콤보박스에 넣을 문자열
HWND hCombo, hWidth, hPaint;//윈도우 호출 시 사용 핸들 

line 구조체

  • POINT p[2]는 선의 시작점과 끝점을 저장
  • pColor는 선마다의 색을 저장
  • pWidth는 선마다의 넓이를 저장

iLines는 선의 갯수를 저장

  • sx, sy, oldx, oldy는 시작 선, 최종 선 좌표 저장

  • iCPC 선 색 저장

  • iCPW 선 굵기 저장

  • Items 콤보박스에 넣을 문자열

  • 핸들 컨트롤 호출 핸들asd

메인 윈도우

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{

	static BOOL bNowDraw = FALSE;
	HPEN hPen;
	HDC hdc;
	PAINTSTRUCT ps;
	switch (iMessage) {
	case WM_CREATE:
		return 0;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDM_MENU:
			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DlgProc);
			break;
		}
		return 0;
	case WM_LBUTTONDOWN:
		lines[iLines].pColor = iCurrentPenColor;
		lines[iLines].pWidth = iCurrentPenWidth;
		sx = LOWORD(lParam);
		sy = HIWORD(lParam);
		oldx = sx;
		oldy = sy;
		lines[iLines].p[0].x = sx;
		lines[iLines].p[0].y = sy;
		bNowDraw = TRUE;
		return 0;
	case WM_MOUSEMOVE:
		if (bNowDraw) {
			hdc = GetDC(hWnd);
			SetROP2(hdc, R2_NOTXORPEN);
			hPen = CreatePen(PS_SOLID, iCurrentPenWidth, iCurrentPenColor);
			hPen = (HPEN)SelectObject(hdc, hPen);
			MoveToEx(hdc, sx, sy, NULL);
			LineTo(hdc, oldx, oldy);
			oldx = LOWORD(lParam);
			oldy = HIWORD(lParam);
			MoveToEx(hdc, sx, sy, NULL);
			LineTo(hdc, oldx, oldy);
			//ReleaseDC(hWnd, hdc);
		}
		return 0;
	case WM_LBUTTONUP:
		bNowDraw = FALSE;
		//hdc = GetDC(hWnd);
		hPen = CreatePen(PS_SOLID, iCurrentPenWidth, iCurrentPenColor);
		hPen = (HPEN)SelectObject(hdc, hPen);
		MoveToEx(hdc, sx, sy, NULL);
		LineTo(hdc, oldx, oldy);
		lines[iLines].p[1].x = oldx;
		lines[iLines].p[1].y = oldy;
		iLines++;
		ReleaseDC(hWnd, hdc);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		for (int i = 0; i < iLines; i++)
		{
			hPen = CreatePen(PS_SOLID, lines[i].pWidth, lines[i].pColor);
			hPen = (HPEN)SelectObject(hdc, hPen);
			MoveToEx(hdc, lines[i].p[0].x, lines[i].p[0].y, NULL);
			LineTo(hdc, lines[i].p[1].x, lines[i].p[1].y);
		}
		EndPaint(hWnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

메인 윈도우 지역변수

static BOOL bNowDraw = FALSE;
	HPEN hPen;
	HDC hdc;
	PAINTSTRUCT ps;

bNowDraw 마우스 선택 누르는 상태인지 저장하는 bool변수

  • 그리기 도구(펜)
  • 그리기 도구통
  • 그리는 도화지

WM_COMMAND

case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDM_MENU:
			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DlgProc);
			break;
		}
		return 0;

WM_COMMAND //부모윈도우(메인윈도우)에게 명령보내기

  • 메인윈도우에 IDM_MENU를 누르면 DialogBox를 여는 메시지를 보낸다.

WM_LBUTTONDOWN

case WM_LBUTTONDOWN:
		lines[iLines].pColor = iCurrentPenColor;
		lines[iLines].pWidth = iCurrentPenWidth;
		sx = LOWORD(lParam);
		sy = HIWORD(lParam);
		oldx = sx;
		oldy = sy;
		lines[iLines].p[0].x = sx;
		lines[iLines].p[0].y = sy;
		bNowDraw = TRUE;
		return 0;

WM_LBUTTONDOWN (iLine=0)

  • lines[0].pColor 전역변수에 현재의 색상값과 굵기값을 저장한다.
  • 클릭한 순간 x, y, oldx, oldy좌표를 저장
  • lines[0].p[0].x 전역변수에 시작하는 지점이 좌표를 저장
  • 왼쪽버튼을 누르고 있다는 신호를 주는 bNW를 변환

WM_MOUSEMOVE

case WM_MOUSEMOVE:
		if (bNowDraw) {
			hdc = GetDC(hWnd);
			SetROP2(hdc, R2_NOTXORPEN);
			hPen = CreatePen(PS_SOLID, iCurrentPenWidth, iCurrentPenColor);
			hPen = (HPEN)SelectObject(hdc, hPen);
			MoveToEx(hdc, sx, sy, NULL);//선지우기
			LineTo(hdc, oldx, oldy);
			oldx = LOWORD(lParam);
			oldy = HIWORD(lParam);
			MoveToEx(hdc, sx, sy, NULL);//선그리기
			LineTo(hdc, oldx, oldy);
			ReleaseDC(hWnd, hdc);
		}
		return 0;

 왼쪽버튼이 누르고있다면(bND=T)

  • SetROP2(hdc, R2_NOTXORPEN) 배경과 그리기도구 일치확인 게이트

WM_LBUTTONUP

case WM_LBUTTONUP:
		bNowDraw = FALSE;
		hdc = GetDC(hWnd);
		hPen = CreatePen(PS_SOLID, iCurrentPenWidth, iCurrentPenColor);
		hPen = (HPEN)SelectObject(hdc, hPen);
		MoveToEx(hdc, sx, sy, NULL);
		LineTo(hdc, oldx, oldy);
		lines[iLines].p[1].x = oldx;
		lines[iLines].p[1].y = oldy;
		iLines++;
		ReleaseDC(hWnd, hdc);
		return 0;

왼쪽 버튼 클릭을 그만하면 

  • 누르고 있다는 신호인 bND를 F로
  • 선분을 그리고 lines[0]배열에 x y좌표를 저장
  • 선의 다음값을 지정해주기 위해 iLines++

WM_PAINT

case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		for (int i = 0; i < iLines; i++)
		{
			hPen = CreatePen(PS_SOLID, lines[i].pWidth, lines[i].pColor);
			hPen = (HPEN)SelectObject(hdc, hPen);
			MoveToEx(hdc, lines[i].p[0].x, lines[i].p[0].y, NULL);
			LineTo(hdc, lines[i].p[1].x, lines[i].p[1].y);
		}
		EndPaint(hWnd, &ps);
		return 0;

무효영역이 발생했을때

  • lines[]배열에 저장되어있는 선을 iLines의 갯수만큼 다시 그려준다.

대화상자 콜백 함수

BOOL CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	int j;
	static COLORREF iColor;
	static int iWidth;
	switch (iMessage) {
	case WM_INITDIALOG:
		iColor = iCurrentPenColor;//iColor의 값은 iCorrentColor의 
		iWidth = iCurrentPenWidth;
		//자식 윈도우를 사용할 수 있는 핸들 지정
		hPaint = GetDlgItem(hDlg, IDC_STATIC2);
		SetFocus(GetDlgItem(hDlg, iColor));//현재 iColor의 색을 포커스 함
		hCombo = GetDlgItem(hDlg, IDC_COMBO1);
		hWidth = GetDlgItem(hDlg, IDC_SCROLLBAR1);
		//스크롤 바의 범위, 초기 스크롤바 커서 위치
		SetScrollRange(hWidth, SB_CTL, 0, 20, TRUE);
		SetScrollPos(hWidth, SB_CTL, iCurrentPenWidth, TRUE);
		//콤보 박스에 문자열 넣기
		for (int i = 0; i < 3; i++) {
			SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)Items[i]);
		}
		if (iCurrentPenColor == RGB(0, 0, 255))
			SetDlgItemText(hDlg, IDC_COMBO1, TEXT("Blue"));
		if (iCurrentPenColor == RGB(255, 0, 0))
			SetDlgItemText(hDlg, IDC_COMBO1, TEXT("Red"));
		if (iCurrentPenColor == RGB(0, 255, 0))
			SetDlgItemText(hDlg, IDC_COMBO1, TEXT("Green"));
		SetDlgItemInt(hDlg, IDC_STATIC1, iWidth, FALSE);

		return TRUE;
	case WM_HSCROLL:
		TempPos = GetScrollPos((HWND)lParam, SB_CTL);

		switch (LOWORD(wParam)) {//자식
		case SB_LINELEFT://임시저장된값에서
			TempPos = max(0, iWidth - 1); //최소제어 0 
			break;
		case SB_LINERIGHT:
			TempPos = min(20, iWidth + 1);//최대제어 255
			break;
		case SB_PAGELEFT://스크롤의 오른쪽빈바
			TempPos = max(0, iWidth - 5);
			break;
		case SB_PAGERIGHT:
			TempPos = min(20, iWidth + 5);
			break;
		case SB_THUMBTRACK://끌었을때
			TempPos = HIWORD(wParam);//임지시저장 값은 커서 현재위치
			break;
		}
		if ((HWND)lParam == hWidth) iWidth = TempPos;
		SetScrollPos((HWND)lParam, SB_CTL, iWidth, TRUE);
		SetDlgItemInt(hDlg, IDC_STATIC1, iWidth, NULL);
		iCurrentPenWidth = iWidth;
		PaintTheBlock(hPaint, iColor, iWidth);
		return TRUE;
	case WM_COMMAND://부모(대화상자)
		switch (LOWORD(wParam)) {
		case IDOK://자식(OK버튼)
			iCurrentPenColor = iColor;
			EndDialog(hDlg, IDOK);
			return TRUE;
		case IDCANCEL://자식(취소)
			EndDialog(hDlg, IDCANCEL);
			return TRUE;
		case IDC_COMBO1:
			switch (HIWORD(wParam))
			{
			case CBN_SELCHANGE:
				j = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
				if (j == 0)
				{
					iColor = RGB(255, 0, 0);
				}
				if (j == 1)
				{
					iColor = RGB(0, 255, 0);
				}
				if (j == 2)
				{
					iColor = RGB(0, 0, 255);
				}
				PaintTheBlock(hPaint, iColor, iWidth);
				break;
			}
			return TRUE;



		}
	case WM_PAINT:
		InvalidateRect(hDlg, NULL, TRUE);
		PaintTheBlock(hPaint, iColor, iWidth);

		break;
	}
	return FALSE;
}

대화상자 지역변수

	int j;
	static COLORREF iColor;
	static int iWidth;
  • 콤보박스 인덱스 값 j
  • 색상 값 iColor / 굵기 저장 iWidth

대화상자_INITDIALOG

switch (iMessage) {
	case WM_INITDIALOG:
		iColor = iCurrentPenColor;//iColor의 값은 iCorrentColor의 
		iWidth = iCurrentPenWidth;
		//자식 윈도우를 사용할 수 있는 핸들 지정
		hPaint = GetDlgItem(hDlg, IDC_STATIC2);
		hCombo = GetDlgItem(hDlg, IDC_COMBO1);
		hWidth = GetDlgItem(hDlg, IDC_SCROLLBAR1);
		//스크롤 바의 범위, 초기 스크롤바 커서 위치
		SetScrollRange(hWidth, SB_CTL, 0, 20, TRUE);
		SetScrollPos(hWidth, SB_CTL, iCurrentPenWidth, TRUE);
		//콤보 박스에 문자열 넣기
		for (int i = 0; i < 3; i++) {
			SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)Items[i]);
		}
		if (iCurrentPenColor == RGB(0, 0, 255))
			SetDlgItemText(hDlg, IDC_COMBO1, TEXT("Blue"));
		if (iCurrentPenColor == RGB(255, 0, 0))
			SetDlgItemText(hDlg, IDC_COMBO1, TEXT("Red"));
		if (iCurrentPenColor == RGB(0, 255, 0))
			SetDlgItemText(hDlg, IDC_COMBO1, TEXT("Green"));
		SetDlgItemInt(hDlg, IDC_STATIC1, iWidth, FALSE);

		return TRUE;

대화상자를 열었을때

  • iColor, iWidth의 초기값 설정
  • 대화상자의 컨트롤 핸들들 지정
  • 스크롤바의 초기 위치 지정
  • 콤보 박스에 문자열 넣기
  • if(iCPC==RGB)는 iCPC의 값에 따라 콤보박스에 표시할 텍스트를 알려줌
  • SetDlgItemInt(hDlg, IDC_STATIC1, iWidth, FALSE) iWidth에 값을 IDC_STATIC1에 표기

대화상자_HSCROLL

case WM_HSCROLL:
		switch (LOWORD(wParam)) {//자식
		case SB_LINELEFT://임시저장된값에서
			iWidth = max(0, iWidth - 1); //최소제어 0 
			break;
		case SB_LINERIGHT:
			iWidth = min(20, iWidth + 1);//최대제어 255
			break;
		case SB_PAGELEFT://스크롤의 오른쪽빈바
			iWidth = max(0, iWidth - 5);
			break;
		case SB_PAGERIGHT:
			iWidth = min(20, iWidth + 5);
			break;
		case SB_THUMBTRACK://끌었을때
			iWidth = HIWORD(wParam);//임지시저장 값은 커서 현재위치
			break;
		}
		
		SetScrollPos((HWND)lParam, SB_CTL, iWidth, TRUE);
		SetDlgItemInt(hDlg, IDC_STATIC1, iWidth, NULL);
		PaintTheBlock(hPaint, iColor, iWidth);
		return TRUE;

스크롤이 움직일때마다 

  • iWidth의 값을 변경해주고
  • STATIC1의 값을 iWidth의 값으로 변경해준다.
  • 전역변수 iCPW의 값을 iWidth의 값으로 변경해준다.
  • PaintTheBlock 함수를 호출한다. (미리보기 그리는 함수)

대화상자_COMMAND

	case WM_COMMAND://부모(대화상자)
		switch (LOWORD(wParam)) {
		case IDOK://자식(OK버튼)
			iCurrentPenColor = iColor;
            iCurrentPenWidth = iWidth;
			EndDialog(hDlg, IDOK);
			return TRUE;
		case IDCANCEL://자식(취소)
			EndDialog(hDlg, IDCANCEL);
			return TRUE;
		case IDC_COMBO1:
			switch (HIWORD(wParam))
			{
			case CBN_SELCHANGE:
				j = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
				if (j == 0)
				{
					iColor = RGB(255, 0, 0);
				}
				if (j == 1)
				{
					iColor = RGB(0, 255, 0);
				}
				if (j == 2)
				{
					iColor = RGB(0, 0, 255);
				}
				PaintTheBlock(hPaint, iColor, iWidth);
				break;
			}
			return TRUE;
		}

부모 윈도우(대화상자)에게 자식 윈도우(OK, CANCEL, COMBO BOX)가 명령을 전달

  • ok를 눌러야 지역변수의 값이 전역변수로 넘어감
  • 취소를 누르면 지역변수의 값이 전역변수로 넘어가지 않는다
  • 콤보 박스를 눌렀을때\
  •   - 콤보박스가 또 어떤 이벤트(셀 선택변경)를 발생시키면
  •      -변경 시 j에 선택한 인덱스 값을 전달
  •      -if(j == 0) 선택된 인덱스 값이 0이면 레드
  • 미리보기 함수 호출
case WM_PAINT:
		InvalidateRect(hDlg, NULL, TRUE);
		PaintTheBlock(hPaint, iColor, iWidth);
		break;
  • 무효영역에 들어갔을 때 다시 그리기
  • 대화상자 전체를 지우고 다시 그림
  • 미리보기 함수 호출

미리보기 함수

void PaintTheBlock(HWND hCtrl, int iColor, int iFigure)//선을 지우고 다시 그리는 함수
{
	InvalidateRect(hCtrl, NULL, TRUE); // Dialog box의 윈도우 프로스져인 AboutDlgProc이 아니라 
	UpdateWindow(hCtrl);               // static control의 숨겨진 WndProc으로 WM_PAINT 전달
	PaintWindow(hCtrl, iColor, iFigure);
}

InvalidateRect는 hCtrl=미리보기 컨트롤을 무효화 시킨다.  무효영역이 발생하면 항상 WM_PAINT메시지가 발생하므로 lnvalidateRect안에 WM_PAINT가 있다고 생각 할 수도 있지만 WM_PAINT메시지는 무효영역이 왔기때문에 실행될뿐이다. 

UpdataWindow함수를 사용하면 즉시 WM_PAINT메시지를 발생시킬 수 있다.

PaintWindow 함수 호출

PaintWindow 함수

void PaintWindow(HWND hwnd, int iColor, int iWidth)//선을 그리는 함수
{

	HPEN		hpen;
	HDC         hdc;


	hdc = GetDC(hwnd);
	hpen = CreatePen(PS_SOLID, iWidth, iColor);
	hpen = (HPEN)SelectObject(hdc, hpen);
	MoveToEx(hdc, 10, 10, NULL);
	LineTo(hdc, 130, 10);
	DeleteObject(SelectObject(hdc, hpen));
	ReleaseDC(hwnd, hdc);
}

선을 그리는 함수이다.

 

반응형
반응형

미리보기 예제

왼쪽 중단에 미리보기 화문을 출력하는 대화상자

소스코드

/*------------------------------------------
   ABOUT2.C -- About Box Demo Program No. 2
               (c) Charles Petzold, 1998
  ------------------------------------------*/

#include <windows.h>
#include "resource.h"

LRESULT CALLBACK WndProc      (HWND, UINT, WPARAM, LPARAM) ;
BOOL    CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ;
     
int iCurrentColor  = IDC_BLACK,//아이디를 바로씀 
    iCurrentFigure = IDC_RECT ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("About2") ;
     MSG          msg ;
     HWND         hwnd ;
     WNDCLASS     wndclass ;
     
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (hInstance, szAppName) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = szAppName ;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("About Box Demo Program"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ; 
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

void PaintWindow (HWND hwnd, int iColor, int iFigure)
{
     static COLORREF crColor[8] = { RGB (  0,   0, 0), RGB (  0,   0, 255),
                                    RGB (  0, 255, 0), RGB (  0, 255, 255),
                                    RGB (255,   0, 0), RGB (255,   0, 255),
                                    RGB (255, 255, 0), RGB (255, 255, 255) } ;

     HBRUSH          hBrush ;
     HDC             hdc ;
     RECT            rect ;
     
     hdc = GetDC (hwnd) ;
     GetClientRect (hwnd, &rect) ;//이 윈도우의 크기를 리턴 rect사격형 크기
     hBrush = CreateSolidBrush (crColor[iColor - IDC_BLACK]) ;//ID_BLACK의 값 1000 
     hBrush = (HBRUSH) SelectObject (hdc, hBrush) ;
     
     if (iFigure == IDC_RECT)
          Rectangle (hdc, rect.left, rect.top, rect.right, rect.bottom) ;
     else
          Ellipse   (hdc, rect.left, rect.top, rect.right, rect.bottom) ;
     
     DeleteObject (SelectObject (hdc, hBrush)) ;
     ReleaseDC (hwnd, hdc) ;
}

void PaintTheBlock (HWND hCtrl, int iColor, int iFigure)
{
     InvalidateRect (hCtrl, NULL, TRUE) ; // Dialog box의 윈도우 프로스져인 AboutDlgProc이 아니라 
	 UpdateWindow (hCtrl) ;               // static control의 숨겨진 WndProc으로 WM_PAINT 전달
     PaintWindow (hCtrl, iColor, iFigure) ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static HINSTANCE hInstance ;
     PAINTSTRUCT      ps ;
     
     switch (message)
     {
     case WM_CREATE:
          hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
          return 0 ;
          
     case WM_COMMAND:
          switch (LOWORD (wParam))
          {
          case IDM_APP_ABOUT:
               if (DialogBox (hInstance, TEXT ("AboutBox"), hwnd, AboutDlgProc))
                    InvalidateRect (hwnd, NULL, TRUE) ;
               return 0 ;
          }
          break ;
          
     case WM_PAINT:
          BeginPaint (hwnd, &ps) ;
          EndPaint (hwnd, &ps) ;
               
          PaintWindow (hwnd, iCurrentColor, iCurrentFigure) ;
          return 0 ;
               
     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT message, 
                            WPARAM wParam, LPARAM lParam)
{
     static HWND hCtrlBlock ;
     static int  iColor, iFigure ;
     
     switch (message)
     {
     case WM_INITDIALOG:
          iColor  = iCurrentColor ;//iColor의 값은 iCorrentColor의 
          iFigure = iCurrentFigure ;
          
          CheckRadioButton (hDlg, IDC_BLACK, IDC_WHITE,   iColor) ;
          CheckRadioButton (hDlg, IDC_RECT,  IDC_ELLIPSE, iFigure) ;
          
          hCtrlBlock = GetDlgItem (hDlg, IDC_PAINT) ;//hCB는 IDC_PAINT의 핸들
          
          SetFocus (GetDlgItem (hDlg, iColor)) ;//현재 iColor의 색을 포커스 함
          return FALSE ;
          
     case WM_COMMAND:
          switch (LOWORD (wParam))
          {
          case IDOK:
               iCurrentColor  = iColor ;
               iCurrentFigure = iFigure ;
               EndDialog (hDlg, TRUE) ;
               return TRUE ;
               
          case IDCANCEL:
               EndDialog (hDlg, FALSE) ;
               return TRUE ;
               
          case IDC_BLACK:
          case IDC_RED:
          case IDC_GREEN:
          case IDC_YELLOW:
          case IDC_BLUE:
          case IDC_MAGENTA:
          case IDC_CYAN:
          case IDC_WHITE:
               iColor = LOWORD (wParam) ;//방금 선택한 라디오박스에 iColor값이 들어감
               CheckRadioButton (hDlg, IDC_BLACK, IDC_WHITE, LOWORD (wParam)) ;
               PaintTheBlock (hCtrlBlock, iColor, iFigure) ;//미리보기창을 호출 (위치, 색, 모양)
               return TRUE ;
               
          case IDC_RECT:
          case IDC_ELLIPSE:
               iFigure = LOWORD (wParam) ;
               CheckRadioButton (hDlg, IDC_RECT, IDC_ELLIPSE, LOWORD (wParam)) ;
               PaintTheBlock (hCtrlBlock, iColor, iFigure) ;
               return TRUE ;
          }
          break ;
          
     case WM_PAINT:
          //대화상자가 최초 그려질 때, 대화상자를 다른 애플리케이션이 가렸을 때  
		  // return TRUE 가 없는 것에 유의. WM_PAINT는 결국 아래의 return FALSE로 간다.
		  PaintTheBlock (hCtrlBlock, iColor, iFigure) ;

          break ;
     }
     return FALSE ;
}

전역변수

LRESULT CALLBACK WndProc      (HWND, UINT, WPARAM, LPARAM) ;
BOOL    CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ;
     
int iCurrentColor  = IDC_BLACK,//아이디를 바로씀 
    iCurrentFigure = IDC_RECT ;

색상 초기 값과 초기 넓이를 가지는 변수

 

대화상자

BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT message, 
                            WPARAM wParam, LPARAM lParam)
{
     static HWND hCtrlBlock ;
     static int  iColor, iFigure ;
     
     switch (message)
     {
     case WM_INITDIALOG:
          iColor  = iCurrentColor ;//iColor의 값은 iCorrentColor의 
          iFigure = iCurrentFigure ;
          
          CheckRadioButton (hDlg, IDC_BLACK, IDC_WHITE,   iColor) ;
          CheckRadioButton (hDlg, IDC_RECT,  IDC_ELLIPSE, iFigure) ;
          
          hCtrlBlock = GetDlgItem (hDlg, IDC_PAINT) ;//hCB는 IDC_PAINT의 핸들
          
          SetFocus (GetDlgItem (hDlg, iColor)) ;//현재 iColor의 색을 포커스 함
          return FALSE ;
          
     case WM_COMMAND:
          switch (LOWORD (wParam))
          {
          case IDOK:
               iCurrentColor  = iColor ;
               iCurrentFigure = iFigure ;
               EndDialog (hDlg, TRUE) ;
               return TRUE ;
               
          case IDCANCEL:
               EndDialog (hDlg, FALSE) ;
               return TRUE ;
               
          case IDC_BLACK:
          case IDC_RED:
          case IDC_GREEN:
          case IDC_YELLOW:
          case IDC_BLUE:
          case IDC_MAGENTA:
          case IDC_CYAN:
          case IDC_WHITE:
               iColor = LOWORD (wParam) ;//방금 선택한 라디오박스에 iColor값이 들어감
               CheckRadioButton (hDlg, IDC_BLACK, IDC_WHITE, LOWORD (wParam)) ;
               PaintTheBlock (hCtrlBlock, iColor, iFigure) ;//미리보기창을 호출 (위치, 색, 모양)
               return TRUE ;
               
          case IDC_RECT:
          case IDC_ELLIPSE:
               iFigure = LOWORD (wParam) ;
               CheckRadioButton (hDlg, IDC_RECT, IDC_ELLIPSE, LOWORD (wParam)) ;
               PaintTheBlock (hCtrlBlock, iColor, iFigure) ;
               return TRUE ;
          }
          break ;
          
     case WM_PAINT:
          //대화상자가 최초 그려질 때, 대화상자를 다른 애플리케이션이 가렸을 때  
		  // return TRUE 가 없는 것에 유의. WM_PAINT는 결국 아래의 return FALSE로 간다.
		  PaintTheBlock (hCtrlBlock, iColor, iFigure) ;

          break ;
     }
     return FALSE ;
}

대화상자 지역변수

    static HWND hCtrlBlock ; //static 핸들 미리보기창을 그릴 
     static int  iColor, iFigure ;//대화상자안에서 색상, 도형을 저장할 공간

WM_INITDALOG

switch (message)
     {
     case WM_INITDIALOG:
          iColor  = iCurrentColor ;//iColor의 값은 iCorrentColor의 
          iFigure = iCurrentFigure ;
          
          CheckRadioButton (hDlg, IDC_BLACK, IDC_WHITE,   iColor) ;
          CheckRadioButton (hDlg, IDC_RECT,  IDC_ELLIPSE, iFigure) ;
          
          hCtrlBlock = GetDlgItem (hDlg, IDC_PAINT) ;//hCB는 IDC_PAINT의 핸들
          
          SetFocus (GetDlgItem (hDlg, iColor)) ;//현재 iColor의 색을 포커스 함
          return FALSE ;

대화상자 처음 시작 시

  • 대화상자 안에서의 컬러와 도형값을 전역변수 색상 도형으로 초기화
  • 체크박스라디오 버튼은 ID블랙~화이트 중에 iColor의 값으로 지정
  • 핸들에 미리보기 컨트롤을 지정해줌
  • GetDlgItem은 iColor안에 있는 ID을 hDlg가 가지고 그 값을 SetFocus 한다.
  • 이 줄을 주석처리하면 방향키를 눌러도 반응하지 않는다.  
case WM_COMMAND:
          switch (LOWORD (wParam))
          {
          case IDOK:
               iCurrentColor  = iColor ;
               iCurrentFigure = iFigure ;
               EndDialog (hDlg, TRUE) ;
               return TRUE ;
               
          case IDCANCEL:
               EndDialog (hDlg, FALSE) ;
               return TRUE ;
               
          case IDC_BLACK:
          case IDC_RED:
          case IDC_GREEN:
          case IDC_YELLOW:
          case IDC_BLUE:
          case IDC_MAGENTA:
          case IDC_CYAN:
          case IDC_WHITE:
               iColor = LOWORD (wParam) ;//방금 선택한 라디오박스에 iColor값이 들어감
               CheckRadioButton (hDlg, IDC_BLACK, IDC_WHITE, LOWORD (wParam)) ;
               PaintTheBlock (hCtrlBlock, iColor, iFigure) ;//미리보기창을 호출 (위치, 색, 모양)
               return TRUE ;
               
          case IDC_RECT:
          case IDC_ELLIPSE:
               iFigure = LOWORD (wParam) ;
               CheckRadioButton (hDlg, IDC_RECT, IDC_ELLIPSE, LOWORD (wParam)) ;
               PaintTheBlock (hCtrlBlock, iColor, iFigure) ;
               return TRUE ;
          }
          break ;

OK를 누르면

색상값 도형을 전역변수로 저장하고 Dialog를 종료한다.

CANCEL을 누르면 

그냥 종료

case IDC_BLACK~IDC_WHITE

  • 블랙부터 화이트 중에 이벤트를 클릭해서 발생시키면
  • iColor에 라디오 박스에 그 이벤트 값이 들어간다. ex) GREEN을 선택하면 1002를 wParam에 전달
  • CheckRadioButton 블랙~화이트까지 중에 wParam 값을 체크박스에서 선택 하도록함
  • hCtrlBlock에 iColor와 iFigure를 기반으로 미리보기창을 그리는 함수를 호출

체크박스 ID 정수 값

 

case lDC_RECT/IDC_ELLIPSE

  • iFigure에 선택한 값 저장
  • 체크박스에 선택한 값 체크하도록 보이게
  • hCtrlBlock에 iColor와 iFigure를 기반으로 미리보기창을 그리는 함수를 호출

 

WM_PAINT

  case WM_PAINT:
          //대화상자가 최초 그려질 때, 대화상자를 다른 애플리케이션이 가렸을 때  
		  // return TRUE 가 없는 것에 유의. WM_PAINT는 결국 아래의 return FALSE로 간다.
		  PaintTheBlock (hCtrlBlock, iColor, iFigure) ;

          break ;
          }//위에 switch문 닫아줌
          return FALSE ;//더 이상 보낼 메시지가 없다.
  • 대화상자가 최초 그려질 때, 대화상자를 다른 애플리케이션이 가렸을 때 미리보기 상자를 출력하기 위해
    return TRUE 가 없는 것에 유의.
  • WM_PAINT는 결국 아래의 return FALSE로 간다.

PaintTheBlock 함수

void PaintTheBlock (HWND hCtrl, int iColor, int iFigure)
{
     InvalidateRect (hCtrl, NULL, TRUE) ; // Dialog box의 윈도우 프로스져인 AboutDlgProc이 아니라 
	 UpdateWindow (hCtrl) ;               // static control의 숨겨진 WndProc으로 WM_PAINT 전달
     PaintWindow (hCtrl, iColor, iFigure) ;
}

위에서 호출한 PaintTheBlock은

  • lnvalidateRect는 화면을 최소화했다가 키는(무효화영역) 메시지를 보내는 효과가 있다. 이때 무효화영역에 들어가면 WM_PAINT메시지가 자동적으로 발생하는다.
  • UpdataWindow는 WM_PAINT메시지를 무시해준다.
  • PaintWindow 초기화한 색상으로 다시 그림그리기

PaintWindow

void PaintWindow (HWND hwnd, int iColor, int iFigure)
{
     static COLORREF crColor[8] = { RGB (  0,   0, 0), RGB (  0,   0, 255),
                                    RGB (  0, 255, 0), RGB (  0, 255, 255),
                                    RGB (255,   0, 0), RGB (255,   0, 255),
                                    RGB (255, 255, 0), RGB (255, 255, 255) } ;

     HBRUSH          hBrush ;
     HDC             hdc ;
     RECT            rect ;
     
     hdc = GetDC (hwnd) ;
     GetClientRect (hwnd, &rect) ;//이 윈도우의 크기를 리턴 rect사격형 크기
     hBrush = CreateSolidBrush (crColor[iColor - IDC_BLACK]) ;//ID_BLACK의 값 1000 
     hBrush = (HBRUSH) SelectObject (hdc, hBrush) ;
     
     if (iFigure == IDC_RECT)
          Rectangle (hdc, rect.left, rect.top, rect.right, rect.bottom) ;
     else
          Ellipse   (hdc, rect.left, rect.top, rect.right, rect.bottom) ;
     
     DeleteObject (SelectObject (hdc, hBrush)) ;
     ReleaseDC (hwnd, hdc) ;
}
  • static COLORREF crColor[8]은 RGB값을 저장하는 배열이다
  • GetClientRect 사격형의 크기를 미리보기 창만큼으로 설정
  • hBursh의 값은 case로 받아온 매개변수 iColor가 들어가기 때문에 만약.
  • IDC_WHITE를 선택했다면.WHITE인 정수값은 1007이다.
  • 1007-1000=7이기 때문에 브러쉬의 RGB값은 255, 255, 255를 가진다.
  • 그리기 도구 hdc가 색상브러쉬를 통에 넣는다
  • 만약 iFigure가 IDC_RECT의 값과 같다면
  • 사각형을 그린다.
  • 아니라면 
  • 원을 그린다
  • 브러쉬반납
  • 그리기 도구 반납
반응형
반응형

DialogBox

 

MainWnd

소스코드

#include <windows.h>
#include <tchar.h> //_ttoi
#include "resource.h"

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass=TEXT("Mouse");

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
		  ,LPSTR lpszCmdParam,int nCmdShow)
{
	HWND hWnd;
	MSG Message;
	WNDCLASS WndClass;
	g_hInst=hInstance;
	
	WndClass.cbClsExtra=0;
	WndClass.cbWndExtra=0;
	WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
	WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
	WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	WndClass.hInstance=hInstance;
	WndClass.lpfnWndProc=WndProc;
	WndClass.lpszClassName=lpszClass;
	WndClass.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1);
	WndClass.style=CS_HREDRAW | CS_VREDRAW;// | CS_DBLCLKS;
	RegisterClass(&WndClass);

	hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,
		  CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
		  NULL,(HMENU)NULL,hInstance,NULL);
	ShowWindow(hWnd,nCmdShow);
	
	while (GetMessage(&Message,NULL,0,0)) {
		TranslateMessage(&Message);
		DispatchMessage(&Message);
	}
	return (int)Message.wParam;
}
//선의 위치, 색, 굵기 저장
typedef struct _line {
	POINT p[500];
	int iCount;
	COLORREF pColor;
	int pWidth;
} line;
line lines[1000];
// 선 갯수
int iLines;
//선의 굵기, 색 기본값
int iCurrentPenWidth = 3;
COLORREF iCurrentPenColor = RGB(255, 0, 0);
TCHAR *Items[] = { TEXT("3"), TEXT("6"), TEXT("9"), TEXT("12") };//콤보박스에 넣을 문자열
HWND hCombo, hEdit, hRed, hGreen, hBlue;//윈도우 호출 시 사용 핸들 

//팬의 RGB색상 값
int Red = GetRValue(iCurrentPenColor);
int Green = GetGValue(iCurrentPenColor);
int Blue = GetBValue(iCurrentPenColor);

//대화상자
BOOL CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	int TempPos;//스크롤 임시 값
	switch (iMessage) {
	case WM_INITDIALOG:
		//자식 윈도우를 사용할 수 있는 핸들 지정
		hCombo = GetDlgItem(hDlg, IDC_COMBO1);
		hRed = GetDlgItem(hDlg, IDC_SCROLLBAR1);
		hGreen = GetDlgItem(hDlg, IDC_SCROLLBAR2);
		hBlue = GetDlgItem(hDlg, IDC_SCROLLBAR3);
		//스크롤 바의 범위, 초기 스크롤바 커서 위치
		SetScrollRange(hRed, SB_CTL, 0, 255, TRUE);
		SetScrollPos(hRed, SB_CTL, Red, TRUE);
		SetScrollRange(hGreen, SB_CTL, 0, 255, TRUE);
		SetScrollPos(hGreen, SB_CTL, Green, TRUE);
		SetScrollRange(hBlue, SB_CTL, 0, 255, TRUE);
		SetScrollPos(hBlue, SB_CTL, Blue, TRUE);
		//콤보 박스에 문자열 넣기
		for (int i = 0; i<4; i++) {
			SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)Items[i]);
		}
		SendMessage(hEdit, EN_CHANGE, iCurrentPenWidth, 0);//에디트의 굵기 값을 iCurrentPenWidthd에게 전달
		//굵기 초기값
		SetDlgItemInt(hDlg, IDC_COMBO1, iCurrentPenWidth, FALSE);
		SetDlgItemInt(hDlg, IDC_STATIC1, Red, FALSE);
		SetDlgItemInt(hDlg, IDC_STATIC2, Green, FALSE);
		SetDlgItemInt(hDlg, IDC_STATIC3, Blue, FALSE);
		return TRUE;
	case WM_HSCROLL://스크롤이 움직일 때 스크롤(부모)
		TempPos = GetScrollPos((HWND)lParam,/*선택한 스크롤바 윈도우 핸들*/
			 SB_CTL);//현재 움직이는 커서 위치를 임시저장

			switch (LOWORD(wParam)) {//자식
			case SB_LINELEFT://임시저장된값에서 1뺌
				TempPos = max(0, TempPos - 1); //최소제어 0 
				break;
			case SB_LINERIGHT:
				TempPos = min(255, TempPos + 1);//최대제어 255
				break;
			case SB_PAGELEFT://스크롤의 오른쪽빈바
				TempPos = max(0, TempPos - 10);
				break;
			case SB_PAGERIGHT:
				TempPos = min(255, TempPos + 10);
				break;
			case SB_THUMBTRACK://끌었을때
				TempPos = HIWORD(wParam);//임지시저장 값은 커서 현재위치
				break;
			}
			//스크롤바 윈도우 핸들 == 레드 스크롤 바의 윈도우핸들
			if ((HWND)lParam == hRed) {
				Red = TempPos;//전역변수 레드 값을 임시저장값으로 변경
				SetDlgItemInt(hDlg, IDC_STATIC1, Red, FALSE);//static1의 텍스트 변경
			 }
			if ((HWND)lParam == hGreen) { 
				Green = TempPos;
				SetDlgItemInt(hDlg, IDC_STATIC2, Green, FALSE);
				 }
			if ((HWND)lParam == hBlue) {
				Blue = TempPos;
				SetDlgItemInt(hDlg, IDC_STATIC3, Blue, FALSE);
			}
			iCurrentPenColor = RGB(Red, Green, Blue);//팬 색을 전역변수Red, Green,Blue로 변경
			SetScrollPos((HWND)lParam, SB_CTL, TempPos, TRUE);//스크롤 바의 위치를 임시저장 값으로 변경
			return 0;

	case WM_COMMAND://부모(대화상자)
		switch (LOWORD(wParam)) {
		case IDOK://자식(OK버튼)
			iCurrentPenWidth = GetDlgItemInt(hDlg, IDC_COMBO1, NULL, FALSE);//콤보박스의 굵기 값을 iCPW에 저장
			EndDialog(hDlg, IDOK);
			return TRUE;
		case IDCANCEL://자식(취소)
			EndDialog(hDlg, IDCANCEL);
			return TRUE;
		}
		break;
	}
	return FALSE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	static int x;
	static int y;
	HPEN hPen;
	switch (iMessage) {
	case WM_CREATE:
		return 0;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDM_DIALOG:
			DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DlgProc);
			break;
		}
	return 0;
	case WM_LBUTTONDOWN:
		SetFocus(hWnd);
		x=LOWORD(lParam);
		y=HIWORD(lParam);
		lines[iLines].pColor =iCurrentPenColor ;
		lines[iLines].pWidth =iCurrentPenWidth;
		lines[iLines].p[lines[iLines].iCount].x = x;
		lines[iLines].p[lines[iLines].iCount].y = y;
		lines[iLines].iCount++;  
		return 0;
	case WM_MOUSEMOVE:
		if (wParam & MK_LBUTTON) {
			hdc=GetDC(hWnd);
			hPen = CreatePen(PS_SOLID, iCurrentPenWidth, iCurrentPenColor);
			hPen=(HPEN)SelectObject(hdc, hPen);
			MoveToEx(hdc,x,y,NULL);
			x=LOWORD(lParam);
			y=HIWORD(lParam);
			lines[iLines].p[lines[iLines].iCount].x = x;
			lines[iLines].p[lines[iLines].iCount].y = y;
			lines[iLines].iCount++;
			LineTo(hdc,x,y);
			DeleteObject(SelectObject(hdc, hPen));
			ReleaseDC(hWnd,hdc);
		}
		return 0;
	case WM_LBUTTONUP:
		iLines++;
		return 0;
	case WM_KEYDOWN:
		switch (wParam) {
		case VK_BACK:
			if (iLines > 0)
			{
				iLines--; lines[iLines].iCount = 0;
			}
			InvalidateRect(hWnd, NULL, TRUE);
			break;
		}
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		for (int i = 0; i < iLines; i++)
		{
			hPen = CreatePen(PS_SOLID, lines[i].pWidth, lines[i].pColor);
			hPen = (HPEN)SelectObject(hdc, hPen); 
			MoveToEx(hdc, lines[i].p[0].x, 
					lines[i].p[0].y, NULL);
			for (int j = 0; j < lines[i].iCount-1; j++)
			{
				
				LineTo(hdc, lines[i].p[j+1].x,
					lines[i].p[j+1].y);
			}
			DeleteObject(SelectObject(hdc, hPen));
		}
		return 0;
	case WM_LBUTTONDBLCLK:
		InvalidateRect(hWnd, NULL, TRUE);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

자료구조

//선의 위치, 색, 굵기 저장
typedef struct _line {
	POINT p[500];
	int iCount;
	COLORREF pColor;
	int pWidth;
} line;
line lines[1000];
// 선 갯수
int iLines;
//선의 굵기, 색 기본값
int iCurrentPenWidth = 3;
COLORREF iCurrentPenColor = RGB(255, 0, 0);
TCHAR *Items[] = { TEXT("3"), TEXT("6"), TEXT("9"), TEXT("12") };//콤보박스에 넣을 문자열
HWND hCombo, hEdit, hRed, hGreen, hBlue;//윈도우 호출 시 사용 핸들 

//팬의 RGB색상 값
int Red = GetRValue(iCurrentPenColor);
int Green = GetGValue(iCurrentPenColor);
int Blue = GetBValue(iCurrentPenColor);

//대화상자

추가된 부분

  • 대화상자에서 여러 컨트롤을 사용하기 때문에 이 전에 윈도우에서 사용하던 핸들은 다 지웠다.
  • hEdit 콤보박스에 직접 숫자를 입력 할때 사용할 핸들.
  • hRed~hBlue 3개의 스크롤바 마다 각자 값을 저장할 핸들.
  • 전역변수 Red에 iCPC의 R값을 받아오는 함수를 사용함.

 

DIgProC(대화상자 원도우)

BOOL CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	int TempPos;//스크롤 임시 값
	switch (iMessage) {
	case WM_INITDIALOG:
		//자식 윈도우를 사용할 수 있는 핸들 지정
		hCombo = GetDlgItem(hDlg, IDC_COMBO1);
		hRed = GetDlgItem(hDlg, IDC_SCROLLBAR1);
		hGreen = GetDlgItem(hDlg, IDC_SCROLLBAR2);
		hBlue = GetDlgItem(hDlg, IDC_SCROLLBAR3);
		//스크롤 바의 범위, 초기 스크롤바 커서 위치
		SetScrollRange(hRed, SB_CTL, 0, 255, TRUE);
		SetScrollPos(hRed, SB_CTL, Red, TRUE);
		SetScrollRange(hGreen, SB_CTL, 0, 255, TRUE);
		SetScrollPos(hGreen, SB_CTL, Green, TRUE);
		SetScrollRange(hBlue, SB_CTL, 0, 255, TRUE);
		SetScrollPos(hBlue, SB_CTL, Blue, TRUE);
		//콤보 박스에 문자열 넣기
		for (int i = 0; i<4; i++) {
			SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)Items[i]);
		}
		SendMessage(hEdit, EN_CHANGE, iCurrentPenWidth, 0);//에디트의 굵기 값을 iCurrentPenWidthd에게 전달
		//굵기 초기값
		SetDlgItemInt(hDlg, IDC_COMBO1, iCurrentPenWidth, FALSE);
		SetDlgItemInt(hDlg, IDC_STATIC1, Red, FALSE);
		SetDlgItemInt(hDlg, IDC_STATIC2, Green, FALSE);
		SetDlgItemInt(hDlg, IDC_STATIC3, Blue, FALSE);
		return TRUE;
}

대화상자를 처음키면 사용되는 이벤트

  • 전역변수로 설정한 핸들에 윈도우를 지정해준다.
  • 스크롤 바의 범위와,  스크롤 바 커서 위치를 지정해준다.
  • 콤보 박스에 문자열Items[]에 저장된 텍스트를 넣는다.
  • SetDigItemInt = 콤보박스와 색상의 초기 값을 설정한다.
case WM_HSCROLL://스크롤이 움직일 때 스크롤(부모)
		TempPos = GetScrollPos((HWND)lParam,/*선택한 스크롤바 윈도우 핸들*/
			 SB_CTL);//현재 움직이는 커서 위치를 임시저장

			switch (LOWORD(wParam)) {//SB에게 명령
			case SB_LINELEFT://임시저장된값에서 1뺌
				TempPos = max(0, TempPos - 1); //최소제어 0 
				break;
			case SB_LINERIGHT:
				TempPos = min(255, TempPos + 1);//최대제어 255
				break;
			case SB_PAGELEFT://스크롤의 오른쪽빈바
				TempPos = max(0, TempPos - 10);
				break;
			case SB_PAGERIGHT:
				TempPos = min(255, TempPos + 10);
				break;
			case SB_THUMBTRACK://끌었을때
				TempPos = HIWORD(wParam);//임지시저장 값은 커서 현재위치
				break;
			}
			//스크롤바 윈도우 핸들 == 레드 스크롤 바의 윈도우핸들
			if ((HWND)lParam == hRed) {
				Red = TempPos;//전역변수 레드 값을 임시저장값으로 변경
				SetDlgItemInt(hDlg, IDC_STATIC1, Red, FALSE);//static1의 텍스트 변경
			 }
			if ((HWND)lParam == hGreen) { 
				Green = TempPos;
				SetDlgItemInt(hDlg, IDC_STATIC2, Green, FALSE);
				 }
			if ((HWND)lParam == hBlue) {
				Blue = TempPos;
				SetDlgItemInt(hDlg, IDC_STATIC3, Blue, FALSE);
			}
			iCurrentPenColor = RGB(Red, Green, Blue);//팬 색을 전역변수Red, Green,Blue로 변경
			SetScrollPos((HWND)lParam, SB_CTL, TempPos, TRUE);//스크롤 바의 위치를 임시저장 값으로 변경
			return 0;

스크롤이 움직일때마다.

  • 지역변수 TempPos는 임시값이라고 하겠다.
  • TempPos = GetScrollPos((HWND)lParam, SB_CTL)
  • GetScrollPos 스크롤 바의 위치를 얻는 함수이다.lParam 스크롤바의 윈도우 핸들이다.
  • 첫 번째 스크롤 바의 윈도우 핸들을 만졌다면 첫 번째 스크롤 바의 커서의 위치가 리턴된다.
  • 임시 값은 선택한 스크롤의 위치 값이 저장된다.

 

스크롤에는 LOWRO(wParam)로 사용자의 스크롤 요구 사항을 전달 받을 수 있다.

  • SB_LINELEFT(UP) / RIGHT(DOWN)=  왼쪽(위로)버튼 클릭 한 단위 이동 / 오른쪽(아래)버튼 클릭 한 단위 이동
  • SB_PAGELEFT(UP) / RIGHT(DOWN)=  왼쪽(위로) 몸통 클릭 한 페이지 이동 / 오른쪽(아래) 몸통 클릭 한 페이지 이동
  • SB_THUMBPOSITION = 스크롤 박스 드래그 후 마우스 버튼 놓는다.
  • SB_THUMBTRACK = 스크롤 박스 드래그 하고 있는 중 이 메시지는 마우스 버튼을 놓을 때까지 계속 전달


if ((HWND)lParam == hRed)
스크롤바 윈도우 핸들 == 레드 스크롤 바의 윈도우핸들이라면

  • Red의 값을 임시값으로 초기화하고 static1의 텍스트 변경

 

case WM_COMMAND://부모(대화상자)
		switch (LOWORD(wParam)) {
		case IDOK://자식(OK버튼)
			iCurrentPenWidth = GetDlgItemInt(hDlg, IDC_COMBO1, NULL, FALSE);//콤보박스의 굵기 값을 iCPW에 저장
			EndDialog(hDlg, IDOK);
			return TRUE;
		case IDCANCEL://자식(취소)
			EndDialog(hDlg, IDCANCEL);
			return TRUE;
		}
		break;

확인 버튼을 누르면

  • iCPW의 굵기를 IDC_COMBO1의 인트값으로 바꾼다.
반응형
반응형

① 유니코드&MBCS

선그리기 v.combo를 보면 

iCurrentPenWidth = _ttoi(str);

이런 코드가 있다.

_ttoiatoi는 C언어에서 텍스트를 정수로 바꿔주는 함수 atoi와 똑같은 역할을 한다.

그러면 atoi와 다른 점은 무엇일까? 

atoi는 멀티바이트코드를 읽는 멀티바이트 코드이고

_ttoi는 멀티바이트+유니코드 모두 읽을 수 있는 중립코드이다. 

유니 코드는 _wtoi가 있다.

v.combo에서 쓰이는 모습을 찾아보자

iCurrentPenWidth = _ttoi(str); //Neutral Code
iCurrentPenWidth = atoi(str);//C-MBCS		
iCurrentPenWidth = _wtoi(str); //C-유니코드 

 

_ttoi를 사용하기 위해서는 라이브러리

#include <tchar.h>

tchar.h를 불러와야 한다.

_ttoi는 문자집합이 유니코드이면 _wtoi로 str을 변환하고 아니라면 atoi로 str을 변환한다.

이전에 C를 배울때는 C는 디폴트 문자집합이 MBCS라 atoi를 사용했지만 그 상태로 문자집합이 유니코드인 환경에서는 오류가 뜨기 때문에 어떤 문자집합에도 읽을 수 있는 Neutral Code를 사용하는 것이 좋다.

2주차에 만든 WM_CHAR에

	len=lstrlen(str);

 

 

 

lstrlen도 Neutral Code이다.

lstrlen의 정의

정의를 확인하면 UNICODE이면 lstrlenW로 읽고 else(MBCS)이면 lstrlenA로 읽는걸 확인 할 수 있다. 

 

② 대화상자

②-1. About

About Dialog

Dialog는 리소스에서 Dialog를 추가하고 도구상자에서 

도구를 선택해 Dialog에 바로 넣을 수 있다.

About Diolog에서 사용하는 도구는 "Button"과 "Static Text"이다. 

Static Text의 텍스트 값 바꾸기

리소스는 이 정도로 끝이다.

소스 코드

#include "resource.h"
BOOL CALLBACK AboutDlgProc(HWND hDlg,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	switch (iMessage) {
	case WM_INITDIALOG:
		return TRUE;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDOK:
			EndDialog(hDlg,IDOK);
			return TRUE;
		case IDCANCEL:
			EndDialog(hDlg,IDCANCEL);
			return TRUE;
		}
		break;
	}
	return FALSE;
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	switch (iMessage) {
	case WM_LBUTTONDOWN:
		DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG1),hWnd,AboutDlgProc);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

Dlglog를 사용하고 싶으면 대화상자 프로시져를 생성 해줘야한다.

BOOL CALLBACK AboutDlgProc(HWND hDlg,UINT iMessage,WPARAM wParam,LPARAM lParam)

메인 윈도우와 똑같이 콜백함수로 선언하고 인자역시 같다.

하지만 리턴 값이 다르다 대화상자 프로시져는 BOOL형의 값을 리턴한다.

메시지를 제대로 처리했다면 TRUE를 리턴하고 그렇지 못하면 FALSE를 리턴한다. 

AboutDlgProc 내부

switch (iMessage) {
	case WM_INITDIALOG: // 1
		return TRUE;
	case WM_COMMAND: //2
		switch (LOWORD(wParam)) {
		case IDOK: //3
			EndDialog(hDlg,IDOK);
			return TRUE;
		case IDCANCEL: //4
			EndDialog(hDlg,IDCANCEL);
			return TRUE;
		}
		break;
    	return FALSE;

1. WM_INITDIALOG는 대화상자가 처음 만들어 질때 딱 한번만 실행되는 메인 윈도우의 WM_CREATE와 같은 이벤트

2. WM_COMMAND는 메인 윈도우와 똑같이 작동한다. 대화상자에서는 여기서는 대화상자가 부모 윈도우이고 버튼이 자식 윈도우이다.

3, 4. 확인, 취소를 눌렀을 때 return TRUE까지 실행 EndDialog 대화상자를 종료한다.

WndProc

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	switch (iMessage) {
	case WM_LBUTTONDOWN:
		DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG2),hWnd,AboutDlgProc);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

왼버튼 클릭시

-DialogBox(인스턴스 핸들, 열고싶은 대화상자ID, 대화상자를 띄울 윈도우, 대화상자가 있는 프로시져)

②-2. InfoDlg

InfoDlg는 대화상자에서 x y값을 입력하고 문자열을 입력하면

x y값 + 문자열 입력

문자열을 출력하는 프로그램이다.

x y위치에 문자열 출력

소스코드

#include "resource.h"
BOOL CALLBACK InfoDlgProc(HWND hDlg,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	switch (iMessage) {
	case WM_INITDIALOG://대화 상자가 한번 떴을떄
		SetDlgItemText(hDlg,IDC_STR,str); //읽기
		SetDlgItemInt(hDlg,IDC_X,x,FALSE);
		SetDlgItemInt(hDlg,IDC_Y,y,FALSE);
		return TRUE;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDOK:
			GetDlgItemText(hDlg,IDC_STR, str,128); //쓰기
			x=GetDlgItemInt(hDlg,IDC_X,NULL,FALSE);
			y=GetDlgItemInt(hDlg,IDC_Y,NULL,FALSE);
			EndDialog(hDlg,IDOK);
			return TRUE;//ok누르면 ok리턴
		case IDCANCEL:
			EndDialog(hDlg,IDCANCEL);
			return TRUE;//clancel을 누르면 clancel을 리턴
		}
		break;
	}
	return FALSE;
}


LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	switch (iMessage) {
	case WM_CREATE:
		hWndMain=hWnd;
		x=100;
		y=100;
		lstrcpy(str,TEXT("String"));
		return 0;
	case WM_PAINT:
		hdc=BeginPaint(hWnd, &ps);
		TextOut(hdc,x,y,str,lstrlen(str));
		EndPaint(hWnd, &ps);
		return 0;
	case WM_LBUTTONDOWN:
		if (DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG1),
			hWnd,InfoDlgProc)==IDOK) //
			InvalidateRect(hWnd, NULL, TRUE);//WM_PAINT로 IDD_DIALOG1 전역변수를 
            바꿔서 새로운 위치에 새로운 텍스트를 그림
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

InfoDlgProc

int x;
int y;
TCHAR str[128];

BOOL CALLBACK InfoDlgProc(HWND hDlg,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	switch (iMessage) {
	case WM_INITDIALOG:// 1. 대화 상자가 한번 떴을떄 
		SetDlgItemText(hDlg,IDC_STR,str); //읽기
		SetDlgItemInt(hDlg,IDC_X,x,FALSE);
		SetDlgItemInt(hDlg,IDC_Y,y,FALSE);
		return TRUE;
	case WM_COMMAND: 
		switch (LOWORD(wParam)) {
		case IDOK: //2
			GetDlgItemText(hDlg,IDC_STR, str,128); //쓰기
			x=GetDlgItemInt(hDlg,IDC_X,NULL,FALSE);
			y=GetDlgItemInt(hDlg,IDC_Y,NULL,FALSE);
			EndDialog(hDlg,IDOK);
			return TRUE;//ok누르면 ok리턴
		case IDCANCEL:
			EndDialog(hDlg,IDCANCEL);
			return TRUE;//clancel을 누르면 clancel을 리턴
		}
		break;
	}
	return FALSE;
}

1. 대화 상자가 켜졌을 때 한번

  • SetDlgItemText은 문자열 전역변수 str에 있는 문자열을 IDC_STR에 쓴다.
  • SetDlgITemInt은 정수 전역변수 x에 값을 읽는다. 4번째 인수가 TRUE이면 무조건 부호가 있는 정수형 값을 읽고 FALSE일때는 무조건 양수로 읽는다.

2. IDOK 이벤트 발생

  • GetDlgItemText(hDlg,IDC_STR, str,128) IDC_STR의 텍스트 값을 str문자열에 넣는다.
  • x=GetDlgItemInt(hDlg,IDC_X,NULL,FALSE) x에 lDC의 값을 전달한다.

WndProc

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	switch (iMessage) {
	case WM_CREATE://1
		hWndMain=hWnd;
		x=100;
		y=100;
		lstrcpy(str,TEXT("String"));
		return 0;
	case WM_PAINT://2
		hdc=BeginPaint(hWnd, &ps);
		TextOut(hdc,x,y,str,lstrlen(str));
		EndPaint(hWnd, &ps);
		return 0;
	case WM_LBUTTONDOWN://3
		if (DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG1),
			hWnd,InfoDlgProc)==IDOK) //
			InvalidateRect(hWnd, NULL, TRUE);//WM_PAINT로 IDD_DIALOG1 전역변수를 
            바꿔서 새로운 위치에 새로운 텍스트를 그림
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

1. 윈도우 첫 생성시

  • 전역변수 x, y를 초기화
  • str문자열에 "String"복사해서 넣음

2. 윈도우 최소화시 

  • 문자열 str을 전역변수 x, y 위치에 그림

3. 왼쪽버튼클릭시

  • 대화상자를 열고 OK값이 리턴되면 WM_PAINT 이벤트를 발생시킨다.

②-3. 스크롤바 맛보기

MyScrollBar

소스코드

#define ID_SCRRED 100
#define ID_SCRGREEN 101
#define ID_SCRBLUE 102
HWND hRed,hGreen,hBlue;
int Red,Green,Blue;
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	HBRUSH MyBrush, OldBrush;
	int TempPos;
	switch (iMessage) {
	case WM_CREATE:
		hRed=CreateWindow(TEXT("scrollbar"),NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
			10,10,400,20,hWnd,(HMENU)ID_SCRRED,g_hInst,NULL);
		hGreen=CreateWindow(TEXT("scrollbar"),NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
			10,40,400,20,hWnd,(HMENU)ID_SCRGREEN,g_hInst,NULL);
		hBlue=CreateWindow(TEXT("scrollbar"),NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
			10,70,400,20,hWnd,(HMENU)ID_SCRBLUE,g_hInst,NULL);
		SetScrollRange(hRed,SB_CTL,0,255,TRUE); //스크롤바의 범위 0~255까지
		SetScrollPos(hRed,SB_CTL,0,TRUE);
		SetScrollRange(hGreen,SB_CTL,0,255,TRUE);

		SetScrollPos(hGreen,SB_CTL,0,TRUE);
		SetScrollRange(hBlue,SB_CTL,0,255,TRUE);
		SetScrollPos(hBlue,SB_CTL,0,TRUE);
		return 0;
	case WM_HSCROLL:
		if ((HWND)lParam == hRed) TempPos = Red;//레드를 만졌다면 TempPos는 
		if ((HWND)lParam == hGreen) TempPos = Green;
		if ((HWND)lParam == hBlue) TempPos = Blue;
		switch (LOWORD(wParam)) {
		case SB_LINELEFT:
			TempPos=max(0,TempPos-1); //0보다는 크다 최소제어
			break;
		case SB_LINERIGHT:
			TempPos=min(255,TempPos+1);//최대제어
			break;
		case SB_PAGELEFT://스크롤의 오른쪽빈바
			TempPos=max(0,TempPos-10);
			break;
		case SB_PAGERIGHT:
			TempPos=min(255,TempPos+10);
			break;
		case SB_THUMBTRACK://끌었을때
			TempPos=HIWORD(wParam);
			break;
		}
		if ((HWND)lParam == hRed) Red=TempPos;
		if ((HWND)lParam == hGreen) Green=TempPos;
		if ((HWND)lParam == hBlue) Blue=TempPos;
		//SetScrollPos((HWND)lParam,SB_CTL,TempPos,TRUE);//스크롤 바의 위치 조정
		InvalidateRect(hWnd,NULL,FALSE);
		return 0;
	case WM_PAINT:
		hdc=BeginPaint(hWnd,&ps);
		MyBrush=CreateSolidBrush(RGB(Red,Green,Blue));
		OldBrush=(HBRUSH)SelectObject(hdc,MyBrush);
		Rectangle(hdc,10,100,410,300);
		SelectObject(hdc,OldBrush);
		DeleteObject(MyBrush);
		EndPaint(hWnd,&ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

sadas간단하게 보고 다음시간에 자세하게 알아보자dasㄱ

 

전역변수

#define ID_SCRRED 100
#define ID_SCRGREEN 101
#define ID_SCRBLUE 102
HWND hRed,hGreen,hBlue;
int Red,Green,Blue;

1~3까지는 스크롤바의 ID값을 정의했다

다른 색을 가지는 윈도우 핸들 3가지

RGB색상의 숫자를 정의하는 정수

switch (iMessage) {
	case WM_CREATE:
		hRed=CreateWindow(TEXT("scrollbar"),NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
			10,10,400,20,hWnd,(HMENU)ID_SCRRED,g_hInst,NULL);
		hGreen=CreateWindow(TEXT("scrollbar"),NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
			10,40,400,20,hWnd,(HMENU)ID_SCRGREEN,g_hInst,NULL);
		hBlue=CreateWindow(TEXT("scrollbar"),NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ,
			10,70,400,20,hWnd,(HMENU)ID_SCRBLUE,g_hInst,NULL);
		SetScrollRange(hRed,SB_CTL,0,255,TRUE); //스크롤바의 범위 0~255까지
		SetScrollPos(hRed,SB_CTL,0,TRUE);
		SetScrollRange(hGreen,SB_CTL,0,255,TRUE);
		SetScrollPos(hGreen,SB_CTL,0,TRUE);
		SetScrollRange(hBlue,SB_CTL,0,255,TRUE);
		SetScrollPos(hBlue,SB_CTL,0,TRUE);
  • hRed=CreateWindow(TEXT("scrollbar"),NULL,WS_CHILD | WS_VISIBLE | SBS_HORZ, 10,10,400,20,hWnd,(HMENU)ID_SCRRED,g_hInst,NULL); hRed핸들에 scrollbar클래스를 지정하고 , 스크롤바는 캡션이 필요없다 , 스타일 지정 , 위치 , 부모 윈도우 , ID , 인스턴스 핸들).
  • SetScrollRange(hRed,SB_CTL,0,255,TRUE); 스크롤바의 범위 0~255까지
    SetScrollPos(hRed,SB_CTL,0,TRUE); 스크롤의 초기 위치

WM_HSCROLL

case WM_HSCROLL:
		if ((HWND)lParam == hRed) TempPos = Red;//레드를 만졌다면 TempPos는 
		if ((HWND)lParam == hGreen) TempPos = Green;
		if ((HWND)lParam == hBlue) TempPos = Blue;
		switch (LOWORD(wParam)) {
		case SB_LINELEFT:
			TempPos=max(0,TempPos-1); //0보다는 크다 최소제어
			break;
		case SB_LINERIGHT:
			TempPos=min(255,TempPos+1);//최대제어
			break;
		case SB_PAGELEFT://스크롤의 오른쪽빈바
			TempPos=max(0,TempPos-10);
			break;
		case SB_PAGERIGHT:
			TempPos=min(255,TempPos+10);
			break;
		case SB_THUMBTRACK://끌었을때
			TempPos=HIWORD(wParam);
			break;
		}
		if ((HWND)lParam == hRed) Red=TempPos;
		if ((HWND)lParam == hGreen) Green=TempPos;
		if ((HWND)lParam == hBlue) Blue=TempPos;
		SetScrollPos((HWND)lParam,SB_CTL,TempPos,TRUE);//스크롤 바의 위치 조정
		InvalidateRect(hWnd,NULL,FALSE);
		return 0;

스크롤을 만졌을 때 발생하는 이벤트

 

 

반응형
반응형

v.combo

#include <windows.h>
#include <tchar.h>
#include "resource.h"

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass=TEXT("Mouse");

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
		  ,LPSTR lpszCmdParam,int nCmdShow)
{
	HWND hWnd;
	MSG Message;
	WNDCLASS WndClass;
	g_hInst=hInstance;
	
	WndClass.cbClsExtra=0;
	WndClass.cbWndExtra=0;
	WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
	WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
	WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	WndClass.hInstance=hInstance;
	WndClass.lpfnWndProc=WndProc;
	WndClass.lpszClassName=lpszClass;
	WndClass.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1);
	WndClass.style=CS_HREDRAW | CS_VREDRAW;// | CS_DBLCLKS;
	RegisterClass(&WndClass);

	hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,
		  CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
		  NULL,(HMENU)NULL,hInstance,NULL);
	ShowWindow(hWnd,nCmdShow);
	
	while (GetMessage(&Message,NULL,0,0)) {
		TranslateMessage(&Message);
		DispatchMessage(&Message);
	}
	return (int)Message.wParam;
}

typedef struct _line {
	POINT p[500];
	int iCount;
	COLORREF pColor;
	int pWidth;
} line;

line lines[1000];

//int iTempCount;
int iLines;

int iCurrentPenWidth = 3;
COLORREF iCurrentPenColor = RGB(255, 0, 0);

enum { ID_R1 = 101, ID_R2, ID_R3 };
HWND r1, r2, r3;

#define ID_COMBOBOX 100
TCHAR *Items[] = { TEXT("3"), TEXT("6"), TEXT("9"), TEXT("12") };
HWND hCombo;
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	static int x;
	static int y;
	//static BOOL bNowDraw=FALSE;
	HPEN hPen;
	TCHAR str[128];
	switch (iMessage) {
	case WM_CREATE:
		CreateWindow(TEXT("button"), TEXT("Color"), WS_CHILD | WS_VISIBLE |
			BS_GROUPBOX, 5, 5, 120, 110, hWnd, (HMENU)0, g_hInst, NULL);
		r1 = CreateWindow(TEXT("button"), TEXT("Red"), WS_CHILD | WS_VISIBLE |
			BS_AUTORADIOBUTTON | WS_GROUP,
			10, 20, 100, 30, hWnd, (HMENU)ID_R1, g_hInst, NULL);
		r2 = CreateWindow(TEXT("button"), TEXT("Green"), WS_CHILD | WS_VISIBLE |
			BS_AUTORADIOBUTTON,
			10, 50, 100, 30, hWnd, (HMENU)ID_R2, g_hInst, NULL);
		r3 = CreateWindow(TEXT("button"), TEXT("Blue"), WS_CHILD | WS_VISIBLE |
			BS_AUTORADIOBUTTON,
			10, 80, 100, 30, hWnd, (HMENU)ID_R3, g_hInst, NULL);
		
		CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R1);
		
		hCombo = CreateWindow(TEXT("combobox"), NULL, WS_CHILD | WS_VISIBLE |
			CBS_DROPDOWN, 130, 10, 100, 200, hWnd, (HMENU)ID_COMBOBOX, g_hInst, NULL);
		for (int i = 0; i<4; i++) {
			SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)Items[i]);
		}
		SendMessage(hCombo, CB_SETCURSEL, (iCurrentPenWidth/3)-1, 0);
		return 0;

	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDM_RED:
		case ID_R1:
			iCurrentPenColor = RGB(255, 0, 0);
			SetFocus(hWnd);
			CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R1);
			break;
		case IDM_GREEN:
		case ID_R2:
			iCurrentPenColor = RGB(0,255, 0, 0);	
			SetFocus(hWnd);
			CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R2);
			break;
		case IDM_BLUE:
		case ID_R3:
			iCurrentPenColor = RGB(0,0, 255);
			SetFocus(hWnd);
			CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R3);
			break;
		
		case ID_COMBOBOX:
			switch (HIWORD(wParam)) {
			case CBN_SELCHANGE:
				iCurrentPenWidth = 
					(SendMessage(hCombo, CB_GETCURSEL, 0, 0) + 1) * 3;
				//SetFocus(hWnd);
				break;
			case CBN_EDITCHANGE:
				GetWindowText(hCombo, str, 128);
				iCurrentPenWidth = _ttoi(str);
				//SetFocus(hWnd);
				break;
			}
			
		}
		return 0;
	case WM_INITMENU:
		if (iCurrentPenColor == RGB(255, 0, 0)){
			CheckMenuItem((HMENU)wParam, IDM_RED, MF_BYCOMMAND | MF_CHECKED);
			CheckMenuItem((HMENU)wParam, IDM_GREEN, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_BLUE, MF_BYCOMMAND | MF_UNCHECKED);
		}
		else if (iCurrentPenColor == RGB(0, 255, 0)){
			CheckMenuItem((HMENU)wParam, IDM_RED, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_GREEN, MF_BYCOMMAND | MF_CHECKED);
			CheckMenuItem((HMENU)wParam, IDM_BLUE, MF_BYCOMMAND | MF_UNCHECKED);
		}
		else if (iCurrentPenColor == RGB(0, 0, 255)){
			CheckMenuItem((HMENU)wParam, IDM_RED, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_GREEN, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_BLUE, MF_BYCOMMAND | MF_CHECKED);
		}
		return 0;
	case WM_KEYDOWN:
		switch (wParam) {
		case VK_BACK:
			if (iLines > 0) 
			{
				iLines--; lines[iLines].iCount = 0;
			}
			InvalidateRect(hWnd, NULL, TRUE);
			break;
		}
		return 0;

	case WM_LBUTTONDOWN:
		SetFocus(hWnd);
		x=LOWORD(lParam);
		y=HIWORD(lParam);
		
		 
		lines[iLines].pColor =iCurrentPenColor ;
		lines[iLines].pWidth =iCurrentPenWidth;

		lines[iLines].p[lines[iLines].iCount].x = x;
		lines[iLines].p[lines[iLines].iCount].y = y;
		lines[iLines].iCount++;  ///
		return 0;
	case WM_MOUSEMOVE:
		if (wParam & MK_LBUTTON) {
			hdc=GetDC(hWnd);
			hPen = CreatePen(PS_SOLID, iCurrentPenWidth, iCurrentPenColor);
			
			hPen=(HPEN)SelectObject(hdc, hPen);
			
			MoveToEx(hdc,x,y,NULL);
			x=LOWORD(lParam);
			y=HIWORD(lParam);
			lines[iLines].p[lines[iLines].iCount].x = x;
			lines[iLines].p[lines[iLines].iCount].y = y;
			lines[iLines].iCount++;
			LineTo(hdc,x,y);

			DeleteObject(SelectObject(hdc, hPen));

			ReleaseDC(hWnd,hdc);
		}
		return 0;
	case WM_LBUTTONUP:
		//lines[iLines].iCount = iTempCount;
		//iTempCount = 0;
		iLines++;
		return 0;
		// 내가 생성한 GDI Object는 사용후반드시 삭제한다, 단 선택해제후
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		for (int i = 0; i < iLines; i++)
		{
			hPen = CreatePen(PS_SOLID, lines[i].pWidth, lines[i].pColor);
			hPen = (HPEN)SelectObject(hdc, hPen);  //선택한다.
			MoveToEx(hdc, lines[i].p[0].x, 
					lines[i].p[0].y, NULL);
			for (int j = 0; j < lines[i].iCount-1; j++)
			{
				
				LineTo(hdc, lines[i].p[j+1].x,
					lines[i].p[j+1].y);
			}
			 //선택해제...
			DeleteObject(SelectObject(hdc, hPen));  //그리고 삭제한다...
		}
		return 0;

	case WM_LBUTTONDBLCLK:
		InvalidateRect(hWnd, NULL, TRUE);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

Combo 버전에서 추가된 부분은 콤보박스와 에디트이다.

콤보 박스를 통해 선의 굵기를 정해주는 기능을 추가했다.

추가된 자료구조

#define ID_COMBOBOX 100
TCHAR *Items[] = { TEXT("3"), TEXT("6"), TEXT("9"), TEXT("12") };
HWND hCombo;
int iCurrentPenWidth = 3;

typedef struct _line {
	int pWidth;
} line;

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	TCHAR str[128];
}

위에서 부터 순서대로

1. ID값을 저장하는 매크로

2. 문자열을 저장하는 배열

3. 컨트롤 윈도우를 저장하는 핸들

4. 팬의 굵기를 기록하는 전역변수

5. 선 마다 굵기를 기록하는 구조체

6. 자식 윈도우의 콤보박스 에디터에 기록되는 값을 저장하는 지역변수 str

WM_CREATE(콤보 박스 생성)

case WM_CREATE:
		hCombo = CreateWindow(TEXT("combobox"), NULL, WS_CHILD | WS_VISIBLE |
			CBS_DROPDOWN, 130, 10, 100, 200, hWnd, (HMENU)ID_COMBOBOX, g_hInst, NULL);
		for (int i = 0; i<4; i++) {
			SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)Items[i]);
		}
		SendMessage(hCombo, CB_SETCURSEL, (iCurrentPenWidth/3)-1, 0);
		return 0;

콤보박스를 hCombo 핸들에 넣는다.

Items[0]에 텍스트를 넣는다 i가 3dl 될때까지 총 4회 반복

WM_COMMAN

	case WM_COMMAND:
		switch (LOWORD(wParam)) {//1
        	case ID_COMBOBOX:
			switch (HIWORD(wParam)) {//2
			case CBN_SELCHANGE://3
				iCurrentPenWidth=(SendMessage(hCombo, CB_GETCURSEL, 0, 0) + 1) * 3;//4
				//SetFocus(hWnd);//5
				break;
			case CBN_EDITCHANGE://6
				GetWindowText(hCombo, str, 128);
				iCurrentPenWidth = _ttoi(str);
				//SetFocus(hWnd);
				break;
			}
		}

부모 윈도우(메인 윈도우)에게 자식 윈도우(COMBOBOX)가 명령을 전달하는 내용이다

1. 부모윈도우에게 보낼 메시지

2. 자식 윈도우에서 일어나는 이벤트

3. 콤보박스(자식 윈도우)이벤트 - 셀 바꾸기

4. 콤보박스 셀이 바뀌면 전역 변수 iCurrentPenWidth의 정수를 (커서의 인덱스 값+1)*3으로 바꾼다

5. 콤보박스 이벤트 - 에디터 텍스트 변경

7. GetWindowText()함수는 CWnd 갭션 타이틀을 복사하는 것으로 CWnd 객체가 컨트롤이면 컨트롤 안에 있는 텍스트를 복사한다. 복사해서 str에 넣는다.

8. iCurrentPenWidth에 str의 값을 텍스트를 정수로 변환해준다.

9. 에디트의 텍스트를 입력하면 포커스를 바꿔준다. 숫자를 1개만 쳐도 포커스가 이동 됌 밑에서 해결

LBUTTONDOWN

case WM_LBUTTONDOWN:
		SetFocus(hWnd);
		x=LOWORD(lParam);
		y=HIWORD(lParam);
		lines[iLines].pColor =iCurrentPenColor ;
		lines[iLines].pWidth =iCurrentPenWidth;
		lines[iLines].p[lines[iLines].iCount].x = x;
		lines[iLines].p[lines[iLines].iCount].y = y;
		lines[iLines].iCount++; 
		return 0;

SetFocus(hWnd)

-메인 윈도우로 포커스 변경 컨트롤을 사용해서 바뀐 포커스를 메인 윈도우로 옮겨준다.

-대화상자를 쓰면 이렇게 포커스를 임의로 바뀌 줄 필요가 없다. 다음 시간에는 대화상자에 대해 배운다.

 

 

반응형
반응형

컨트롤

컨트롤이란 사용자와 인터페이스를 이루는 도구(작은 윈도우)이다.
컨트롤의 의미를 한마디로 설명하기는 힘들지만 "버튼, 에디트, 리스트 박스, 스크롤 바 등을 뭉뚱그려 컨트롤이라고 한다"

대표적 컨트롤
윈도우 클래스 컨트롤
button 버튼, 체크, 라디오
static 텍스트
scrollbar 스크롤 바
edit 에디트
listbox 리스트 박스
combobox 콤보 박스

CreateWindow 함수의 첫 번째 인수를 클래스 이름만 주면 해당 컨트롤을 만들 수 있다.

 

Button

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	switch (iMessage) {
	case WM_CREATE:
		CreateWindow(TEXT("button"),TEXT("Click Me"),WS_CHILD | WS_VISIBLE | 
			BS_PUSHBUTTON,20,20,100,25,hWnd,(HMENU)0,g_hInst,NULL); 
		CreateWindow(TEXT("button"),TEXT("Me Two"),WS_CHILD | WS_VISIBLE | 
			BS_PUSHBUTTON,20,50,100,25,hWnd,(HMENU)1,g_hInst,NULL); 
		return 0;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {//컨트롤 ID
		case 0:
			MessageBox(hWnd,TEXT("First Button Clicked"),TEXT("Button"),MB_OK);
			break;
		case 1: 
			MessageBox(hWnd,TEXT("Second Button Clicked"),TEXT("Button"),MB_OK);
			break;
		}
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

WM_CREATE

1, 2.  CreateWindow( 1. TEXT("button"), 2. TEXT("Click Me"), 3. WS_CHILD | WS_VISIBLE | 
                           BS_PUSHBUTTON,  4. 20, 5. 20, 6. 100, 7. 25, 8. hWnd, 9. (HMENU)0, 10. g_hInst,NULL);

1. "button" 윈도우 클래스명

2. "Click Me" 버튼에 나타나는 텍스트

3. 세 번째 인수는 윈도우 속성 값이다. WS_CHILD함수는 필수로 주고 WS_VISIBLE 스타일을 주어야 ShowWindow 함수 없이 컨트롤이 화면에 나온다. 그 외에 컨트롤에 고유한 스타일을 추가한다. 버튼의 스타일의 값은 BS이다.

여기서는 푸시 버튼 BS_PUSHBUTTON을 지정했다.

4~7. 까지 인수는 모두 위치이다. 4=x, 5=y, 6=폭 7=높이

8. 부모 윈도를 지정한다. 이 프로그램의 부모는 메인 윈도우 hWnd이다. 

9. 윈도우의 ID이다.

10. 인스턴스 핸들 hlnstance의 사본인 g_hlnst를 받는다.

WM_COMMAND

LOWORD(wParam)을 통해 위에서 지정한 ID를 받아온다

MessageBox(hWnd,TEXT("First Button Clicked"),TEXT("Button"),MB_OK);
"Fisrt Button Clicked" 메시지 박스에서 출력하는 메시지

"Button" 메시지 박스 캡션

MB_OK 확인 키

버튼을 눌렀을 때 모습

라디오 버튼

V.Radio Button

typedef struct _line {
	POINT p[500];
	int iCount;
	COLORREF pColor;
} line;

line lines[1000];
int iLines;
enum { ID_R1, ID_R2, ID_R3};//라디오 버튼아이디
HWND r1, r2, r3; //라디오 버튼  핸들
COLORREF iCurrentPenColor = RGB(255, 0, 0);

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	static int x;
	static int y;
	//static BOOL bNowDraw=FALSE;
	HPEN hPen;
	switch (iMessage) {
	case WM_CREATE://윈도우 생성되기 직전에 한번만 실행되는 메시지
		CreateWindow(TEXT("button"), TEXT("Color"), WS_CHILD | WS_VISIBLE |
			BS_GROUPBOX/*테두리*/, 5, 5, 120, 110, hWnd, (HMENU)0, g_hInst, NULL);
		r1 = CreateWindow(TEXT("button"), TEXT("Red"), WS_CHILD | WS_VISIBLE |
			BS_AUTORADIOBUTTON | WS_GROUP,
			10, 20, 100, 30, hWnd, (HMENU)ID_R1, g_hInst, NULL);
		r2 = CreateWindow(TEXT("button"), TEXT("Green"), WS_CHILD | WS_VISIBLE |
			BS_AUTORADIOBUTTON,
			10, 50, 100, 30, hWnd, (HMENU)ID_R2, g_hInst, NULL);
		r3 = CreateWindow(TEXT("button"), TEXT("Blue"), WS_CHILD | WS_VISIBLE |
			BS_AUTORADIOBUTTON,
			10, 80, 100, 30, hWnd, (HMENU)ID_R3, g_hInst, NULL);
		CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R1);
		return 0;
	case WM_COMMAND:
		switch (LOWORD(wParam)){
			case IDM_RED:
			case ID_R1:
				iCurrentPenColor = RGB(255, 0, 0); 
				CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R1);
				break;
			case IDM_GREEN:
			case ID_R2:
				iCurrentPenColor = RGB(0, 255, 0);
				CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R2);
				break;
			case IDM_BLUE:
			case ID_R3:
				iCurrentPenColor = RGB(0, 0, 255);
				CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R3);
				break;
		}
		return 0;
	case WM_INITMENU:
		if (iCurrentPenColor == RGB(255, 0, 0)){
			CheckMenuItem((HMENU)wParam, IDM_RED, MF_BYCOMMAND | MF_CHECKED);
			CheckMenuItem((HMENU)wParam, IDM_GREEN, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_BLUE, MF_BYCOMMAND | MF_UNCHECKED);
		}
		else if (iCurrentPenColor == RGB(0, 255, 0)){
			CheckMenuItem((HMENU)wParam, IDM_RED, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_GREEN, MF_BYCOMMAND | MF_CHECKED);
			CheckMenuItem((HMENU)wParam, IDM_BLUE, MF_BYCOMMAND | MF_UNCHECKED);
		}
		else if (iCurrentPenColor == RGB(0, 0, 255)){
			CheckMenuItem((HMENU)wParam, IDM_RED, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_GREEN, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_BLUE, MF_BYCOMMAND | MF_CHECKED);
		}
		return 0;
	case WM_KEYDOWN:
		switch (wParam) {
		case VK_BACK:
			if(iLines>0) 
				iLines--;
			InvalidateRect(hWnd, NULL, TRUE);
			break;
		}
		return 0;
	case WM_LBUTTONDOWN:
		x=LOWORD(lParam);
		y=HIWORD(lParam);
		lines[iLines].iCount = 0;
		lines[iLines].pColor = iCurrentPenColor;
		lines[iLines].p[lines[iLines].iCount].x = x;
		lines[iLines].p[lines[iLines].iCount].y = y;
		lines[iLines].iCount++;
		return 0;
	case WM_MOUSEMOVE:
		if (wParam & MK_LBUTTON) {
			hdc=GetDC(hWnd);
			hPen = CreatePen(PS_SOLID, 3, iCurrentPenColor);
			hPen=(HPEN)SelectObject(hdc, hPen);
			MoveToEx(hdc,x,y,NULL);
			x=LOWORD(lParam);
			y=HIWORD(lParam);
			lines[iLines].p[lines[iLines].iCount].x = x;
			lines[iLines].p[lines[iLines].iCount].y = y;
			lines[iLines].iCount++;
			LineTo(hdc,x,y);
			DeleteObject(SelectObject(hdc, hPen));
			ReleaseDC(hWnd,hdc);
		}
		return 0;
	case WM_LBUTTONUP:
		iLines++;
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		for (int i = 0; i < iLines; i++)
		{
			hPen = CreatePen(PS_SOLID, 3, lines[i].pColor);
			hPen = (HPEN)SelectObject(hdc, hPen); 
			MoveToEx(hdc, lines[i].p[0].x, 
					lines[i].p[0].y, NULL);
			for (int j = 0; j < lines[i].iCount; j++)
			{
				LineTo(hdc, lines[i].p[j].x,
					lines[i].p[j].y);
			}
			DeleteObject(SelectObject(hdc, hPen)); 
		}
		return 0;
	case WM_LBUTTONDBLCLK:
		InvalidateRect(hWnd, NULL, TRUE);
		return 0;
	case WM_RBUTTONDOWN:
		SetFocus(hWnd); //작업 영역을 메인 윈도우로 바꾼다
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

전역 변수 자료구조

enum { ID_R1, ID_R2, ID_R3};//라디오 버튼아이디
HWND r1, r2, r3; //라디오 버튼 핸들

WM_CREATA

case WM_CREATE://윈도우 생성되기 직전에 한번만 실행되는 메시지
		CreateWindow(TEXT("button"), TEXT("Color"), WS_CHILD | WS_VISIBLE |
			BS_GROUPBOX/*테두리*/, 5, 5, 120, 110, hWnd, (HMENU)0, g_hInst, NULL);
		r1 = CreateWindow(TEXT("button"), TEXT("Red"), WS_CHILD | WS_VISIBLE |
			BS_AUTORADIOBUTTON | WS_GROUP,
			10, 20, 100, 30, hWnd, (HMENU)ID_R1, g_hInst, NULL);
		r2 = CreateWindow(TEXT("button"), TEXT("Green"), WS_CHILD | WS_VISIBLE |
			BS_AUTORADIOBUTTON,
			10, 50, 100, 30, hWnd, (HMENU)ID_R2, g_hInst, NULL);
		r3 = CreateWindow(TEXT("button"), TEXT("Blue"), WS_CHILD | WS_VISIBLE |
			BS_AUTORADIOBUTTON,
			10, 80, 100, 30, hWnd, (HMENU)ID_R3, g_hInst, NULL);
		
		CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R1);
		return 0;

원도우 생성되기 직전에 한 번만 실행되는 메시지

1. CreateWindow(TEXT("button"), TEXT("Color"), WS_CHILD | WS_VISIBLE | BS_GROUPBOX, 5, 5, 120, 110, hWnd, (HMENU)0, g_hInst, NULL)는 테두리를 만드는 함수 BS_GROUPBOX는 테두리를 그린다

 

2. r1 = CreateWindow(TEXT("button"), TEXT("Red"), WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP, 10, 20, 100, 30, hWnd, (HMENU)ID_R1, g_hInst, NULL)윈도우 핸들에 저장한다. 이 프로그램에서는 꼭 저장할 필요는 없다. BS_AUTORADIOBUTTON 스타일은 자동 라디오 버튼이다.

WM_COMMAND

case WM_COMMAND:
		switch (LOWORD(wParam)){
			case IDM_RED:
			case ID_R1:
				iCurrentPenColor = RGB(255, 0, 0); 
				CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R1);
				break;
			case IDM_GREEN:
			case ID_R2:
				iCurrentPenColor = RGB(0, 255, 0);
				CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R2);
				break;
			case IDM_BLUE:
			case ID_R3:
				iCurrentPenColor = RGB(0, 0, 255);
				CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R3);
				break;
		}
		return 0;

차일드 컨트롤은 WM_COMMAND를 통해 부모 윈도에게 메시지를 보낸다.

1. LOWORD(wParam)은 ID값을 보내준다.

2. 선택한 ID가 IDM_RED or ID_R1이면 iCurrentPenColor의 색상은 빨간 라디오 버튼은 ID_R1이 설정된다.

WM_INITMENU

case WM_INITMENU:
		if (iCurrentPenColor == RGB(255, 0, 0)){
			CheckMenuItem((HMENU)wParam, IDM_RED, MF_BYCOMMAND | MF_CHECKED);
			CheckMenuItem((HMENU)wParam, IDM_GREEN, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_BLUE, MF_BYCOMMAND | MF_UNCHECKED);
		}
		else if (iCurrentPenColor == RGB(0, 255, 0)){
			CheckMenuItem((HMENU)wParam, IDM_RED, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_GREEN, MF_BYCOMMAND | MF_CHECKED);
			CheckMenuItem((HMENU)wParam, IDM_BLUE, MF_BYCOMMAND | MF_UNCHECKED);
		}
		else if (iCurrentPenColor == RGB(0, 0, 255)){
			CheckMenuItem((HMENU)wParam, IDM_RED, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_GREEN, MF_BYCOMMAND | MF_UNCHECKED);
			CheckMenuItem((HMENU)wParam, IDM_BLUE, MF_BYCOMMAND | MF_CHECKED);
		
		}
		return 0;

메뉴를 클릭했을 때

- iCurrentPenColor의 색상이 빨강이면 메뉴에 빨강 버튼을 체크/ 파랑 언체크/초록 언체크

백스페이스가 먹히는가?

라디오 버튼을 클릭하고 백스페이스바를 누르면 선이 지워지지 않는다.

그 이유는 위에서 말한 것처럼 컨트롤들도 하나의 작은 윈도우기 때문에 라디오라는 윈도우에 백스페이스 키다운 명령을 보내고 있기 때문이다. 

라디오 박스로 포커스 돼 있는걸 메인 윈도우창으로 다시 가져와야 한다.

WM_RBUTTONDOWN

	case WM_RBUTTONDOWN:
		SetFocus(hWnd); //작업 영역을 메인 윈도우로 바꾼다
		return 0;

SetFocus 함수는 괄호 안의 영역으로 바꿔준다. 우리는 메인 윈도우로 이동해야 되기 때문에 hWnd를 넣는다.

WM_RBUTTONDOWN에 넣는 게 아니라

switch (LOWORD(wParam)){
			case IDM_RED:
			case ID_R1:
				iCurrentPenColor = RGB(255, 0, 0); 
				CheckRadioButton(hWnd, ID_R1, ID_R3, ID_R1);
                SetFocus(hWnd); //작업 영역을 메인 윈도우로 바꾼다
				break;

WM_COMMAND에서 바로 빨간색을 선택하자마자 작업 영역을 바로 윈도우로 바꿔 줄 수도 있다.

ListBox

#define ID_LISTBOX 100
TCHAR *Items[] = { TEXT("Apple"), TEXT("Orange"), TEXT("Melon"), 
TEXT("Grape"), TEXT("Strawberry") };
HWND hList;
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	int i;
	TCHAR str[128];
	switch (iMessage) {
	case WM_CREATE:
		hList=CreateWindow(TEXT("listbox"),NULL,WS_CHILD | WS_VISIBLE | WS_BORDER |
			LBS_NOTIFY,10,10,100,200,hWnd,(HMENU)ID_LISTBOX,g_hInst,NULL);
		for (i=0;i<5;i++) {
			SendMessage(hList,LB_ADDSTRING/*문자열의 번지를 넘겨준다*/,0,(LPARAM)Items[i]);
		}
		SendMessage(hList, LB_SETCURSEL, 0, (LPARAM)Items[i]);//선택한 디폴드 값
		//SendMessage(hList, LB_GETTEXT, i, (LPARAM)str);
		//SetWindowText(hWnd, str); //윈도우 caption에 출력 
		SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE)
        /*커맨드에서 listbox와 selchange선택*/, 0);
		return 0;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {//LOWORD면 어떤 친구가 때렸지는지 어디서이 명령이 왔는지
		case ID_LISTBOX:
			switch (HIWORD(wParam)) { //HIWORD 구체적 어디에 맞았는지 어떤 상황 (통지 메시지)
			case LBN_SELCHANGE:
				i=SendMessage(hList, LB_GETCURSEL,0,0);//현재 선택중인 리스트 박스의 
                인덱스를 리턴
				SendMessage(hList, LB_GETTEXT, i, (LPARAM)str);
				SetWindowText(hWnd, str); //윈도우 caption에 출력
				break;
			}
		}
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

자료구조

#define ID_LISTBOX 100//ID값 저장된공간

TCHAR *Items[] = { TEXT("Apple"), TEXT("Orange"), TEXT("Melon"), 
TEXT("Grape"), TEXT("Strawberry") };
HWND hList;

Items=문자열 변수

hList=윈도우 핸들을 넣는다.

WM_CREATE

case WM_CREATE:
		hList=CreateWindow(TEXT("listbox"),NULL,WS_CHILD | WS_VISIBLE | WS_BORDER |
			LBS_NOTIFY,10,10,100,200,hWnd,(HMENU)ID_LISTBOX,g_hInst,NULL);
		for (i=0;i<5;i++) {
			SendMessage(hList,LB_ADDSTRING/*문자열의 번지를 넘겨준다*/,0,(LPARAM)Items[i]);
		}
		SendMessage(hList, LB_SETCURSEL, 0, (LPARAM)Items[i]);//선택한 디폴드 값
		//SendMessage(hList, LB_GETTEXT, i, (LPARAM)str);
		//SetWindowText(hWnd, str); //윈도우 caption에 출력 
		SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE), 0);
		return 0;

1. hList핸들은 listbox 컨트롤을 가진다.

2. 리스트박스에 Items[0]의 텍스트를 추가 Items[4]까지 반복

3. 처음 시작할 때의 기본 값

4. MAKEPARAM(리스트박스, 사용자에 의해 선택)WM_COMMAND에 인수 강제 전달

WM_COMMAND

case WM_COMMAND:
		switch (LOWORD(wParam)) {//LOWORD면 어떤 친구가 때렸지는지 어디서이 명령이 왔는지
		case ID_LISTBOX:
			switch (HIWORD(wParam)) { //HIWORD 구체적 어디에 맞았는지 어떤 상황 (통지 메시지)
			case LBN_SELCHANGE://1
				i=SendMessage(hList, LB_GETCURSEL,0,0);//2현재 선택중인 리스트 박스의 인덱스를
                리턴
				SendMessage(hList, LB_GETTEXT, i, (LPARAM)str);//3
				SetWindowText(hWnd, str); //4 윈도우 caption에 출력
				break;
			}
		}
인수 설명
HIWORD(wParam) 통지 코드
LOWORD(wParam) 컨트롤의 ID
lParam 메시지를 보낸 차일드 윈도우의 윈도우 핸들

통지 코드란 Listbox가 어떤 상황인지 설명해주는 코드이다. 다시 말해 차일드 컨트롤이 왜 메시지를 보냈는가를 나타내는 값이다.

 

1. 사용자에 의해 선택이 변경되어 메세지를 보냈다

2. 변수 i에 현재 선택된 인덱스를 넣는다

3. 선택되서 읽어온 인덱스의 값을 str문자열에 넣는다.

4. 윈도우캡션을 str문자열로 바꾼다.

COMBOBOX

#define ID_COMBOBOX 100
TCHAR *Items[]={TEXT("Apple"),TEXT("Orange"),TEXT("Melon"),TEXT("Grape"),
	TEXT("Strawberry")};
HWND hCombo;
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	int i;
	TCHAR str[128];
	switch (iMessage) {
	case WM_CREATE:
		hCombo=CreateWindow(TEXT("combobox"),NULL,WS_CHILD | WS_VISIBLE | 
			CBS_DROPDOWN,10,10,100,200,hWnd,(HMENU)ID_COMBOBOX,g_hInst,NULL);
		for (i=0;i<5;i++) {
			SendMessage(hCombo,CB_ADDSTRING,0,(LPARAM)Items[i]);
		}
		return 0;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case ID_COMBOBOX:
			switch (HIWORD(wParam)) {
			case CBN_SELCHANGE:
				i=SendMessage(hCombo, CB_GETCURSEL,0,0);
				SendMessage(hCombo, CB_GETLBTEXT, i, (LPARAM)str);
				SetWindowText(hWnd, str);
				break;
			case CBN_EDITCHANGE:
				GetWindowText(hCombo, str, 128);
				SetWindowText(hWnd,str);
				break;
			}
		}
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

콤보박스를 만드는 것은 리스트 박스와 비슷하다.

비슷한 구조에서 컨트롤 선언, 스타일, 메시지 등만 바꿔주면 된다. 

 

반응형

+ Recent posts