본문 바로가기
프로그래밍/MFC (C++)

MFC ] 통계자료, 자식 다이얼로그 생성하고 부모 다이얼로그와 상호참조하기

by eteo 2022. 7. 8.

 

리소스뷰 다이얼로그에서 리소스 추가

 

 

 

 

다이얼로그 새로 만들기

 

 

자식 다이얼로그 ID 바꿔주기

 

 

 

자식 다이얼로그의 클래스 추가

 

 

 

 

CNewDlg 라는 이름으로 생성하고 기본 클래스는 CDialogEx가 된다.

 

 

자식 다이얼로그에도 리스트 컨트롤을 만들고 변수 추가

 

 

 

자식 다이얼로그에는 처음 클래스 생성시 생성자, 소멸자, DoDataExchange 함수밖에 없다.

 

필요한 경우 가상함수에서 OnInitDialog와 메시지에서 Ondestroy를 추가한다.

 

부모 다이얼로그 .cpp 파일에서 자식 다이얼로그의 헤더를 추가하고 코드를 작성한다.

 

 

자식 다이얼로그 클래스를 생성하고

자식에게 부모 다이얼로그의 포인터를 넘겨주고

키워드 검색결과가 담긴 벡터를 주소로 넘긴 후 DoModal() 을 호출하여 새 창을 연다.

 

Modal 방식은 새창이 열려있는 동안 계속 그 안에서 루프를 돌기 때문에 데이터를 미리 넘겨서 자식 다이얼로그 OnInit()에서 View 세팅까지 다 마쳐야 한다.

	CNewDlg child;

	child.SetParentPtr(this);
	child.SetListControl(&searchedRows);

	child.DoModal();

 

자식이 부모 다이얼로그에게 다시 데이터를 넘겨주는 부분은 자식창이 닫힐 때 실행되는 OnDestory() 함수 안에서 부모 포인터를 활용해 구현하였다.

 

 

CarAccidentListDlg.h

// CarAccidentListDlg.h: 헤더 파일
//

#pragma once
#include "DataController.h"
#include <string>


using namespace std;

// CCarAccidentListDlg 대화 상자
class CCarAccidentListDlg : public CDialogEx
{
// 생성입니다.
public:
	CCarAccidentListDlg(CWnd* pParent = nullptr);	// 표준 생성자입니다.

// 대화 상자 데이터입니다.
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_CARACCIDENTLIST_DIALOG };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 지원입니다.


// 구현입니다.
protected:
	HICON m_hIcon;

	// 생성된 메시지 맵 함수
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
	DataController DC;
public:
	
	CListCtrl m_list;
	afx_msg void OnBnClickedButtonload();
	CString m_keyword;
	afx_msg void OnBnClickedButtonsearch();
	int selectedIDX;
	afx_msg void OnLvnItemchangedList2(NMHDR* pNMHDR, LRESULT* pResult);
	afx_msg void OnDestroy();
	CListCtrl m_listSubTotal;
	void SetListSubTotal(int* subTotal);
};

 

 

 

CarAccidentListDlg.cpp

// CarAccidentListDlg.cpp: 구현 파일
//

#include "pch.h"
#include "framework.h"
#include "CarAccidentList.h"
#include "CarAccidentListDlg.h"
#include "afxdialogex.h"
#include "CNewDlg.h"



#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 응용 프로그램 정보에 사용되는 CAboutDlg 대화 상자입니다.

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 대화 상자 데이터입니다.
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 지원입니다.

// 구현입니다.
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CCarAccidentListDlg 대화 상자



CCarAccidentListDlg::CCarAccidentListDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_CARACCIDENTLIST_DIALOG, pParent)
	, m_keyword(_T(""))
	, selectedIDX(-1)	
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	
}

void CCarAccidentListDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST2, m_list);
	DDX_Text(pDX, IDC_EDITKEYWORD, m_keyword);
	DDX_Control(pDX, IDC_LISTSUBTOTAL, m_listSubTotal);
}

