지난번 UnitTool Part1에서 이어서 진행을 하려고한다.
오브젝트한테 필요한 정보는 어떤 것이 있을까?
우선 오브젝트의 이름이 필요하다.
그리고 공격력 방어력 등의 수치와 현재 어떤 아이템을 가지고 있는지 등이 필요할 수도 있다.
그래서 다음과 같이 리소스 뷰를 설정 해놓는다.(리소스 뷰를 꾸미는 것은 자유!!)


변수 추가를 통해서 이름, 공격력, 방어력 등의 변수를 추가해준다.

Radio Button과 CheckBox는 따로 배열로 만들어 주었다.
여기까지 진행이 완료되었으면, 이제 위의 정보를 담을 구조체가 하나 필요하므로,
추가한 변수를 넣을 구조체를 하나 만들어준다.
typedef struct tagUnitInfo
{
CString strName;
int iAttack;
int iDef;
BYTE byJop;
BYTE byItem;
}UNITINFO;
구조체까지 정의하였으면, 이제 UnitInfo의 정보를 담을 공간이 필요하다.
UnitInfo를 확인해보면 오브젝트 각각의 이름과 공격력 방어력 등이 있다.
여기서 오브젝트 각각의 이름은 Key 값 그 외 정보들(UnitInfo)는 Value라고 생각하면된다.
여기까지 생각해보았을 때 Key와 Value를 담을 공간, 즉 map 컨테이너를 사용하는 것이다.
다음과 같이 map 컨테이너의 변수를 하나 만들어준다.
private:
map<CString, UNITINFO*> m_mapUnitInfo;
그리고 Add 버튼에 클릭 이벤트를 추가해준다.

추가를 하고나서 해당 이벤트 함수에 다음과 같이 코드를 작성한다.
UpdateData(TRUE);
auto& iter_find = m_mapUnitInfo.find(m_strName);
if (iter_find != m_mapUnitInfo.end())
return;
UNITINFO* pUnit = new UNITINFO;
pUnit->strName = m_strName;
pUnit->iAttack = m_iAttack;
pUnit->iDef = m_iDef;
pUnit->byJop = 0;
pUnit->byItem = 0;
for (int i = 0; i < 3; ++i)
{
if (m_Jop[i].GetCheck())
{
pUnit->byJop = i;
break;
}
}
if (m_CheckBox[0].GetCheck())
pUnit->byItem |= SWORD;
if (m_CheckBox[1].GetCheck())
pUnit->byItem |= BOW;
if (m_CheckBox[2].GetCheck())
pUnit->byItem |= SPEAR;
m_mapUnitInfo.emplace(pUnit->strName, pUnit);
m_ListBox.AddString(m_strName);
UpdateData(FALSE);
간단하게 설명하자면,
Add 버튼을 클릭하였을 때 리스트 박스에 있는 오브젝트 이름과 같은 이름이 있을 경우
새로운 정보 추가가 되지않도록 예외 처리를 해주었다.
만약 같은 이름이 추가가 되면 나중에 저장을 하였을 때 혼동이 찾아올 수도 있기 때문이다.
아래 GetCheck()라는 함수는 UnitTool에서 해당 체크박스를 체크하였는지 안했는지 여부를 가져오는 함수이다.
여기까지 하였으면 정보를 입력하고 Add 버튼을 눌렀을 때 다음과 같이 ListBox에 추가가 된 것을 볼 수 있다.

하지만 리스트에서 추가된 오브젝트를 클릭하였을 때 저장된 정보가 확인되지 않는다.
그래서 이제 리스트에 추가된 오브젝트를 클릭하면 이전에 만들었을때의 정보를 불러오게 하려고 한다.
우선 리소스뷰에서 리스트 박스를 클릭하고 다음과 같이 이벤트 처리기를 추가해준다.

추가한 이벤트 함수에 다음과 같이 정의한다.
UpdateData(TRUE);
int iIndex = m_ListBox.GetCurSel();
if (LB_ERR == iIndex)
return;
CString strfindName;
m_ListBox.GetText(iIndex, strfindName);
auto& iter_Find = m_mapUnitInfo.find(strfindName);
if (iter_Find == m_mapUnitInfo.end())
return;
for (int i = 0; i < 3; ++i)
{
m_Jop[i].SetCheck(FALSE);
m_CheckBox[i].SetCheck(FALSE);
}
m_strName = iter_Find->second->strName;
m_iAttack = iter_Find->second->iAttack;
m_iDef = iter_Find->second->iDef;
m_Jop[iter_Find->second->byJop].SetCheck(TRUE);
if (iter_Find->second->byItem & SWORD)
m_CheckBox[0].SetCheck(TRUE);
if (iter_Find->second->byItem & BOW)
m_CheckBox[1].SetCheck(TRUE);
if (iter_Find->second->byItem & SPEAR)
m_CheckBox[2].SetCheck(TRUE);
UpdateData(FALSE);
위와 같이 정의한 후 실행을 시켜보면 다음과 같이 추가된 정보를 확인할 수 있게된다.

여기서 오브젝트를 추가할 때 아무런 직업도 선택을 안할경우,
제일 첫번째에 있는 직업으로 자동으로 저장이 되도록 하였다.
이제 오브젝트 추가에 대한 것을 끝났으니 리스트에 있는 오브젝트를 삭제하는 것을 추가해보자.
이전과 같이 버튼을 추가하고 클릭 이벤트 처리기 함수를 하나 만들어준다.

그 다음 해당 이벤트 함수에 다음과 같이 정의한다.
UpdateData(TRUE);
int iIndex = m_ListBox.GetCurSel();
if (LB_ERR == iIndex)
return;
CString wstrName;
m_ListBox.GetText(iIndex, wstrName);
auto& iter_find = m_mapUnitInfo.find(wstrName);
if (m_mapUnitInfo.end() == iter_find)
return;
Safe_Delete(iter_find->second);
m_mapUnitInfo.erase(wstrName);
m_ListBox.DeleteString(iIndex);
UpdateData(FALSE);
위와같이 정의하였으면 다음과 같이 리스트에 있는 오브젝트의 정보를 Delete버튼을 클릭하여 삭제가 가능하게된다.

마지막으로 오브젝트를 추가한 상태로 프로그램을 종료시켰을 때 메모리 누수가 생기게될 것이다.
이유는 map 컨테이너에 원소를 추가만 한 상태로 종료를 해서 그렇다.
그러므로 소멸자 부분에 다음과 같이 메모리 누수가 생기지 않도록 map 컨테이너를 비워줘야한다.
for (auto& rPair : m_mapUnitInfo)
{
if (rPair)
{
delete rPair;
rpair = nullptr;
}
}
m_mapUnitInfo.clear();
여기까지 오브젝트의 정보 추가와 삭제를 해보았고,
다음에는 ListBox에 추가한 오브젝트를 저장 및 불러오기를 해보려고 한다.
'Programming > MFC' 카테고리의 다른 글
MFC - 프로젝트 세팅 (0) | 2020.12.09 |
---|---|
MFC - UnitTool Part3(저장 및 불러오기) (0) | 2020.12.05 |
MFC - 미니맵 (1) | 2020.11.29 |
MFC - UnitTool Part1(기본 구성), 이벤트 처리기 (0) | 2020.11.29 |
MFC - 기본 이론 , 계층 구조 (0) | 2020.11.29 |