티스토리 뷰

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개 매서드로 진행한다.
 
HWND WINAPI CreateDialog(
_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와 똑같다고 생각하면된다. 핸들을 반환한다.
 
화면에 보여주기 위한 코드도 작성해야한다.
  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)
 
HWND SetFocus(
  HWND hWnd
);
 
이제 이 뷰와 맞는 모델을 만들어야한다.
 
추가 버튼 누르면 추가되게.
 
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;
}
댓글
댓글쓰기 폼