190627(4일차) - 다이얼로그 윈도우, 자식윈도우, 컨트롤
교육을 받으면서 노트필기 했던 내용을 날것 그대로 업로드합니다.
다이얼로그윈도우
-
자식윈도우
-
컨트롤
-
응용 프로그램
메뉴 클릭시 WM_COMMAND 가 발생된다.
wParam의 LOWORD에서 어떤 메뉴가 눌렸는지 알 수 있다.
프로시저(핸들러) : 메세지를 처리하는 함수
MVVM : 모델뷰 뷰모델
현윈도우 외 다른 영역에서 마우스가 떼졌을 때 좌표가 필요하다면, 마우스캡쳐가 필요하다.
SetCapture(①); //DOWN메세지에서
①: 어떤 윈도우가 캡쳐받을 건지 (hwnd 등)
ReleaseCapture(); //UP메세지에서
이 때 우리가 하는 실습 네모그리기에서 화면 밖 영역에서 마우스를 놓게되면, 마이너스 값을 갖게된다.
8비트 였던 LO,HI워드를 16비트로 변환시 마이너스 값이 었을 경우 엄청 큰 양수값으로 읽힐 수 있다. 따라서 음수였다는 것을 알려주어야한다.
-
GetDlgItemInt(hwnd, IDC_EDIT1, NULL, TRUE);
-
대화 상자의 지정된 컨트롤의 텍스트를 정수 값으로 변환합니다.부모 윈도우의 핸들과 자식의 아이디를 주면 핸들을 얻어올 수 있다.
UINT GetDlgItemInt(
HWND hDlg,
int nIDDlgItem,
BOOL *lpTranslated,
BOOL bSigned
);
싱크 : 뷰와 데이터
WPF:바인딩
WM_INITDIALOG (View에 데이터 값을 올리자. 싱크를 맞추자)
SetDlgItemInt(hwnd, IDC_EDIT1, dx, TRUE);
Data WR
GetWindowText()
SetWindowText()
일반적으로 컨트롤의 데이터를 W,R하는 함수는 SetDlgItem이라는 단어가 붙는다.
SetDlgItemText()
SetDlgItemInt()
또는 Get 이 있다.
부모의 핸들얻어오는 함수 : GetParent()
자식의 핸들얻어오는 함수 : GetDlgItem()
[dialog3 프로젝트]
모달리스 다이얼로그를 만들어보자.
기본적으로 확인, 취소 버튼이 없다.
떠 있는 상태에서도 처리를 해야한다.
CreateDialog()
DestroyWindow()
생성과 삭제는 위 2개 매서드로 진행한다.
_In_opt_ HINSTANCE hInstance,
_In_ LPCTSTR lpTemplate,
_In_opt_ HWND hWndParent,
_In_opt_ DLGPROC lpDialogFunc
);
hDlgLess = CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_DIALOG2), hwnd, DlgLessProc)
CreateWindow와 똑같다고 생각하면된다. 핸들을 반환한다.
화면에 보여주기 위한 코드도 작성해야한다.
BOOL ShowWindow(
HWND hWnd,
int nCmdShow
);
ShowWindow(hDlgLess, SW_SHOW);
WM_DESTROY 이전에 WM_CLOSE 가 발생한다. X버튼 눌렀을 때 사실 WM_CLOSE가 발생된다.
WM_CLOSE 호출이후 DESTROY메세지가 발생하는 것이다.
또 띄우기를 했을 때 새로 띄우는 것이 아니라 포커싱만 다시 주어야한다.
if (!IsWindow(hDlgLess)) if(hDlgLess==NULL) 다이얼로그 생성
else SetFocus(hDlgLess)
이제 이 뷰와 맞는 모델을 만들어야한다.
추가 버튼 누르면 추가되게.
Document View : 옵저버 패턴
전역변수를 쓰지 않고 실제로 맵을 쓴다. 키값을 주면 벨류 값을 얻어올 수 있도록한다.
InvalidateRect(GetParent(hwnd), NULL, TRUE);
오후 3:19 2019-06-27
Listbox
자식, 부모 send 메세지로 통신한다.
hListBox = GetDlgItem(hwnd, IDC_LIST1);
SendMessage(hListBox, LB_ADDSTRING, NULL, (LPARAM)_T("AAA") );
ex180316 과 같은 예제를 공부함
시험 : 월요일.
#include <windows.h>
#include <TCHAR.H>
#include <vector>
#include "resource.h"
using namespace std;
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK DlgLessProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam);
HINSTANCE g_hInst;
int dx = 100, dy = 100;
vector<RECT> rtList;
int selected = -1;
HWND hMainWnd;
HWND hDlgLess; // 모달리스 다이얼로그 핸들
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
g_hInst = hInstance;
HWND hwnd;
MSG msg;
WNDCLASS WndClass;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
WndClass.lpszClassName = _T("Window Class Name");
RegisterClass(&WndClass);
hwnd = CreateWindow(_T("Window Class Name"),
_T("Window Title Name"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// 사각형 그리기
void DrawRect(HDC hdc, const RECT& rt, bool selected)
{
HPEN hNewPen, hOldPen;
if (selected) // 선택된 사각형 인덱스는 빨간색으로 그린다.
{
hNewPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
hOldPen = (HPEN)SelectObject(hdc, hNewPen);
}
else
{
hNewPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
hOldPen = (HPEN)SelectObject(hdc, hNewPen);
}
Rectangle(hdc, rt.left, rt.top, rt.right, rt.bottom);
SelectObject(hdc, hOldPen);
DeleteObject(hNewPen);
}
// 리스트 박스 갱신
void UpdateListBox()
{
if (IsWindow(hDlgLess)) // 모달레스 창이 존재하면.
{
HWND hListBox = GetDlgItem(hDlgLess, IDC_LIST1); // 리스트 박스핸들을 받아온다.
SendMessage(hListBox, LB_RESETCONTENT, 0, 0); // 리스트 박스를 리셋한다.
for (unsigned i = 0; i < rtList.size(); ++i) // rtList사이즈 만큼 반복
{
const RECT& rt = rtList[i];
TCHAR buf[500];
wsprintf(buf, _T("R:(%d,%d - %d,%d)"),
rt.left, rt.top, rt.right, rt.bottom); // 사각형 정보에 대한 문자열 버프를 작성하고
SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)buf); // 문자열을 추가하라고 메세지를 보낸다.
}
}
}
// 사각형이 수정되면 리스트를 갱신한다.
void UpdateRectList()
{
//1. view 갱신 (화면 갱신)
InvalidateRect(hMainWnd, NULL, TRUE);
//2. view 갱신 (데이터 갱신)
UpdateListBox();
}
// 사각형들을 전부 이동시킨다.
void MoveRectList(vector<RECT>& rtList, int dx, int dy)
{
for (unsigned i = 0; i < rtList.size(); ++i)
{
RECT& rt = rtList[i];
rt.left += dx;
rt.right += dx;
rt.top += dy;
rt.bottom += dy;
}
UpdateRectList();// 사각형이 수정되면 리스트를 갱신한다.
}
// 사각형을 추가한다.
void AddRectList(vector<RECT>& rtList, const RECT& rt)
{
rtList.push_back(rt);
UpdateRectList();
}
// 사각형을 삭제한다.
void RemoveRectList(vector<RECT>& rtList, int idx)
{
rtList.erase(rtList.begin() + idx);
selected = -1; // 삭제하고 나서는 인덱스를 -1로 설정한다.
UpdateRectList();
}
// 윈도우 프로시저
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam)
{
static RECT rt;
HDC hdc;
PAINTSTRUCT ps;
switch (iMsg)
{
case WM_CREATE:
hMainWnd = hwnd;
break;
case WM_LBUTTONDOWN:
SetCapture(hwnd); // 바깥쪽 마우스도 캡쳐하기 위해서
rt.left = LOWORD(lParam);
rt.top = HIWORD(lParam);
break;
case WM_LBUTTONUP:
ReleaseCapture(); // 바깥쪽 마우스도 캡쳐하기 위해서
rt.right = (short)LOWORD(lParam);
rt.bottom = (short)HIWORD(lParam);
AddRectList(rtList, rt);
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
for (unsigned i = 0; i < rtList.size(); ++i)
{
if (i == selected)
DrawRect(hdc, rtList[i], true); // 선택된 것이면 true전달
else
DrawRect(hdc, rtList[i], false);
}
EndPaint(hwnd, &ps);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_INFO: // 리스트 박스가 있는 메뉴 선택시 다이얼로그생성
if (!IsWindow(hDlgLess))
{
hDlgLess = CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_DIALOG2), hwnd, DlgLessProc); // 프로시저 등록
ShowWindow(hDlgLess, SW_SHOW);
}
else
SetFocus(hDlgLess); // 이미 생성되어 있으면 포커스만 준다.
break;
case ID_MOVE:
if (IDOK == DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), hwnd, DlgProc)) // 이동하는 대화상자 생성
{ // 모달 다이얼로그
MoveRectList(rtList, dx, dy);
InvalidateRect(hwnd, NULL, TRUE);// 받아온 좌표로 다시 그린다.
}
else
MessageBox(hwnd, _T("확인 Cancel"), _T("확인"), MB_OK);
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
// 이동시키는 대화상자 (모달) 프로시저
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam)
{
switch (iMsg)
{
case WM_INITDIALOG:
SetDlgItemInt(hwnd, IDC_EDIT1, dx, TRUE);
SetDlgItemInt(hwnd, IDC_EDIT2, dy, TRUE); // dx와 dy로 값을 설정한다.
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK: // OK 버튼 클릭시
dx = GetDlgItemInt(hwnd, IDC_EDIT1, NULL, TRUE);
dy = GetDlgItemInt(hwnd, IDC_EDIT2, NULL, TRUE); // 좌표 값을 받아온다.
EndDialog(hwnd, IDOK); // 다이얼로그 종료
break;
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);// 다이얼로그 종료
break;
}
break;
}
return FALSE;
}
// 리스트 박스가 있는 대화상자(모달리스) 프로시저
INT_PTR CALLBACK DlgLessProc(HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam)
{
static RECT addRect = { 100,100,200,200 };
switch (iMsg)
{
case WM_INITDIALOG:
hDlgLess = hwnd;
SetDlgItemInt(hwnd, IDC_EDIT1, addRect.left, TRUE);
SetDlgItemInt(hwnd, IDC_EDIT2, addRect.top, TRUE);
SetDlgItemInt(hwnd, IDC_EDIT3, addRect.right, TRUE);
SetDlgItemInt(hwnd, IDC_EDIT4, addRect.bottom, TRUE); // 아이템 설정
UpdateListBox(); // 리스트 박스를 최신거로 갱신한다.
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_LIST1: // 리스트 박스에서 발생되는 이벤트 추적
switch (HIWORD(wParam))
{
case LBN_SELCHANGE: // 선택이 변경될 때.
{
HWND hListBox = GetDlgItem(hwnd, IDC_LIST1);
int idx = (int)SendMessage(hListBox, LB_GETCURSEL, 0, 0);
if (idx >= 0)
{
selected = idx; // 선택된 곳을 selected에 대입
InvalidateRect(hMainWnd, NULL, TRUE); // 다시그린다.
}
}
break;
}
break;
case IDC_ADD: // ADD 버튼 클릭시
addRect.left = GetDlgItemInt(hwnd, IDC_EDIT1, NULL, TRUE);
addRect.top = GetDlgItemInt(hwnd, IDC_EDIT2, NULL, TRUE);
addRect.right = GetDlgItemInt(hwnd, IDC_EDIT3, NULL, TRUE);
addRect.bottom = GetDlgItemInt(hwnd, IDC_EDIT4, NULL, TRUE);
AddRectList(rtList, addRect);
InvalidateRect(GetParent(hwnd), NULL, TRUE);
break;
case IDC_DELETE: // 삭제 버튼 클릭시
{
HWND hListBox = GetDlgItem(hwnd, IDC_LIST1);
int idx = (int)SendMessage(hListBox, LB_GETCURSEL, 0, 0); // 선택한 인덱스 가져오기
if (idx >= 0)
{
RemoveRectList(rtList, idx);
}
}
break;
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
}
return FALSE;
}
'Win32(API)' 카테고리의 다른 글
[win32 API] cbClsExtra 등 (0) | 2019.07.03 |
---|---|
[win32 API] DC 그리기 작업, bitmap (0) | 2019.07.02 |
[win32 API] 콜백, Invalid 무효영역 다시그리기 등 (0) | 2019.07.02 |
[win32 api] 기본 동작 개념, 메세지 처리, 프로시저 등 (2) | 2019.07.01 |
[win32 api] EditBox, ListBoc Control (1) | 2018.03.17 |