MFC custom Listcontrol 사용방법

반응형
728x90
반응형
 
Introduction

MFC를 사용하면서 list control을 사용할 때가 많습니다. 이전 포스팅 release 중에 리스트 콘트롤을 사용하는 경우가 종종 있어 이를 사용하기 위해서 조금 더 편리하게 클래스로 묶어두면 좋지 않을까 고민을 하였습니다. 또한, 리스트 콘트롤을 사용할 경우 발생하는 문제점으로 결과물 출력 속도가 있습니다. 이런 부분을 조금 더 쉽게 해결할 수 있는 방법이 없을까? 고민하여 인터넷을 찾아보기 시작하였습니다. 그렇게 인터넷을 찾아보고, 조금씩 아이디어를 획득 후 작업에 들어갔습니다. 결과는 성공....!! 랩핑이 조금 필요한 부분이 있지만, 사용방법에 대해 먼저 포스팅 하도록 하겠습니다. 
 
 
사용법

사용하기 이전 list control의 properties 설정을 변경해야 합니다. 
 
Dialog UI : Properties 설정
 
커스텀 Listcontrol을 설정하기위해 MFC 리소스관리자에서 Owner Data의 값을 True로 변경 합니다. 이때, 값을 변경하지 않을 경우, 값을 입력할 때, 오류 발생하게 됩니다. 
 
리스트 콘트롤에 맞춰서 다음과 같이 define을 작성합니다. 
 
CustomListcontrol.h
 
#define DEF_LIST_PATH_FOLDER            1

#define DEF_COL_FOLDER_NUM              0
#define DEF_COL_FOLDER_PATH             1
 
먼저 리스트 콘트롤의 이름을 추가하고, 리스트 콘트롤에 삽입되는 Column의 이름을 순차적으로 작성합니다. 이때, 매크로 번호는 0번부터 시작해야 합니다. 
 
MFC Main Dialog에 아래 내용 추가
// MFC UI by system
public:
    CCustomListcontrol m_ui_FolderList;
 
그리고 MFC 위자드를 이용하여 list control을 이용하여 추가 합니다. DDX관련 부분은 자동생성 되도록 하고, 이후에 CCustomListcontrol 이름만 변경하시면 됩니다. 
 
다음은 list control을 초기화 하는 방법입니다. 
 

 

 

 
MFC Main Dialog: 함수 정의
void InitListCtrlColumn();
 
 
MFC Main Dialog: 함수 구현 
 
void CDatasetManagerDlg::InitDirPathColumn()
{
    CCustomListControlMgrSingleton::GetSingleton().InsertList(DEF_LIST_PATH_FOLDER, &m_ui_FolderList);
    
    int wFileNum = 50;    
    int wFilePath = 420;
    vector<ST_COLINFO> _FileListList;
    _FileListList.push_back(ST_COLINFO(_T("Num"), LVCFMT_CENTER, wFileNum));    
    _FileListList.push_back(ST_COLINFO(_T("Path"), LVCFMT_LEFT, wFilePath));
    CCustomListControlMgrSingleton::GetSingleton().InitColumn(DEF_LIST_PATH_FOLDER, _FileListList);
}
 
초기화를 위해, 컬럼의 width를 작성하고, Name, width를 파라미터로 전달합니다. 이때, 각각의 컬럼에 대한 정렬(좌/중/우) 할 수 있도록 하였습니다. 
 
 
Listcontrol - Add Data 정의&구현
void InsertDataFolder(CString _num, CString _path);

//
void CDatasetManagerDlg::InsertDataFolder(CString _num, CString _path)
{
    vector<CString> _FileData;
    _FileData.push_back(_num);    
    _FileData.push_back(_path);
    CCustomListControlMgrSingleton::GetSingleton().InsertData(DEF_LIST_PATH_FOLDER, _FileData);
}
 
 
그리고 list control 에 값을 추가하기위해서 vector<string> 형태로 값을 변경 후 추가하게 됩니다. 이때, 추가된 값들은 custom list control 내부에서 관리를 하고 있으니 따로 결과값을 메모리에 상주하지 않도록 하시기 바랍니다. (코드만 지저분해질뿐...)
 
Listcontrol - Delete
 
void CDatasetManagerDlg::DeleteSelectedDataFolder()
{
    CCustomListControlMgrSingleton::GetSingleton().DelSelectData(DEF_LIST_PATH_FOLDER);
}
 
