MFC 윈도우 GUI 프로그래밍 단기 속성 – 널널한 개발자 TV
https://www.youtube.com/watch?v=VPt69tFR4ww&list=PLXvgR_grOs1BEwuPXc0L7qm_11DeApwKJ&index=1
UI 와 자료 구조는 분리되어야 한다.
# 클래스의 상속 관계에서 생성자 호출은 자식 생성자부터 호출되지만 부모 생성자부터 실행된다.
# 생성자에서는 객체 자신을 초기화하는 작업 외에는 넣지 마라.
CDataA *pA = (CDataA*)new CDataC;
접근형식(참조형식) / 실형식
일반메서드는 파생클래스에서 재정의 하더라도 접근 형식을 따라 간다.
상위 클래스에서 함수를 가상화(virtual 을 붙이면) 시키면 파생 함수도 모두 가상 함수가 된다.
상위 클래스 일반 함수에서 가상 함수를 호출하면 파생 클래스의 함수가 호출 된다.
# Handle (HWND) : 식별자값 또는 포인터
# Document/View 체계
Frame Window (GUI) : Caption, Menu
View (GUI) : 내부 (클라이언트 윈도우)
Document : 자료구조
모든 걸 제어 : main 함수
– 세가지 구조
CMainFrame : GUI
C~~~View : GUI
C~~~Doc : 자료구조
C~~~App : 제어 체계
App -> InitInstance() : 메인함수의 시작으로 간주하자
App -> ExitInstance() : 메인함수의 끝부분
# 메뉴 추가
ID_MY_PAGE_USER_INPUT
이벤트 핸들러 추가
// cpp 파일 상단에 다이얼로그 클래스 파일을 include 시켜준다.
#include "CUserInputDlg.h"
void CMYMFCTEST1View::OnMyPageUserInput()
{
CUserInputDlg dlg;
if (dlg.DoModal() == IDOK)
{
AfxMessageBox(dlg.m_strUrl);
}
}
# 새 다이얼로그 만들기
IDD_DIALOG_USER_INPUT
대화상자 클래스 추가 : CUserInputDlg (기본 클래스 CDialog)
가상 함수 -> OnInitDialog 추가 (초기화 작업)
OK 버튼 이벤트 핸들러 추가
// Control -> Variable // DoDataExchange() 호출 UpdateData();
# 새 다이얼로그에 edit control 추가
IDC_EDIT_URL
변수 추가 : m_strURL
초기화는 생성자에서 한다.
전역 번수를 어디에서 선언하는게 좋을까?
App
Doc
View (교체 가능성 있음)
MainFrame
SDI : 문서 하나 뷰 여러개
MDI : 문서 뷰 1:1
# 전역변수는 App 이나 MainFrame 에 선언하는게 낫다.
# App 클래스에서 -> 변수 추가
CStringArray
m_arURL
public
// DECLARE_MESSAGE_MAP() 이 protected 매크로로 되어 있어서 접근성 오류가 난다.
m_arURL 변수를 public: 으로 위치로 옮겨준다.
다이얼로그 추가
IDD_DIALOG_HISTORY
클래스 추가 : CHistoryDlg (기본클래스 CDialog)
OnInitDialog() 추가 // 대화상자가 초기화되고 나타날 때
BOOL CHistoryDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
for (int i = 0; i < theApp.m_arURL.GetCount(); ++i)
{
m_listURL.AddString(theApp.m_arURL[i]);
}
}
리스트 박스 추가
IDC_LIST_URL
변수 추가 m_listURL
메뉴 History 추가
이벤트 처리기 추가 (글로벌 수준이므로 MainFrame 이 좋겠다.)
(View 클래스, App 클래스, MainFrm 클래스 중에 가장 괜찮은 클래스 선택하자)
전역 변수를 쓰려면 App 클래스나 MainFrm 클래스가 좋다.
void CMainFrame::OnHistory()
{
CHistoryDlg dlg;
dlg.DoModal();
}
# 체크박스 추가
IDC_CHECK_ADD
변수 추가 : 값, m_bAdd
생성자에 FALSE로 되어 있는데 TRUE로 바꿔준다.
버튼이나 체크박스나 모두 버튼이다.
# 에디트 컨트롤
IDC_EDIT_SELECTED_ITEM
READ ONLY : TRUE
BORDER : FALSE
스태틱이랑 모양이 같지만 드래그가와 복붙이 가능해진다.
변수 추가 : m_strSelected (값, CString)
통지 메시지 (차일드 윈도우는 부모 윈도우를 통해서 접근)
리스트 박스 -> 클래스 마법사 -> 명령 -> 리스트박스 ID -> LBN_SELCHANGE (해당 다이얼로그 클래스에)
// 리스트 박스에서 아이템이 선택되면 에디트 컨트롤에 표시
void CHistoryDlg::OnSelchangeList1()
{
int nIndex = m_listURL.GetCurSel();
if (nIndex >= 0)
{
m_listURL.GetText(nIndex, m_strSelected);
UpdateData(FALSE); // 변수 -> 컨트롤
}
}
리스트박스를 지우고 리스트컨트롤 추가
IDC_LIST_URL
View : Report
변수 추가 : m_listURL
초기화 작업은 onInitDialog() 에서..
BOOL CHistoryDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
m_listURL.InsertColumn(0, _T("URL"), LVCFMT_LEFT, 400);
m_listURL.SetExtendedStyle(m_listURL.GetExtendedStyle() |
LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES |
LVS_EX_TRACKSELECT | LVS_EX_UNDERLINEHOT);
for (int i = 0; i < theApp.m_arURL.GetCount(); ++i)
{
m_listURL.InsertItem(i, theApp.m_arURL[i]);
}
return TRUE;
}
// 리스트 컨트롤의 아이템을 선택했을 때 에디트 컨트롤에 접근
void CHistoryDlg::OnLvnItemchangedListUrl(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
CString strTmp = m_listURL.GetItemText(0, 0);
//1. 리소스 ID로 에디트 컨트롤에 접근
//GetDlgItem(IDC_EDIT_SELECTED_ITEM)->SetWindowText(strTmp);
//2. 에디트 컨트롤 변수 추가 (컨트롤)로 접근 (값, 컨트롤 두개를 만들었음)
m_wndEdit.SetWindowText(strTmp);
*pResult = 0;
}
“지원되지 않는 작업을 시도했습니다.” 메시지박스가 뜨면 리소스만 지웠다.
에디트 컨트롤만 지우면 리소스만 지운거지 코드상에는 남아있다.