BEGIN_MESSAGE_MAP(CCarAccidentListDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTONLOAD, &CCarAccidentListDlg::OnBnClickedButtonload)
	ON_BN_CLICKED(IDC_BUTTONSEARCH, &CCarAccidentListDlg::OnBnClickedButtonsearch)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST2, &CCarAccidentListDlg::OnLvnItemchangedList2)
	ON_WM_DESTROY()
END_MESSAGE_MAP()


// CCarAccidentListDlg 메시지 처리기

BOOL CCarAccidentListDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();	

	// 시스템 메뉴에 "정보..." 메뉴 항목을 추가합니다.

	// IDM_ABOUTBOX는 시스템 명령 범위에 있어야 합니다.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 이 대화 상자의 아이콘을 설정합니다.  응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
	//  프레임워크가 이 작업을 자동으로 수행합니다.
	SetIcon(m_hIcon, TRUE);			// 큰 아이콘을 설정합니다.
	SetIcon(m_hIcon, FALSE);		// 작은 아이콘을 설정합니다.

	// TODO: 여기에 추가 초기화 작업을 추가합니다.
	m_list.SetExtendedStyle(
		LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);

	m_list.InsertColumn(0, _T("순서"), LVCFMT_CENTER, 40);
	m_list.InsertColumn(1, _T("시도"), LVCFMT_CENTER, 80);
	m_list.InsertColumn(2, _T("시군구"), LVCFMT_CENTER, 80);
	m_list.InsertColumn(3, _T("터널안"), LVCFMT_CENTER, 70);
	m_list.InsertColumn(4, _T("교량위"), LVCFMT_CENTER, 70);
	m_list.InsertColumn(5, _T("고가도로위"), LVCFMT_CENTER, 70);
	m_list.InsertColumn(6, _T("지하차도(도로)내"), LVCFMT_CENTER, 70);
	m_list.InsertColumn(7, _T("기타단일로"), LVCFMT_CENTER, 70);
	m_list.InsertColumn(8, _T("교차로내"), LVCFMT_CENTER, 70);
	m_list.InsertColumn(9, _T("교차로횡단보도내"), LVCFMT_CENTER, 70);
	m_list.InsertColumn(10, _T("교차로부근"), LVCFMT_CENTER, 70);
	m_list.InsertColumn(11, _T("철길건널목"), LVCFMT_CENTER, 70);
	m_list.InsertColumn(12, _T("기타"), LVCFMT_CENTER, 70);
	m_list.InsertColumn(13, _T("불명"), LVCFMT_CENTER, 70);


	m_listSubTotal.SetExtendedStyle(
		LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);

	m_listSubTotal.InsertColumn(0, _T("시도 또는 시군구"), LVCFMT_CENTER, 100);
	m_listSubTotal.InsertColumn(1, _T("터널안"), LVCFMT_CENTER, 70);
	m_listSubTotal.InsertColumn(2, _T("교량위"), LVCFMT_CENTER, 70);
	m_listSubTotal.InsertColumn(3, _T("고가도로위"), LVCFMT_CENTER, 70);
	m_listSubTotal.InsertColumn(4, _T("지하차도(도로)내"), LVCFMT_CENTER, 70);
	m_listSubTotal.InsertColumn(5, _T("기타단일로"), LVCFMT_CENTER, 70);
	m_listSubTotal.InsertColumn(6, _T("교차로내"), LVCFMT_CENTER, 70);
	m_listSubTotal.InsertColumn(7, _T("교차로횡단보도내"), LVCFMT_CENTER, 70);
	m_listSubTotal.InsertColumn(8, _T("교차로부근"), LVCFMT_CENTER, 70);
	m_listSubTotal.InsertColumn(9, _T("철길건널목"), LVCFMT_CENTER, 70);
	m_listSubTotal.InsertColumn(10, _T("기타"), LVCFMT_CENTER, 70);
	m_listSubTotal.InsertColumn(11, _T("불명"), LVCFMT_CENTER, 70);



	return TRUE;  // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}

void CCarAccidentListDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
//  아래 코드가 필요합니다.  문서/뷰 모델을 사용하는 MFC 애플리케이션의 경우에는
//  프레임워크에서 이 작업을 자동으로 수행합니다.

void CCarAccidentListDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다.
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 아이콘을 그립니다.
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
//  이 함수를 호출합니다.
HCURSOR CCarAccidentListDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}




void CCarAccidentListDlg::OnBnClickedButtonload()
{
	
	DC.loadListFromFile();
	

	CString str;

	m_list.DeleteAllItems();

	for(int i = 0; i < (int)DC.getList().size(); i++)
	{
		str.Format(_T("%d"), i + 1);
		m_list.InsertItem(i, str);
		m_list.SetItem(i, 1, LVIF_TEXT, DC.getList().at(i)->GetSiDo(), NULL, NULL, NULL, NULL);
		m_list.SetItem(i, 2, LVIF_TEXT, DC.getList().at(i)->GetSiGunGoo(), NULL, NULL, NULL, NULL);


		for(int j=0; j < LOCATION_NUMBER; j++)
		{
			str.Format(_T("%d"), DC.getList().at(i)->GetAccidentCount(j));
			m_list.SetItem(i, j+3, LVIF_TEXT, str, NULL, NULL, NULL, NULL);
		}
	}
	
	UpdateData(false);
	
}


void CCarAccidentListDlg::OnBnClickedButtonsearch()
{
		
	UpdateData(true);
	
	vector<Data> searchedRows = DC.searchList(m_keyword);
	
	if(searchedRows.size()==0)
	{
		AfxMessageBox(_T("일치하는 결과가 없습니다"));
		return;
	}

	m_listSubTotal.DeleteAllItems();
	
	CNewDlg child;

	child.SetParentPtr(this);
	child.SetListControl(&searchedRows);

	child.DoModal();	

	m_keyword = "";

	UpdateData(false);

}


void CCarAccidentListDlg::OnLvnItemchangedList2(NMHDR* pNMHDR, LRESULT* pResult)
{
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	*pResult = 0;

	selectedIDX = pNMLV->iItem;
}


void CCarAccidentListDlg::OnDestroy()
{
	if (DC.getList().size() != 0)
	{
		for (int i = 0; i < DC.getList().size(); i++)
		{
			delete DC.getList().at(i);
		}
		DC.getList().clear();
	}
	CDialogEx::OnDestroy();

}


void CCarAccidentListDlg::SetListSubTotal(int* subTotal)
{
	m_listSubTotal.InsertItem(0, m_keyword);
	for (int i = 0; i < LOCATION_NUMBER; i++)
	{
		CString str;
		str.Format(_T("%d"), subTotal[i]);
		m_listSubTotal.SetItem(0, i+1, LVIF_TEXT, str, NULL, NULL, NULL, NULL);
	}
}

 

 

CNewDlg.h

#pragma once
#include <vector>

#include "CarAccidentListDlg.h"
#include "Data.h"


// CNewDlg 대화 상자

class CNewDlg : public CDialogEx
{
	DECLARE_DYNAMIC(CNewDlg)

public:
	CNewDlg(CWnd* pParent = nullptr);   // 표준 생성자입니다.
	virtual ~CNewDlg();

// 대화 상자 데이터입니다.
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_NEWDLG };
#endif

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 지원입니다.

	DECLARE_MESSAGE_MAP()
public:
	CListCtrl m_listChild;
	virtual BOOL OnInitDialog();
	void SetListControl(vector<Data>* searchedRows);
	vector<Data>* searchedRows;
	void SetParentPtr(CCarAccidentListDlg* dlg);
	CCarAccidentListDlg* dlgPtr;

	afx_msg void OnDestroy();
};

 

 

 

CNewDlg.cpp

// CNewDlg.cpp: 구현 파일
//