삭제는 아주 간단합니다. 전체 삭제는 따로 구현을 해두었지만, 상단 코드는 list control에서 선택된 항목에 대해서 삭제를 진행합니다. 
다음은 수정과 관련된 부분인데 작업이 조금 길어지게 됩니다. 
 

 

 

 
Listcontrol - 수정(edit)
void CDatasetManagerDlg::EditSelectedDataFolder()
{
    CCustomListcontrol* pListCtr = CCustomListControlMgrSingleton::GetSingleton().GetList(DEF_LIST_PATH_FOLDER);
    int SelectItemCount = pListCtr->GetSelectedCount();
    if (SelectItemCount > 1) {
        MessageBox(L"1개만 선택 해주세요!", L"경고", MB_OK);
        return;
    }


    // call to Dlg
    AddpathDlg childDlg;
    childDlg.m_edit_Num = CCustomListControlMgrSingleton::GetSingleton().getSelectData(DEF_LIST_PATH_FOLDER, DEF_COL_FOLDER_NUM);
    childDlg.m_edit_Path = CCustomListControlMgrSingleton::GetSingleton().getSelectData(DEF_LIST_PATH_FOLDER, DEF_COL_FOLDER_PATH);


    
    // error
    // childDlg.GetDlgItem(IDC_EDIT_NUM)->EnableWindow(FALSE);
    
    if (childDlg.DoModal() == IDOK) {
        CString dirNum  = childDlg.GetNum();
        CString dirPath = childDlg.GetPath();


        if (dirNum.Compare(L"") == 0 || dirPath.Compare(L"") == 0) {
            CString _msg = L"값을 입력해주세요!";
            if (MessageBox(_msg, L"확인", MB_OK) == IDOK) {
                return;
            }
        } else {
            // 순서 유의
            CCustomListControlMgrSingleton::GetSingleton().UpdteData(DEF_LIST_PATH_FOLDER, DEF_COL_FOLDER_NUM, childDlg.m_edit_Num, DEF_COL_FOLDER_PATH, dirPath);
            CCustomListControlMgrSingleton::GetSingleton().UpdteData(DEF_LIST_PATH_FOLDER, DEF_COL_FOLDER_NUM, childDlg.m_edit_Num, DEF_COL_FOLDER_NUM, dirNum);            
        }
    }


    Invalidate(FALSE); // false: REGION
}
 
수정을 하기위해서는 선택된 항목이 1개인지 검사 후 진행하게 됩니다. 그리고 선택된 항목에 대해 각각의 column값을 가지고 와서 새로운 Dialog에 출력, 그리고 수정된 값을 다시 받아 리스트 컬럼에 적용하는 과정입니다. 조금 더 간편하게 코드를 구현할 수 있었지만, 일단 step by step으로 진행을...
// 순서 유의
CCustomListControlMgrSingleton::GetSingleton().UpdteData(DEF_LIST_PATH_FOLDER, DEF_COL_FOLDER_NUM, childDlg.m_edit_Num, DEF_COL_FOLDER_PATH, dirPath);
CCustomListControlMgrSingleton::GetSingleton().UpdteData(DEF_LIST_PATH_FOLDER, DEF_COL_FOLDER_NUM, childDlg.m_edit_Num, DEF_COL_FOLDER_NUM, dirNum);            
 
 
수정할 때, 주의사항으로는 (주의:)삭제를 할때는 column의 첫번째 값을 이용하여 검색 후, 변경하기때문에 1번째 컬럼의 값은 제일 마지막에 변경 해야합니다. 그렇지 않은 경우, 제대로 수정되지 않습니다. 
 
 
참고용 : tok를 이용하여 글자를 제거하는 방법

string에 포함된 글자 중 일부 특수 문자를 제거하고 싶을 때가 있어 간략하게 메모를 남겨드립니다. 예시는 아래에 있으니 참고하면 됩니다. 
 
string CEliminateSpecialCharMgr::EraseTok(string _iString, const string _tok)
{
    int pos = -1;
    if ((pos = _iString.find("_")) != string::npos)
        _iString.erase(_iString.find("_"));


    return _iString;
}
 
다음과 같은 경우에 사용할 수 있다. 
 
// Input
//string str = "000020_2020-04-26-16-05-34";

// Output
000020 
 
즉, tok("_") 값을 찾아서, 검색된 position으로부터 문자열 끝까지 삭제하는 코드이다. 
 
 
 
 
 
728x90
반응형

댓글

Designed by JB FACTORY