#include "pch.h"
#include "CarAccidentList.h"
#include "CNewDlg.h"
#include "afxdialogex.h"


// CNewDlg 대화 상자

IMPLEMENT_DYNAMIC(CNewDlg, CDialogEx)

CNewDlg::CNewDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_NEWDLG, pParent)
{

}

CNewDlg::~CNewDlg()
{
}

void CNewDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST1, m_listChild);
}


BEGIN_MESSAGE_MAP(CNewDlg, CDialogEx)
	ON_WM_DESTROY()
END_MESSAGE_MAP()


// CNewDlg 메시지 처리기


BOOL CNewDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// TODO:  여기에 추가 초기화 작업을 추가합니다.

	m_listChild.SetExtendedStyle(
		LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);

	m_listChild.InsertColumn(0, _T("순서"), LVCFMT_CENTER, 40);
	m_listChild.InsertColumn(1, _T("시도"), LVCFMT_CENTER, 80);
	m_listChild.InsertColumn(2, _T("시군구"), LVCFMT_CENTER, 80);
	m_listChild.InsertColumn(3, _T("터널안"), LVCFMT_CENTER, 70);
	m_listChild.InsertColumn(4, _T("교량위"), LVCFMT_CENTER, 70);
	m_listChild.InsertColumn(5, _T("고가도로위"), LVCFMT_CENTER, 70);
	m_listChild.InsertColumn(6, _T("지하차도(도로)내"), LVCFMT_CENTER, 70);
	m_listChild.InsertColumn(7, _T("기타단일로"), LVCFMT_CENTER, 70);
	m_listChild.InsertColumn(8, _T("교차로내"), LVCFMT_CENTER, 70);
	m_listChild.InsertColumn(9, _T("교차로횡단보도내"), LVCFMT_CENTER, 70);
	m_listChild.InsertColumn(10, _T("교차로부근"), LVCFMT_CENTER, 70);
	m_listChild.InsertColumn(11, _T("철길건널목"), LVCFMT_CENTER, 70);
	m_listChild.InsertColumn(12, _T("기타"), LVCFMT_CENTER, 70);
	m_listChild
		.InsertColumn(13, _T("불명"), LVCFMT_CENTER, 70);

	CString str;


	for (int i = 0; i < (int)searchedRows->size(); i++)
	{
		str.Format(_T("%d"), i + 1);
		m_listChild.InsertItem(i, str);
		m_listChild.SetItem(i, 1, LVIF_TEXT, searchedRows->at(i).GetSiDo(), NULL, NULL, NULL, NULL);
		m_listChild.SetItem(i, 2, LVIF_TEXT, searchedRows->at(i).GetSiGunGoo(), NULL, NULL, NULL, NULL);


		for (int j = 0; j < LOCATION_NUMBER; j++)
		{
			str.Format(_T("%d"), searchedRows->at(i).GetAccidentCount(j));
			m_listChild.SetItem(i, j + 3, LVIF_TEXT, str, NULL, NULL, NULL, NULL);
		}
	}

	return TRUE;  // return TRUE unless you set the focus to a control
				  // 예외: OCX 속성 페이지는 FALSE를 반환해야 합니다.
}

void CNewDlg::SetListControl(vector<Data>* searchedRows)
{
	this->searchedRows = searchedRows;
}

void CNewDlg::SetParentPtr(CCarAccidentListDlg* dlg)
{
	// TODO: 여기에 구현 코드 추가.
	this->dlgPtr = dlg;
}


void CNewDlg::OnDestroy()
{
	int subTotal[LOCATION_NUMBER] = {0,};

	for(int i=0 ; i< searchedRows->size() ; i++)
	{
		for(int j=0; j< LOCATION_NUMBER; j++)
		{
			subTotal[j] += searchedRows->at(i).GetAccidentCount(j);
		}
	}

	dlgPtr->SetListSubTotal(subTotal);
	CDialogEx::OnDestroy();

	// TODO: 여기에 메시지 처리기 코드를 추가합니다.
}