[쥬니] 전환점

블로그 이미지
시작!
by eiliyuki
  • 8,273Total hit
  • 0Today hit
  • 2Yesterday hit

ON_NOTIFY(NM_CLICK, IDC_LIST_START_ITEM, &CQuestToolView::OnNMClickListStartItem)


void CQuestToolView::OnNMClickListStartItem(NMHDR *pNMHDR, LRESULT *pResult)

{

LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.


int rc = 0;

NM_LISTVIEW *pNMListView = (NM_LISTVIEW*)pNMHDR;


// checkbox HitTest

LVHITTESTINFO oInfo;

oInfo.pt = pNMListView->ptAction;

m_LT_StartItem.HitTest(&oInfo);


// checkbox icon click

if(oInfo.flags == LVHT_ONITEMSTATEICON)

{

SetModify(true);

}


*pResult = 0;

}

    

        void CxListView::OnNMClickShelllist(NMHDR *pNMHDR, LRESULT *pResult)
        {    
                int rc = 0;
                 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

                 // Checkbox HitTest
                 LVHITTESTINFO oInfo ;
                 oInfo.pt = pNMListView->ptAction ;
                 m_listCtl.HitTest(&oInfo) ;

                /// Check Box Icon Click
                 if( oInfo.flags == LVHT_ONITEMSTATEICON ) 
                {
                     rc = 1; // 무시하고 싶으면 셋팅                      
                }

                pResult = rc;
        }

신고
TRACKBACK 0 AND COMMENT 0
MFC 주요 클래스의 멤버 변수와 멤버 함수


1. CObject 클래스

2. 애플리케이션 프레임 워크 관련 클래스
   1) CWinApp
   2) CFrameWnd
   3) CView
   4) CDocument

3. 윈도우 관련 클래스 : CWnd

4. 디바이스 컨텍스트 클래스
   1) CDC 클래스
   2) CDC 파생 클래스들
      CPaintDC 클래스
      CClientDC 클래스
      CWindowDC 클래스
      CMetaFileDC 클래스
   3) CGdiObject 클래스







1. CObject 클래스

- CObject는 MFC 라이브러리에서 가장 기본이 되는 클래스이다. 



생성

CObject : 디폴트 생성자

CObject : 복사 생성자

operator new : new연산자

operator delete : delete연산자

operator = : 할당 연산자 


진단 관련 함수

AssertValid : 객체의 멤버들에 대한 유효성 여부를 검사한다.

Dump : 객체의 멤버들에 대한 진단 덤프를 생성한다. 


직렬화 관련 함수

IsSerializable : 객체가 직렬화될 수 있는지를 알아보기 위해서 검사 작업을 수행한다.

Serialize : 아카이브를 이용하여 일반 파일에 객체를 저장하거나 또는 파일로부터 읽어 들인다. 


기타 함수들

GetRuntimeClass : 객체의 클래스와 일치하는 CRuntimeClass 구조체를 반환한다.

IsKindOf : 주어진 클래스와 객체와의 관계를 검사한다. 



2. 애플리케이션 프레임 워크 관련 클래스

- Visual C++에서 AppWizard가 생성해주는 기본 클래스들이다. 

1)CWinApp

- CWinApp 클래스는 윈도우에서 수행되는 애플리케이션의 객체를 파생하기 위한 베이스 클래스이다. 

데이터 멤버

m_pszAppName : 애플리케이션의 이름을 지정한다.

m_hInstance : 애플리케이션의 현재 인스턴스에 대한 핸들

m_hPrevInstance : 32비트 애플리케이션에서는 NULL로 설정된다.

m_lpCmdLine : 애플리케이션을 수행하기 위한 위한 명령행 문자열로 널 문자로 끝난다.

m_nCmdShow : 초기 윈도우가 어떻게 표시되는지를 지정한다.

m_bHelpMode : 사용자가 도움말 모드에 있는지를 알려준다.(shift + F1으로 호출)

m_pActiveWnd : OLE서버가 in-place모드로 활성화될 때 컨테이녀 애플리케이션의 메인 윈도에 대한 포인터이다.

m_pszExeName : 애플리케이션의 모듈명

m_pszHelpFilePath : 도움말 파일의 경로명

m_pazProfileName : 애플리케이션에서 사용되는 INI파일명

m_pszRegistrykey : 애플리케이션의 프로파일 설정 상태를 저장하기 위한 완전한 형태의 레지스트리 키를 지정하기 위해서 사용된다. 

생성관련함수

CWinApp : CWinApp객체를 생성한다. 


역할

LoadCuror : 커서 리소스를 읽어들인다.

LoadStandardCursor : WINDOWS.H 해더파일에서 이미 IDC_상수로 정의되어 있는 커서를 읽어 들인다.

LoadOEMCursor : WINDOWS.H 해더파일에서 윈도우 OEM에 이미 OCR_상수로 정의되어 있는 커서를 읽어 들인다.

LoadIcon : 아이콘 리소스를 읽어 들인다.

LoadStandardIcon : WINDOWS.H 해더파일에서 윈도우에 이미 IDI_ 상수로 정의되어있는 아이콘을 읽어 들인다.

LoadOEMIcon : WINDOWS.H 해더파일에서 윈도우 OEM에 이미 OIC_상수로 정의되어 있는 아이콘을 읽어 들인다.

RunAutomated : /Automation 옵션에 대해서 애플리케이션의 명령행 옵션의 전달을 테스트한다.
(CCommandLineInfo::m_bRunEmbedded에 있는 값을 이용하는 것이 더 낫다.)

RunEmbedded : /Embedding 옵션에 대해서 애플리케이션의 명령행 전달을 테스트한다.
(CCommandLineInfo::m_bRunEmbedded에 있는 값을 이용하는 것이 더 낫다.) ParseCommandLine : 명령행 문자열에서 피라미터와 플래그를 parsing한다.

ProcessShellCommand : 명령행 문자열에서 피라미터와 플래그를 처리한다.

GetProfileInt : 애플리케이션의 .INI 파일로부터 정수 값을 읽는다.

WriteProfileInt : 애플리케이션의 .INI 파일에 정수 값을 적는다.

GetProfileString : 애플리케이션의 .INI 파일로부터 문자열을 읽는다.

WriteProfileString : 애플리케이션의 .INI 파일에 문자열을 적는다.

AddDocTemplate : 애플리케이션에서 사용 가능한 문서 템플릿의 리스트에 문서 템플릿을 추가한다.

GetFirstDocTemplatePosition : 첫 번째 문서 템플릿으 위치를 얻어낸다.

GetNextDocTemplate : 문서 템플릿의 위치를 얻어낸다. (반복사용가능)

OpenDocumentFile : 파일에서 문서를 열기 위해서 프레임워크에 의해 호출된다.

AddToRecentFileList : 최근에 사용되었던 파일들의 리스트에 파일명을 추가한다. 최근 에 사용되었던 파일을 MRU파일이라고도 한다.

SelectPrinter : 프린터 대화상자를 통해서 사용자가 전에 지정한 프린터를 선택한다.

CreatePrinterDC : 프린터의 디바이스 컨테스트를 생성한다.

GetPrintDeviceDefaultsD : 프린터의 기본설정 값을 얻어낸다. 

오버라이드 가능한 함수

InitApplication : 애플리케이션 수준의 초기화 작업을 수행할 때 오버라이드한다.

InitInstance : 윈도우 객체를 생성하는 것처럼 윈도우 시스템에서 사용하는 인스턴스에 대해서 초기화 작업을 수행하는 경우에 오버라이드한다.

Run : 디폴트 메시지 루프를 실행한다. 메시지 루프를 다른 방식으로 수행하기를 원하면 이 함수를 오버라이드한다.

OnIdle : 애플리케이션의 idle time에 작업을 수행하려면 오버라이드한다.

ExitInstance : 애플리케이션이 종료될 때 수행하려는 작업이 있으면 오버라이드한다.

HideApplication : 모든 문서를 닫기 전에 애플리케이션을 숨긴다.

CloseAllDocuments : 모든 문서를 닫는다.

PreTranslateMessage : 메시지가 윈도우 함수 ::TranslateMessage와 DispatchMessage로 보내기 전에 메시지를 필터링한다.

SaveAllModified : 수정된 모든 문서들을 저장한다고 사용자에게 알려준다.

DoMessageBox : 애플리케이션에서 AfxMessageBox를 구현한다.

ProcessMessageFilter : 어떤 메시지가 애플리케이션으로 보내지기 전에 가로챈다. ProcessWndProcException : 애플리케이션의 메시지가 명령 핸들러에 의해서 넘겨진 처리 되지 않은 모든 예외들을 처리한다.

DoWaitCuror : 대기 중임을 나타내는 커서(보통 모래시계 모양)를 출력하거나, 사라지게 한다.

OnDDECommand : DDE(Dynamic Data Exchange)를 실행한다는 명령에 대응하여 프레임워크 가 직접 호출한다.

WinHelp : 윈도우 함수인 WinHelp를 호출한다. 


초기화 관련 함수

LoadStdProfileSettintgs : 표준 .INI파일에 설정된 값을 읽어들이고 최근에 사용한 파 일들의 목록을 유지하다.

SetDialogBkColor : 대화상자와 메시지 출력 상자의 기본 배경색을 지정한다.

SetRegistryKey : 애플리케이션의 설정 값들이 .INI파일 대신에 레지스트리에 저장되도 록 한다.

EnableShellOpen : 사용자가 파일 관리자에서 테이터 파일을 열 수 있도록 한다.

RegisterShellFileTypes : 파일 관리자에게 모든 문서의 타입을 등록한다.

Enable3dControls : 컨트롤의 모양이 3차원 형태를 하도록 한다.

Enable3dControlsStatic : 컨트롤의 모양이 3차원 형태를 하도록 한다. 


명령 핸들러 관련 함수

OnFileNew : ID_FILE_NEW 명령을 수행한다.

OnFileOpen : ID_FILE_OPEN 명령을 수행한다.

OnFilePrintSetup : ID_FILE_PRINT_SETUP 명령을 수행한다.

OnContextHelp : 애플리케이션의 SHIFT+F1 키를 핸들링한다.

OnHelp : 애플리케이션에서 F1 키를 누를 경우 도움말의 수행을 핸들링한다.

OnHelpIndex : ID_HELP_INDEX 명령을 핸들링한다.

OnHelpFinder : ID_HELP_FINDER 명령과 ID_DEFAULT_HELP 명령을 핸들링한다.

OnHelpUsing : ID_HELP_USING 명령을 핸들링한다. 


2) CFrameWnd

- CFrameWnd 클래스는 윈도우를 직접 다루는 멤버함수와 함께 오버라이드된 SDI 또는 팝업 프레임윈도우의 기능을 제공한다.



데이터 멤버

m_bAutoMenuEnable : 메뉴 아이템에 대한 자동 사용 및, 가능과 불가능여부를 제어한다. rectDefault : 윈도우가 초기 크기와 위치를 선택하도록 하는 CWnd 객체를 생성하는 경 우 정적 CRect 형인 멤버를 피라미터로 넘겨주게 된다. 


생성 관련 함수

Create : CFrameWnd 객체와 관련된 프레임 윈도우를 생성하고 초기화하기 위해서 사용한 다.

LoadFrame : 리소스 정보를 이용하여 프레임 윈도우를 동적으로 생성하기 위해서 이 함 수를 호출한다.

LoadAccelTable : 가속키 테이블을 읽어 들이기 위해서 이 함수를 호출한다.

LoadBarState : 컨트롤 바의 설정 상태를 복원하기 위해서 호출한다.

SaveBarState : 컨트롤 바의 설정 상태를 보관하기 위해서 호출한다.

ShowControlBar : 컨트롤 바를 실제로 보이게 하기 위해서 이 함수를 호출한다.

SetDockState : 메인 윈도우 내의 프레임 윈도우를 도크상태(dock)로 설정한다.

GetDockState : 메인 윈도우 내의 프레임 윈도우 중 도크상태(dock)인 것들을 검색한다. 


역할

ActivateFrame : 사용자가 사용 가능하고 실제로 보이는 프레임을 만든다.

InitialUpdateFrame : 프레임 윈도우 내에서 호출된 모든 뷰에 소속된 OnInitialUpdate 멤버 함수의 호출을 유발한다.

GetActiveFrame : 활성화된 CFrameWnd 객체를 설정한다.

SetActiveView : 활성화된 CView 객체를 설정한다.

GetActiveView : 활성화된 CView 객체를 반환한다.

CreateView : CView에서 파생되지 않은 프레임 내에 뷰를 생성한다.

GetActiveDocument : 활성화된 CDocument 객체를 반환한다.

GetControlBar : 컨트롤 바를 검색한다.

GetMessageString : 명령 ID와 일치하는 메시지를 검색한다.

IsTracking : 스플리터 막대가 이동되었는지를 확인하고자 하는 경우에 호출한다.

SetMessageText : 표준 상태 바의 텍스트를 설정한다.

EnableDocking : 컨트롤 바가 도킹되도록 허용한다.

DockControlBar : 컨트롤 바를 도킹시킨다.

FloatControlBar : 컨트롤 바를 분리시킨다.

BeginModalState : 프레임 윈도우를 modal로 설정한다.

EndModalState : 프레임 윈도우의 modal상태를 종료한다.

InModalState : 프레임 윈도우가 modal상태에 있는지를 알려주는 값을 반환한다.

ShowOwnedWindows : CFrameWnd객체에서 계승받은 모든 윈도우들을 보여준다.

RecalcLayout : CFrameWnd객체의 컨트롤 바를 다시 위치시킨다. 


오버 라이드 가능한 함수

OnCreateClient : 프레임에 대한 클라이언트 윈도우를 생성한다.

OnSetPreviewMode : 애플리케이션의 메인 프레임 윈도우를 인쇄 미리 보기 모드 내부와 외부 모두를 설정한다.

GetMessageBar : 프레임 윈도우에 속한 상태 바에 대한 포인터를 반환한다.

NegotiateBorderSpace : 프레임 윈도우 내의 경계 공간을 결정한다. 


명령 핸들러 관련 함수

OnContextaHelp : 도움말을 보고자 하는 아이템에 위치시키고 SHIFT+F1 키를 눌렀을 때 해당 도움말을 출력하는 기능을 한다. 



3) CView - CView클래스는 사용자 정의 뷰 클래스의 기본적인 기능을 제공한다. 뷰는 문서와 연관 이 있으며 문서와 사용자 사이를 연결하는 중간 매개체가 된다. 즉, 뷰는 문서의 이미 지를 화면 상이나 프린터에 표현하고 사용자의 입력을 문서에 대한 조작으로 바꾸는 작업을 수행한다. 


역할

DoPreparePrinting : 인쇄 대화상자를 표시하고 프린터 디바이스 컨텍스트를 생성한다. PreparePrinting 멤버 함수를 오버라이드하는 경우에 호출한다.

GetDocument : 뷰와 관련된 문서를 반환한다. 


OLE 관련 오버라이드 가능한 함수

OnDragEnter : 아이템이 처음으로 뷰의 드래그-드롭 영역으로 드래그 되는 경우에 호출 된다.

OnDragLeave : 드래그된 아이템이 뷰의 드래그-드롭 영역을 벗어 나는 경우에 호출된다.

OnDragOver : 아이템이 뷰의 드래그-드롭 영역위로 드래그되는 경우에 호출된다.

OnDrop : 아이템이 뷰의 드래그-드롭 영역으로 드래그되었을 때 호출된다. (디폴트 핸들러)

OnDropEx : 아이템이 뷰의 드래그-드롭 영역으로 드래그되었을 때 호출된다. (디폴트 핸들러)

OnDragScroll : 커서가 윈도우의 스크롤 영역으로 드래그되었을 때 호출된다.

OnInitialUpdate : 뷰가 처음으로 문서에 추가된 후에 호출된다.

OnScrollBy : 활성화된 인-플레이스 OLE 아이템을 포함하는 뷰가 스크롤되는 경우에 호출 된다.

OnScroll : OLE 아이템이 뷰의 경계선을 넘어서 드래그될 때 호출된다. 

오버라이드 가능한 함수

IsSelected : 문서 아이템이 선택되었는지를 확인한다. OLE에 대한 지원이 요구된다.

OnActivateView : 뷰가 활성화되었을 때 호출된다.

OnActivateFrame : 뷰를 포함하는 프레임 윈도우가 활성화 또는 비활성화될 때 호출된다.

OnBeginPrinting : 인쇄 작업이 시작될 때 호출된다. GDI 리소스를 할당하기 위해서 오버라이드 한다.

OnDraw : 문서의 이미지를 클라이언트 윈도우, 프린터, 인쇄 미리보기 윈도우로 출력하는 경우에 호출된다. 보통은 오버라이드 한다.

OnEndPrinting : 인쇄 작업이 끝나는 경우에 호출된다. GDI 리소스를 할당 해제하기 위해서 오버라이드한다.

OnEndPrintPreview : 미리보기 모드를 빠져나올 대 호출된다.

OnPrepareDC : 화면 표시를 위해 OnDraw멤버 함수를 호출하기 전이나 인쇄, 인쇄 미리보 기를 위해서 OnPrint 멤버 함수를 호출하기 전에 호출된다.

OnPreparePrinting : 문서가 인쇄되거나 미리보기 전에 호출된다. 인쇄 대화상자를 초기화 하려면 이 함수를 오버라이드 한다.

OnPrint : 문서의 한 페이지를 인쇄하거나 미리보기 하는 경우에 호출된다. 


생성 관련 함수

CView : CView 객체를 생성한다. 



4) CDocument

- CDocument클래스는 사용자에 의해서 정의된 문서 클래스들을 위해서 기본적인 기능 들을 제공한다 여기서 문서란 사용자가 "File" ▶ "Open" 명령을 사용하여 열고 "File" ▶ "Save" 명령을 사용하여 저장하는 데이터의 단위를 나타낸다. 


생성 관련 함수

CDocument : CDocument 객체를 생성한다. 


역할

AddView : 뷰를 문서에 연결시킨다.

GetDocTemplate : 문서 타입을 기술한 문서 템플릿에 대한 포인터를 반환한다.

GetFirstViewPosition : 뷰의 리스트에서 첫 번째 뷰의 위치를 반환한다. 보통 루프에서 처 음 위치로 사용된다.

GetNextView : 문서와 관련된 뷰의 포인터를 반환하고, 다음 뷰의 위치로 이동한다.

GetPathName : 문서에서 사용되는 데이터 파일의 경로를 반환한다.

GetTitle : 문서의 제목을 반환한다.

IsModified : 문서가 마지막으로 저장된 후에 수정이 되었는지의 여부를 가리킨다.

RemoveView : 문서에서 뷰와의 연결을 해제한다.

SetModifiedFlag : 마지막으로 저장이 된 후에 문서를 수정했는지의 여부를 가리키는 플래 그를 설정한다.

SetPathName : 문서에 의해 사용되는 데이터 파일의 경로를 설정한다.

SetTitle : 문서의 제목을 설정한다.

UpdateAllViews : 문서와 연관이 있는 모든 뷰를 갱신한다. 


오버라이드 가능한 함수

CanCloseFrame : 미리 오버라이드할 수 있으며 이 문서를 보여주기 위한 프레임 윈도우를 닫기 전에 호출된다.

DeleteContents : 문서의 해제 작업을 수행하기 위해서 호출된다.

OnChangedViewList : 뷰가 문서에 추가되거나 혹은 해제될 때 호출된다.

OnCloseDocument : 문서를 닫기 위해서 호출된다.

OnNewDocument : 새로운 문서를 생성하기 위해서 호출된다.

OnOpenDocument : 이미 존재하는 문서를 열기 위해서 호출된다.

OnSaveDocument : 디스크에 문서를 저장하기 위해서 호출된다.

ReportSaveLoadException : 미리 오버라이드할 수 있으며 문서를 열거나 저장하는 작업을 수행하는 도중에 예외가 발생하였을 때 호출된다.

GetFile : 원하는 CFile 객체의 포인터를 반환한다.

ReleaseFile : 다른 애플리케이션이 파일을 사용할 수 있도록 하기 위해서 파일을 해제한 다.

SaveModified : 미리 오버라이드할 수 있으며 문서가 저장이 되어야 하는지를 사용자에게 묻기 위해서 호출된다.

PreClossFrame : 프레임 윈도우를 닫기 전에 호출된다. 


메일 관련 함수

OnFileSendMail : 연결된 문서와 메일 메시지를 전송한다.

OnUpdateFileSendMail : 메일기능이 지원된다면, Send Mail 명령이 수행될 수 있다. 



3. 윈도우 관련 클래스 : CWnd

- CWnd 클래스는 MFC의 모든 윈도우 클래스들에 대해서 기본적인 기능을 제공 하는 클래스이다. 

데이터 멤버

m_hWnd : CWnd와 관련된 HWND를 가리킨다. 


생성/소멸 관련 함수

CWnd : CWnd객체를 생성한다.

DestroyWindow : 윈도우를 소멸한다. 그렇지만 객체를 소멸시키는 것은 아니다. 





초기화 관련 함수

Create : CWnd 객체와 관련된 자식 윈도우를 만들고 초기화한다.

PreCreateWindow : CWnd 객체와 관련된 실제 윈도우를 만들기 전에 호출된다.

CaleWindowRect : 클라이언트 사각형 영역에서 윈도우를 만들기 전에 호출된다.

GetStyle : 현재 윈도우의 스타일을 반환한다.

GetExStyle : 확장된 윈도우의 스타일을 반환한다.

Attach : CWnd 객체에 윈도우 핸들을 추가한다.

Detach : CWnd 객체에서 윈도우 핸들을 분리하고 핸들을 반환한다.

PreSubclassWindow : SubclassWindow가 호출되기 전에 필요한 다른 서브클래싱이 일어나 는 것을 허용한다.

SubclassWindow : CWnd 객체에 윈도우를 추가하고 CWnd의 메시지맵을 통해서 루트 메시 지로 만든다.

UnSubclassWindow : CWnd 객체에서 윈도우를 분리한다.

FromHandle : 윈도우에 핸들이 주어질 때 CWnd 객체에 대한 포인터를 반환한다. CWnd 객체가 핸들을 가지지 않는다면, 임시적인 CWnd 객체기 생성되고 추가된다.

FromHandlePermanent : 윈도우에 핸들이 주어질 때 CWnd 객체에 대한 포인터를 반환한다. 

CWnd 객체가 핸들을 가지지 않는다면, NULL이 반환된다.

DeleteTempMap : CWinApp가 자동으로 호출하며 FromHandle에 의해서 생성된 어떠한 임시 CWnd 객체도 지운다.

GetSafeHwnd : 포인터가 NULL이면, m_hWnd, 또는 NULL을 반환된다.

CreateEx : 오버랩된 형태의 팝업 자식 윈도우를 생성하고 이것을 CWnd 객체에 추가한다

. CreateControl : MFC 프로그램에서 CWnd 객체에 의해서 표현되는 OLE 컨트롤을 생성한다. 


윈도우 상태 함수

IsWindowEnabled : 윈도우에 마우스와 키보드 입력이 가능한지를 결정한다.

EnableWindow : 윈도우에 마우스와 키보드로 입력을 가능하게 하거나 불가능하도록 한다.

GetActiveWindow : 활성 윈도우를 얻는다.

SetActiveWindow : 윈도우를 활성화한다.

GetCapture : 마우스를 캡쳐한 CWnd를 얻는다.

SetCapture : 모든 일련의 마우스 입력이 CWnd로 보내지도록 한다.

GetFocus : CWnd가 현재 입력 포커스를 가지고 있는지 검사한다.

SetFocus : 입력 포커스를 설정한다.

GetDestktopWindow : 윈도우 시스템의 desktop윈도우를 얻는다.

GetForegroundWindow : 포그라운드 윈도우의 포인터를 반환한다.

SetForegroundWindow : 생성된 윈도우의 스레드를 포그라운드로 설정하고 윈도우를 활성 화 한다.

GetIcon : 핸들에서 아이콘을 얻는다.

SetIcon : 핸들에 특정 아이콘을 설정한다.

GetWindowContextHelpId : 도움말 항목에 대한 식별자를 얻는다.

SetWindowContextHelpId : 도움말 항목에 대한 식별자를 지정한다.

ModifyStyle : 현재 윈도우의 스타일을 수정한다.

ModifyStyleEx : 확장된 윈도우의 스타일을 수정한다. 


윈도우의 크기와 위치

GetWindowPlacement : 윈도우가 보여지는 상태와 정상(복귀된), 최소, 최대화된 윈도우의 위치를 얻는다.

SetWindowPlacement : 윈도우가 보여지는 상태와 정상(복귀된), 최소, 최대화된 윈도우의 위치를 설정한다.

IsIconic : CWnd가 최소화되었는지를 알아본다.

IsZoomed : CWnd가 최대화되었는지를 알아본다.

MoveWindow : CWnd의 위치또는 크기를 변경한다.

SetWindowPos : 크기, 위치, 순서, 팝업, 최상위 윈도우에 대한 것을 설정한다.

ArrangeIconicWindows : 모든 축소된(아이콘화 된) 자식 윈도우에 대한 것을 설정한다.

BringWindowToTop : CWnd를 오버랩 된 윈도우의 맨 처음으로 보낸다.

GetWindowRect : CWnd의 화면 좌표를 얻는다.

GetClientRect : CWnd 클라이언트 영역의 크기를 얻는다. 


윈도우 참조 관련 함수

ChildWinddowFromPoint : 어떤 자식 윈도우가 특정 점을 포함하고 있는지를 알아낸다.

FindWindow : 윈도우의 이름과 클래스로 확인이 가능한 윈도우의 핸들을 반환한다.

GetNextWindow : 윈도우 관리자의 리스트에서 다음 또는 이전 윈도우를 반환한다.

GetOwner : CWnd의 소유자에 대한 포인터를 얻는다.

SetOwner : CWnd의 소유자를 변경한다.

GetTopWindow : CWnd에 속한 맨 첫 번째 자식 윈도우를 반환한다.

GetWindow : 이 윈도우와 특정한 관계를 가지고 있는 윈도우를 반환한다.

GetLastActivePopup : CWnd이 가지고 있는 팝업 윈도우가 가장 최근에 활성화 되었는지를 알아낸다.

IsChild : CWnd가 자식 윈도우인지 또는 다른 특정 윈도우의 후손인지를 알아낸다.

GetParent : CWnd의 부모 윈도우가 있다면 그 윈도우를 얻는다.

GetSafeOwner : 지정된 윈도우의 소유자를 얻는다.

SetParent : 부모 윈도우를 변경한다.

WindowFromPoint : 특정 점을 포함하는 윈도우를 알아낸다.

GetDlgItem : 특정 대화상자에서 특정 ID의 컨트롤을 얻는다.

GetDlgCtrlID : CWnd가 자식 윈도우이면, 자신의 ID 값을 반환한다.

SetDlgCtrlID : 윈도우에 윈도우 또는 컨트롤의 ID를 설정한다.

GetDescendantWindow : 모든 자식 윈도우를 검색하고 윈도우의 특징 ID를 반환한다.

GetParentFrame : CWnd 객체의 부모 프레임 윈도우를 얻는다.

SendMessageToDescendants : 윈도우의 모든 자식 윈도우에게 메시지를 보낸다.

GetToLevelParent : 윈도우의 최상위 부모를 얻는다.

GetToLevelOwner : 최상위 윈도우를 얻는다.

GetParentOwner : 자식 윈도우의 부모 윈도우에 대한 포인터를 반환한다.

GetTopLevelFrame : 윈도우의 촤상위 프레임 윈도우를 얻는다.

UpdateDialogControls : 대화상자의 버튼이나 다른 컨트롤들의 상태 갱신을 요구한다.

UpdateData : 대화상자의 데이터를 초기화하고 유효화한다.

CenterWindow : 부모 윈도우의 중앙에 윈도우를 위치시킨다. 


갱신/그리기 함수

BeginPaint : 드로잉 작업을 수행하기 위해서 CWnd를 준비한다.

EndPaint : 드로임 작업을 마친다.

Print : 특정 디바이스 컨텍스트에 현재 윈도우를 그린다.

PrintClient : 특정 디바이스 컨텍스트에 모든 윈도우를 그린다.

LockWindowUpdate : 정해진 윈도우에 드로잉을 불가능하도록 하거나 다시 가능하도록 한다.

GetDC : 클라이언트 영역에 표시된 디바이스 컨텍스트를 얻는다.

GetDCEx : 클라이언트 영역에 표시된 디바이스 컨텍스트를 얻고, 그리는 도중에 클리핑이 가능하도록 한다.

RedrawWindow : 클라이언트 영역에서 특정 사각형이나 특정 영역을 갱신한다.

GetWindowDC : 툴바나, 메뉴, 스크롤 바를 포함한 모든 윈도우 영역에 대한 디바이스 컨 텍스트를 얻는다.

ReleaseDC : 클라이언트와 윈도우 디바이스 컨택스트를 해제함으로써, 다른 애플리케이션 이 사용할 수 있도록 한다.

UpdateWindow : 클라이언트 영역을 갱신한다.

SetRedraw : CWnd가 변화된 것을 다시 그리도록 설정하거나, 다시 그릴 수 없도록 설정 하는 역할을 한다.

GetUpdateRect : CWnd의 갱신 영역을 완전히 둘러싸는 가장 작은 사각형의 좌표를 얻는다.

GetUpdateRgn : CWnd의 갱신 영역을 얻는다.

Invalidate : 모든 클라이언트 영역을 무효화한다.

InvalidateRect : 현재의 갱신 영역에 사각형을 추가함으로써 정해진 사각형 내의 클라이언 트 영역을 무효화한다.

InvalidateRgn : 현재의 갱신 영역에 영역을 추가함으로써 정해진 영역내의 클라이언트 영 역을 무효화한다.

VaildateRect : 현재의 갱신 영역에서 사각형을 제거함으로써 정해진 사각형 내의 클라이 언트 영역을 유효화시킨다.

VaildateRgn : 현재의 갱신 영역에 영역을 제거함으로써 정해진 영역 내의 클라이언트 영 역을 유효화시킨다.

ShowWindow : 윈도우를 보이도록 하거나 숨긴다.

IsWindowVisible : 윈도우가 보이는지를 알아낸다.

ShowOwnedPopups : 윈도우가 가지고 있는 모든 팝업 윈도우를 보이게 하거나 숨긴다.

EnableScrollBar : 스크롤 바의 화살표를 사용가능하도록 하거나 불가능하게 한다. 


좌표 매핑 관련 함수

MapWindowPoints : CWnd의 좌표계로부터 다른 윈도우의 좌표계로 지정된 점들을 매핑시 킨다.

ClientToSreen : 클라이언트 좌표계를 화면 좌표계로 변환한다.

ScreenToClient : 화면 좌표계를 클라이언트 좌표계로 변환한다. 


윈도우 텍스트 함수

SetWindowText : 윈도우의 텍스트나 캡션 제목을 지정된 텍스트로 설정한다.

GetWindowText : 윈도우의 텍스트나 캡션 제목을 반환한다.

GetWindowTextLength : 윈도우의 텍스트나 캡션 제목의 길이를 반환한다.

SetFont : 현재의 폰트를 설정한다.

GetFont : 현재의 폰트를 얻는다. 


스크롤 관련 함수

GetScrollPos : 스크롤 박스의 현재 위치를 얻는다.

GetScrollRange : 지정된 스크롤 바에 대한 최소, 최대의 스크롤 바 위치 값을 얻는다.

ScrollWindow : 클라이언트 영역의 내용을 스크롤한다.

ScrollWindowEx : 클라이언트 영역의 내용을 스크롤한다. (ScrollWindow과 비슷)

GetScrollInfo : 스크롤 바에 대한 SCROLLINFO 구조체 값을 얻는다.

GetScrollLimit : 스크롤 바의 한계 값을 얻는다.

SetScrollInfo : 스크롤 바에 대한 정보를 설정한다.

SetScrollPos : 스크롤 박스의 현재 위치를 설정하고, 설정이 되면, 새로운 위치를 나타내 도록 스크롤 바를 다시 그린다.

SetScrollRange : 지정된 스크롤 바에 대한 최소와 최대 위치 값을 지정한다.

ShowScrollBar : 스크롤 바를 보이거나 숨긴다.

EnableScrollBarCtrl : 스크롤 바의 컨트롤을 가능하게 하거나 불가능하도록 한다.

GetScrollBarCtrl : 스크롤 바 컨트롤을 반환한다.

RepositionBars : 클라이언트 영역에 컨트롤 바를 재위치 시킨다. 


드래그-드롭 함수

DragAcceptFiles : 윈도우가 드래그된 파일을 받아들일 것인지를 결정한다. 


Caret 관련 함수

CreateCaret : 시스템 캐럿으로 새로운 형태를 생성하고 캐럿의 소유권을 얻는다.

CreateSolidCaret : 시스템 캐럿으로 솔리드 캐럿을 생성하고 캐럿의 소유권을 얻는다.

CreateGrayCaret : 시스템 캐럿으로 회색 캐럿을 생성하고 캐럿의 소유권을 얻는다.

GetCaretPos : 특정 위치로 캐럿을 이동시킨다.

SetCaretPos : 화면에서 캐럿을 숨긴다.

HideCaret : 캐럿의 현재 위치에서 캐럿을 보이도록 한다.

ShowCaret : 캐럿의 현재 위치에서 캐럿을 보이도록 한다. 일단 캐럿이 화면에 나타나면 캐럿은 자동적으로 깜박거리게 된다. 


대화상자 아이템 관련 함수

CheckDlgButton : 버튼 컨트롤 다음에 체크 표시를 하거나 버튼 컨트롤에서 체크 표시를 제거한다.

CheckRadioButton : 특정 라디오 버튼을 체크하고, 특정 버튼 그룹 내에 있는 모든 다른 라디오 버튼에서 체크 표시를 제거한다.

GetCheckedRadioButton : 버튼 그룹에서 현재 체크된 라디오 버튼의 ID를 반환한다.

DlgDirList : 파일이나 디렉토리에 대한 리스트로 리스트 박스를 채운다.

DlgDirListComboBox : 파일이나 디렉토리에 대한 리스트 콤보 박스를 채운다.

DlgDirSelect : 리스트 박스에서 현재 선택된 항목을 얻는다.

DlgDirSelectComboBox : 콤보 박스에서 현재 선택된 항목을 얻는다.

GetDlgItemInt : 지정된 대화상자에서 컨트롤이 사용하는 텍스트를 정수 값으로 변환한다.

GetDlgItemText : 컨트롤과 관련된 캡션이나 텍스트를 얻는다.

GetNextDlgGroupItem : 컨트롤 그룹 내의 다음 또는 이전 컨트롤을 찾는다.

GetNextDlgTabItem : 특정 컨트롤의 다음 또는 이전 컨트롤 중에서 WS_TABSTOP속성을 가 지는 컨트롤을 얻는다.

IsDlgButtonChecked : 버튼 컨트롤이 체크되었는지를 결정한다.

IsDialogItemMessage : 지정된 메시지가 모달리스(modeless)대화상자를 위한 것인지를 알아 내고, 만약에 그렇다면 그것을 처리한다.

SendDigItemMessage : 특정 컨트롤에 메시지를 보낸다.

SendDigItemInt : 지정된 대화상자에서 컨트롤이 사용하는 텍스트를 정수 값에 해당하는 문 자열로 설정한다.

SendDigItemText : 지정된 대화상자에서 컨트롤의 캡션이나 텍스트를 설정한다.

SubclassDlgItem : CWnd 컨트롤에 윈도우 컨트롤을 추가하고 CWnd의 메시지 맵을 통해 메시지를 배정하도록 한다.

ExecuteDlgInit : 해당 대화상자의 리소스로 초기화한다.

RunModalLoop : 모달 상태에 있는 윈도우의 메시지를 검색하고, 번역하거나, 처리한다.

ContinueModal : 윈도우 모달 상태를 지속시킨다.

EndModalLoop : 윈도우 모달 상태를 마친다. 


메뉴 함수

GetaMenu : 특정 메뉴에 대한 포인터를 얻는다.

SetMenu : 현재의 메뉴를 지정된 메뉴로 설정한다.

DrawMenuBar : 메뉴 바를 다시 그린다.

GetSystemMenu : 애플리케이션이 컨트롤 메뉴를 복사하거사 수정하도록 참조하는 것을 허용한다.

HiliteMenuItem : 최상위 메뉴 아이템에서 선택된 부분을 하이라이트하거나 해제한다. 


툴팁 함수

EnableToolTips : 툴팁 컨트롤을 사용가능하도록 한다.

CancelToolTips : 툴팁 컨트롤을 사용 불가능하도록 한다.

FilterToolTipMessage : 대화상자에서 컨트롤과 관련된 제목이나 텍스트를 얻는다.

OnToolHitTest : 포인터가 특정 도구의 사각형 경계(보통 툴바 영역)안에 있는지를 알아내 고 그 도구에 대한 정보를 얻는다. 


타이머 관련 함수

SetTimer : 시작될 때 WM_TIMER 메시지를 보내는 시스템 타미머를 설치한다.

KillTimer : 타이머를 해제한다. 


경고 함수

FlashWindow : 윈도우를 한 번 반짝이게 한다.

MessageBox : 애플리케이션이 제공하는 캡션과 메시지를가지고 있는 윈도우를 생성하고 화면에 출력한다. 


윈도우 메시지 관련 함수 GetCurrentMessage : 윈도우가 현재 처리하고 있는 메시지의 포인터를 반환한다. OnMessage 류의 메시지 핸들러 멤버 함수 내부에서만 호출되어야한다.

Default : 디폴트 윈도우 프로시저를 호출하며, 이것은 애플리케이션에게 어떤 윈도우 메 시지도 디폴트 형태로 처리하도록 한다.

PreTranslateMessage : TranslateMessage와 DispatchMessage 윈도우 함수에서 처리되기 전 에 윈도우의 메시지를 필터링하기 위해서 CWinApp가 사용한다.

SendMessage : CWnd 객체에 메시지를 보내고 메시지를 처리할 때 까지 반환되지 않는다.

PostMessage : 애플리케이션 큐에 메시지를 위치시키고, 윈도우가 메시지를 처리할 때까 지 기다리지 않고 바로 반환한다.

SendNotifyMessage : 특정 메시지를 윈도우에 보내고 호출한 스래드가 윈도우를 생성했는 지에 따라서, 가능한 빨리 반환한다.




클립보드 관련 함수

ChangeClipboardChain : 클립보드 뷰어의 체인으로부터 CWnd를 제거한다.

SetClientboardViewer : 클립보드의 내용이 변하면 윈도우의 체인에 CWnd를 추가한다.

SetClipboard : 클립보드를 연다. 다른 애플리케이션이 윈도우의 CloseClipboard 함수를 호 출할 때까지 클립보드를 수정하지 않도록 한다.

GetClipboardOwner : 클립보드의 현재 소유자에 대한 포인터를 얻는다.

GetOpenClipboardWindow :현재 클립보드가 열려진 윈도우에 대한 포인터를 얻는다.

GetClipboardViewer : 클립보드 뷰어의 체인에서 처음 윈도우에 대한 포인터를 얻는다. 


OLE 콘트롤

SetProperty : OLE 컨트롤 프로퍼티를 설정한다.

OnAmbientProperty : 환경 프로퍼티 값을 구현한다.

GetControlUnknown : 알려지지 않은 OLE 컨트롤에 대한 포인터를 얻는다.

GetProperty : OLE 컨트롤 프로퍼티를 얻는다.

InvokeaHelper : OLE 컨트롤의 메소드나 프로퍼티를 호출한다. 


오버라이드 가능한 함수

WindowProc : CWnd에 대한 디폴트 프로시저를 제공한다. 디폴트로 메시지 맵을 통해서 메시지를 처리하게 된다.

DefWindowProc : 디폴트 윈도우 프로시저를 요구하며, 이것은 애플리케이션이 처리하지 않은 모든 윈도우 메시지에 대해서 디폴트 처리를 하도록 한다.

PostNcDestroy : 윈도우가 소멸된 후에 디폴트 OnNcDestroy 함수에 의해서 호출되는 가상 함수이다.

OnChildNotify : 컨트롤 통지 메시지를 처리하기 위한 기회를 컨트롤에게 주기 위해서 부 모 윈도우에 의해 호출된다.

DoDateExchange : 대화상자의 데이터 교환이나 유효화 검사를 위해서 UpdateData에 의해 서 호출된다. 


초기화 메시지 핸들러

OnInitMenu : 메뉴가 활성화될 때 호출된다.

OnInitMenuPopup : 팝업 메뉴가 활성화될 때 호출된다. 


시스템 메시지 핸들러

OnSysChar : 사용자가 컨트롤 문자로 변환하기 위해서 호출된다.

OnSysCommand : 사용자가 컨트롤 메뉴에서 항목을 선택하거나, 사용자가 최대화 또는 최 소화 버튼을 누를 때 호출된다.

OnSysDeadChar : 키 입력을 시스템의 Dead 문자((')등이 추가된 문자)로 변환할 때 호출 된다.

OnSysKeyDown : 사용자가 Alt 키를 누르고 다른 키를 누를 때 호출된다.

OnSysKeyUp : 사용자가 Alt 키를 누른 상태로 다른 키를 놓을 때 호출된다.

OnCompacting : 윈도우 시스템에서 시스템 메모리가 부족한 경우에 호출된다.

OnDevModeChange : 사용자가 디바이스의 모드 설정을 바꿀 때 최상위 윈도우가 호출된다.

OnFontChange : 폰트 리소스의 풀이 변할 때 호출된다.

OnPaletteChanged : 애플리케이션이 논리 팔레트를 적용할 것임을 다른 애플리케이션들에 게 알린다.

OnPaletteChanging : 윈도우가 논리 팔레트를 적용할 것임을 다른 애플리케이션들에게 알 린다.

OnSysColorChange : 시스템의 컬러 설정에 변화가 있을 때 최상위 윈도우가 호출한다.

OnWindowPosChanging : SetWindowPos나 다른 윈도우-관리 함수의 호출의 결과로 크기, 위치, 또는 Z-Order가 변하려 할 때 호출된다.

OnWindowPosChanged : SetWindowPos나 다른 윈도우-관리 함수의 호출의 결과로 크기, 위치, 또는 Z-Order가 변했을 때 호출된다.

OnDropFiles : 사용자가 드롭된 파일을 실행하기 위한 프로그램으로 등록된 윈도우 위에서 왼쪽 마우스 버튼을 놓을 때 호출된다.

OnSpoolerStatus : 프린트 관리자의 작업이 추가되거나 삭제될 때마다 프린트 관리자가 호출한다.

OnTimeChange : 시스템 시간 설정이 변경되면 최상위 윈도우가 호출한다.

OnWinIniChange : 윈도우의 초기화 파일인 WIN.INI가 변경되면 최상위 윈도우가 호출한다. 


일반 메시지 핸들러

OnCommand : 사용자가 명령을 선택할 때 호출된다.

OnActivate : CWnd가 활성화되거나 비활성화될 때 호출된다.

OnActivateApp : 애플리케이션이 활성화되려고 하거나 비활성화되려고 하는 경우에 호출 된다.

OnCancelMode : CWnd가 마우스 캡쳐와 같은, 어떤 내부적인 모드를 취소하는 것을 허용 하기 위해서 호출된다.

OnChildActivate : MDI의 자식 윈도우에서 CWnd의 크기나 위치가 변경되거나 CWnd가 활 성화될 때 호출된다.

OnClose : CWnd이 종료되는 신호로서 호출된다.

OnCreat : 윈도우 생성의 일부분으로서 호출된다.

OnCtlColor : 컨트롤이 그려지려 할 때 CWnd가 컨트롤의 부모 윈도우이면 호출된다.

OnDestroy : CWnd가 소멸될 때 호출된다

OnEnable : CWnd가 사용 가능하거나 불가능할 때 호출된다.

OnEndSession : 세션이 종료될 때 호출된다.

OnEnterIdle : 모달 대화상자나 메뉴가 유휴(idle)상태에 들어갈 때 애플리케이션의 메인 윈 도우 프로시저에서 호출된다.

OnEraseBkgnd : 윈도우의 바탕이 지워져야 할 때 호출된다.

OnGetMinMaxInfo : 윈도우가 최대화된 위치나 크기, 또는 최소 또는 최대 트랙킹 크기를 알아야 할 때마다 호출된다.

OnIconEraseBkgnnd : CWnd가 최소화되거나 아이콘이 그려지기 전에 아이콘의 배경을 채 워야 하는 경우에 호출된다.

OnKillFocus : CWnd가 입력포커스를 잃기 전에 호출된다.

OnMenuChar : 사용자가 현재 메뉴에서 이미 정의된 코드와 대응이 안되는 문자를 눌렀을 때 호출된다.

OnMenuSelect : 사용자가 메뉴 아이템을 선택할 때 호출된다.

OnMove : CWnd의 위치가 변경된 후에 호출된다.

OnMoving : 사용자가 CWnd 객체를 이동하고 있음을 나타낸다.

OnDeviceChange : 디바이스나 컴퓨터의 하드웨어 설정이 변경되었음을 알려준다.

OnStyleChanged : ::SetWindowLong 윈도우 함수를 사용하여 하나나 혹은 그 이상의 윈도우 의 스타일이 변했음을 알려준다.

OnStyleChanging : ::SetWindowLong 윈도우 함수를 사용하여 하나나 혹은 그 이상의 윈도 우의 스타일이 변하려 하는 것을 알려준다.

OnPaint : 윈도우의 일부분을 다시 그리기 위해서 호출된다.

OnParentNotify : 자식 윈도우가 생성되거나 소멸될 때, 또는 커서가 자식 윈도우 위에 있 는 동안 마우스 버튼을 클릭하는 경우에 호출된다.

OnQueryDragIcon : 최소화된 CWnd가 사용자에 의해서 드래그될 때 호출된다.

OnQueryEndSession : 사용자가 윈도우의 세션 종료를 선택하는 경우에 호출된다.

OnQueryNewPalette : CWnd가 입력 포커스를 받게됨을 알려준다.

OnQueryOpen : CWnd가 아이콘이거나 사용자가 아이콘이 열려지지기를 요구할 때 호출된다.

OnSetFocus : CWnd가 입력 포커스를 얻은 후에 호출된다.

OnShowWindow : CWnd가 감추어지거나 혹은 보여질 때 호출된다.

OnSize : CWnd의 크기가 변한 후에 호출된다.

OnSizing : 사용자가 사각형의 크기를 다시 조정하고 있음을 나타낸다.

OnStyleChanged : 윈도우의 하나나 혹은 그 이상의 스타일이 변한 것을 나타낸다.

OnStyleChanging : 윈도우의 하나나 혹은 그 이상의 스타일이 변하려 하는 것을 나타낸다. 


컨트롤 메시지 핸들러

OnCharToItem : LBS_WANTKEYBOARDINPUT 스타일을 가지고 있는 리스트 박스에 의해서 WM_CHAR에 대한 응답으로 호출된다.

OnCompareItem : 정렬이 가능한 owner draw 형태의 콤보 박스나 리스트 박스에서 새로운 아이템의 상대 위치를 지정하기 위해서 호출된다.

OnDeleteItem : owner draw 형태의 리스트 박스나 콤보 박스가 소멸되거나 아이템이 컨트 롤에서 제거될 때 호출된다.

OnDrawItem : owner draw 형태의 버튼 컨트롤, 콤보 박스 컨트롤, 리스트 박스 컨트롤이 다시 그려져야 할 때 호출된다.

OnGetDlgCode : 컨트롤이 화살표 키와 Tab 키에 대한 입력을 수행할 수 있도록 하기 위 해서 호출된다.

OnMeasureItem : 컨트롤이 생성될 때 owner draw 형태의 콤보 박스, 리스트 박스, 또는 메뉴 아이템을 요구한다. CWnd는 윈도우에게 컨트롤의 크기를 알려준다.

SendChildNotifyLastMsg : 부모 윈도우가 자식 윈도우에게 통보 메시지를 제공하여 자식 윈도우가 작업을 수행할 수 있도록 한다.

OnWndMsg : 윈도우의 메시지가 핸들링되고 있는 것을 나타낸다.

ReflectLastMsg : 자식 윈도우의 마지막 메시지를 나타낸다.

OnVKeyToItem : WM_KEYDOWN 메시지에 대하여 CWnd가 소유한 리스트 박스가 호출된다. 


입력 메시지 핸들러

OnChar : 키 입력이 시스템 문자가 아닌 문자로 변환될 때 호출된다.

OnDeadChar : 키 입력이 시스템 문자가 아닌 Dead 문자로 변환될 때 호출된다.

OnHSroll : 사용자가 CWnd의 수평 스크롤 바를 클릭하는 경우에 호출된다.

OnKeyDown : 시스템 키가 아닌 키보드가 눌러 졌을 때 호출된다.

OnKeyUp : 시스템 키가 아닌 키보드가 놓을 때 호출된다.

OnLButtonDblClk : 사용자가 왼쪽 버튼을 더블 클릭 했을 때 호출된다.

OnLButtonDown : 사용자가 왼쪽 버튼을 눌렀을 때 호출된다.

OnLButtonUp : 사용자가 왼쪽 버튼을 놓을 때 호출된다.

OnMButtonDblClk : 사용자가 가운데 버튼을 더블 클릭 했을 때 호출된다.

OnMButtonDown : 사용자가 가운데 버튼을 눌렀을 때 호출된다.

OnMButtonUp : 사용자가 가운데 버튼을 놓을 때 호출된다.

OnMouseActivate : 커서가 비활성화된 윈도우에 있고 사용자가 마우스 버튼을 누를 때 호출된다.

OnMouseMove : 마우스커서가 움직일 때 호출된다.

OnRButtonDblClk : 사용자가 오른쪽 버튼을 더블 클릭 했을 때 호출된다.

OnRButtonDown : 사용자가 오른쪽 버튼을 눌렀을 때 호출된다.

OnRButtonUp : 사용자가 오른쪽 버튼을 놓을 때 호출된다.

OnSetCuror : 마우스 입력이 캡쳐되지 않고 마우스가 윈도우에서 커서를 움직이게 하려면 호출된다.

OnTimer : SetTimer에서 정해진 간격마다 호출된다.

OnVScroll : 사용자가 윈도우의 수직 스크롤 바를 클릭할 때 호출된다.

OnCaptureChanged : 마우스 캡쳐를 놓치는 윈도우 메시지를 보낸다. 


비 클라이언트 영역 메시지 핸들러

OnNcActivate : 비 클라이언트 영역이 활성화된 상태인지 비활성화된 상태인지를 가리키 기 위해서 변환이 필요한 경우 호출된다.

OnNcCalcSize : 비 클라이언트 영역의 크기와 위치가 계산될 때 호출된다.

OnNcCreate : 비 클라이언트 영역이 생성될 때 OnCreate 보다 먼저 호출된다.

OnNcDestroy : 비 클라이언트 영역이 소멸될 때 호출된다.

OnNcHitTest : CWnd가 커서를 포함하고 SetCapture로 마우스 입력을 캡쳐할 때 마우스가 움직일 때 마다 윈도우에 의해서 호출된다.

OnNcLButtonDblClk : 커서가 CWnd의 비 클라이언트 영역 내에 있는 동안 사용자가 왼쪽 마우스 버튼을 더블 클릭 했을 때 호출된다.

OnNcLButtonDown : 커서가 CWnd의 비 클라이언트 영역 내에 있는 동안 사용자가 왼쪽 마우스 버튼을 눌렀을 때 호출된다.

OnNcLButtonUp : 커서가 CWnd의 비 클라이언트 영역 내에 있는 동안 사용자가 왼쪽 마우스 버튼을 놓을 때 호출된다.

OnNcMButtonDblClk : 커서가 CWnd의 비 클라이언트 영역 내에 있는 동안 사용자가 가운데 마우스 버튼을 더블 클릭 했을 때 호출된다.

OnNcMButtonDown : 커서가 CWnd의 비 클라이언트 영역 내에 있는 동안 사용자가 가운데 마우스 버튼을 눌렀을 때 호출된다.

OnNcMButtonUp : 커서가 CWnd의 비 클라이언트 영역 내에 있는 동안 사용자가 가운데 마우스 버튼을 놓을 때 호출된다.

OnNcMouseMove : 커서가 CWnd의 비 클라이언트 영역 내에서 이동할 때 호출된다.

OnNcPaint : 비클라이언트 영역이 다시 그려지기를 요구할 때 호출된다.

OnNcRButtonDblClk : 커서가 CWnd의 비 클라이언트 영역 내에 있는 동안 사용자가 오른쪽 마우스 버튼을 더블 클릭 했을 때 호출된다.

OnNcRButtonDown : 커서가 CWnd의 비 클라이언트 영역 내에 있는 동안 사용자가 오른쪽 마우스 버튼을 눌렀을 때 호출된다.

OnNcRButtonUp : 커서가 CWnd의 비 클라이언트 영역 내에 있는 동안 사용자가 오른쪽 마 우스 버튼을 놓을 때 호출된다. 


MDI 메시지 핸들러

OnMDIActivate : MDI child 윈도우가 활성화되거나 비활성화될 때 호출된다. 


클립보드 메시지 핸들러

OnAskCbFormatName : 클립보드의 소유자가 클립보드의 내용을 나타낼 때 클립보드 뷰어 애플리케이션에 의해서 호출된다.

OnChangeCbChain : 특정 윈도우가 체인에서 제거되었는지를 통지한다.

OnDestroyClipboard : 클립보드가 윈도우 EmptyClipboard 함수의 호출에 의해서 비워지는 경우에 호출된다.

OnDrawClipboard : 문장이 변경되었을 때 호출된다.

OnHScrollClipboard : 클립보드의 소유주가 클립보드의 이미지를 스크롤해야 하고 적절한 섹션을 무효화할 때 호출되며, 스크롤 바의 값들을 갱신한다.

OnPaintClipboard : 클립보드 뷰어의 클라이언트 영역이 다시 그려져야 할 때 호출된다.

OnRenderAllForamts : 소유주 애플리케이션이 파괴되고 있고 모든 포맷들을 다시 만들 필 요가 있을 때 호출된다.

OnSizeClipboard : 클립보드 뷰어 윈도우의 클라이언트 영역의 크기가 변하는 경우에 호출 된다.

OnVSrollClipboard : 소유주가 크립보드 이미지 스크롤해야 하는 경우에 호출되며, 적절한 섹션을 무효화하고, 스크롤바 값들을 갱신한다. 


메뉴 루프 통지

OnEnterMenuLoop : 메뉴의 모달 루프가 수행되는 경우에 호출된다.

OnExitMenuLoop : 메뉴의 모달 루프가 마치는 경우에 호출된다. 



4. 디바이스 컨텍스트 클래스

1) CDC 클래스

- CDC 객체는 디스플레이 또는 프린터와 같이 윈도우 클라이언트 영역과 관련된 디스 플레이 컨텍스트와 관계된 작업을 수행하기 위한 멤버 함수를 제공한다. 

데이터 멤버

m_hDC : CDC 객체에 의해서 사용되는 출력 디바이스 컨텍스트.

m_hAttribDC : CDC 객체에 의해서 사용되는 속성 디바이스 컨텍스트. 

생성 관련 함수

CDC : CDC 객체를 생성한다.

CreateDC : 특정 디바이스에 대한 디바이스 컨텍스트를 만든다.

CreateIC : 특정 디바이스에 대한 정보 컨텍스트를 만든다. 이것은 디바이스 컨텍스트를 만들지 않고 디바이스에 관한 정보만 빠르게 얻을 수 있는 방법을 제공한다.

CreateCompatibleDC : 다른 디바이스 컨텍스트와 호환이 가능한 메모리 디바이스 컨텍스 트를 만든다. 이것은 메모리에 이미지를 미리 읽어 들이기 위해서 사용할 수 있다.

DeleteDC : CDC 객체와 관련된 윈도우 디바이스 컨텍스트를 삭제한다.

FromHandle : 디바이스 컨텍스트에 대한 핸들이 주어졌을 때 CDC 객체에 대한 포인터를 반환한다. 만약 CDC 객체가 핸들과 연관되지 않았다면 임시로 CDC 객체를 만들고 핸들을 추가한다.

DeleteTempMap : FromHandle에 의해서 만들어진 임시 CDC 객체를 삭제하기 위해서 CWinApp가 유휴 시간 핸들러를 사용해서 호출하도록 한다. 이것은 디바이스 컨텍스트로 부터 핸들을 분리시킨다.

Attach : CDC 객체에 윈도우 핸들을 추가한다.

Detach : CDC 객체로부터 윈도우 핸들을 분리한다.

SetAttribDC : 속성 디바이스 컨텍스트인 m_hAttribDC를 설정한다.

SetOutputDC : 출력 디바이스 컨텍스트인 m_hDC를 설정한다.

ReleaseAttribDC : 속성 디바이스 컨텍스트인 m_hAttribDC를 해제한다.

ReleaseOutputDC : 출력 디바이스 컨텍스트인 m_hDC를 해제한다.

GetCurrentBitmap : 현재 선택된 CBitmap 객체에 대한 포인터를 반환한다.

GetCurrentBrush : 현재 선택된 CBrush 객체에 대한 포인터를 반환한다.

GetCurrentFont :현재 선택된 CFont객체에 대한 포인터를 반환한다.

GetCurrentPalette : 현재 선택된 CPalette 객체에 대한 포인터를 반환한다.

GetCurrentPen : 현재 선택된 CPen 객체에 대한 포인터를 반환한다.

GetWindow : 디스플레이 디바이스 컨텍스트와 관련된 윈도우를 반환하다. 

디바이스 컨텍스트 관련 함수

GetSafeHdc : 출력 디바이스 컨텍스트인 m_hDC를 반환한다.

SaveDC : 디바이스 컨텍스트의 현재 상태를 저장한다.

RestoreDC : SaveDC로 저장하기 이전 상태로 디바이스 컨텍스트를 복원한다.

ResetDC : m_hAttribDC 디바이스 컨텍스트를 갱신한다.

GetDeviceCaps : 주어진 디스플레이 디바이스의 성능에 관한 세부적인 디바이스 정보를 얻어 온다.

IsPrinting : 디바이스 컨텍스트가 인쇄를 위해서 사용될지의 여부를 결정한다. 



드로잉 도구(drawing tool)

관련 함수

GetBrushOrg : 현재의 브러시의 원점 값을 얻는다.

SetBrushOrg : 디바이스 컨텍스트에서 선택된 브러시의 원점을 설정한다.

EnumObjects : 디바이스 컨텍스트에서 이용할 수 있는 펜들과 브러시들을 열거한다. 



선택 helper 함수

SelectObject : 펜들과 같은 GDI 드로잉 객체를 선택한다.

SelectStockObject : 미리 정의된 스톡 펜, 브러시 또는 윈도우에 의해서 제공되는 폰트 중 에서 하나를 선택한다. 


컬러와 컬러

팔레트 관련 함수

GetNearestColor : 지정된 디바이스가 나타낼 수 있는 논리 컬러에 가장 근접한 논리 컬러 를 얻는다.

SelectPalette : 논리 팔레트를 선택한다.

RealizePalette : 시스템 팔레트에 현재 논리 팔레트의 항목들을 매핑한다.

UpdatedColors : 픽셀당 픽셀을 기본으로 시스템 팔레트를 이용하여 현재 클라이언트 영 역을 일치시킴으로써 디바이스 컨텍스트의 클라이언트 영역을 갱신한다.

GetHalftoneBrush : 하프톤 브러시를 얻어온다. 



드로잉 속성 관련 함수

GetBkColor : 현재의 배경색을 얻는다.

SetBkColor : 현재의 배경색을 설정한다.

GetBkMode : 배경 모드를 얻는다.

SetBkMode : 배경 모드를 설정한다.

GetPolyFillMode : 현재의 다각형을 채우기 위한 모드를 얻어 온다.

SetPolyFillMode : 다각형을 채우기 위한 모드를 설정한다.

GetROP2 : 현재의 드로잉 모드를 얻는다.

SetROP2 : 현재의 드로잉 모드를 설정한다.

GetStretchBltMode : 현재의 비트맵 확대 모드를 얻는다.

SetStretchBltMode : 비트맵 확대 모드를 설정한다.

GetTextColor : 현재의 텍스트 컬러를 얻는다.

SetTextColor : 텍스트 컬러를 설정한다.

GetColorAdjustment : 디바이스 컨텍스트에 대한 컬러 보정 값을 얻는다.

SetColorAdjustment : 특정 값을 사용하여 디바이스 컨텍스트에 대한 컬러 보정 값을 설정 한다. 

매핑 관련 함수

GetMapMode : 현재의 매핑 모드를 얻는다.

SetMapMode : 현재의 매핑 모드를 설정한다.

GetViewportOrg : 뷰포트의 원점의 x와 y좌표를 얻는다.

SetViewportOrg : 뷰포트의 원점을 설정한다.

OffsetViewportOrg : 현재 뷰포트 원점의 좌표와 관련된 뷰포트의 원점을 수정한다.

GetViewportExt : 뷰포트의 x와 y좌표를 얻는다.

SetViewportExt : 뷰포트의 x와 y좌표를 설정한다.

ScaleViewportExt : 현재 값과 관련있는 뷰포트의 범위를 수정한다.

GetWindowOrg : 관련된 윈도우의 원점에 대한 x와 y 좌표를 얻는다.

SetWindowOrg : 디바이스 컨텍스트의 윈도우 원점을 설명한다.

OffsetWindowOrg : 현재의 윈도우 원점의 좌표와 관련된 윈도우의 원점을 수정한다.

GetWindowExt : 관련된 윈도우의 x와 y의 범위를 얻는다.

SetWindowExt : 관련된 윈도우의 x와 y의 범위를 설정한다.

ScaleWindowExt : 현재 값과 관련있는 윈도우의 범위를 수정한다.




좌표 변환 함수

DPtoHTMETRIC : 디바이스 단위를 HTMETRIC 단위로 변환한다.

DPtoLP : 디바이스 단위를 논리 단위로 변환한다.

HTMETRICtoDP : HTMETRIC 단위를 디바이스 단위로 변환한다.

HTMETRICtoLP : HTMETRIC 단위를 논리 단위로 변환한다.

LPtoDP : 논리 단위를 디바이스 단위로 변환한다.

LPtoHTMETRIC : 논리 단위를 HTMETRIC 단위로 변환한다.




영역 관련 함수

FillRgn : 지정된 브러시로 특정 영역을 채운다.

FrameRgn : 브러시를 사용하여 특정 영역 주위의 경계선을 그린다.

InvertRgn : 영역에 있는 컬러들을 전부 반전시킨다.

PaintRgn : 선택한 브러시로 특정 영역을 채운다. 


클리핑(clipping)관련 함수

SetBoundsRect : 지정된 디바이스 컨텍스트에 대한 사각형 경계영역의 정보를 설정한다.

GetBoundsRect : 지정된 디바이스 컨텍스트에 대해서 현재 설정된 사각형 경계영역의 정 보를 반환한다.

GetClipBox : 화면의 클리핑 경계에 가장 가까운 사각형의 크기를 얻는다.

SelectClipRgn : 특정 모드를 사용하여 현재 클리핑 영역과 조합한다.

ExcludeClipRect : 현재의 클리핑 영역에서 지정된 사각형 영역을 빼낸 후에 새로운 클리핑 영역을 생성한다.

ExcludeUpdateRgn : 클리핑 영역에서 윈도우에 있는 갱신될 영역을 제외함으로써 유효하지 않은 영역에 그려지는 것을 막는다.

IntersectClipRect : 현재 영역과 사각형의 교차 영역을 만들어서 새로운 클리핑 영역을 만 든다.

OffsetClipRgn : 주어진 디바이스의 클리핑 영역 x 축과 y 축으로 각각 이동한다.

PtVisible : 클리핑 영역에 주어진 점이 존재하는지의 여부를 알아낸다.

RectVisible : 주어진 사각형의 임의의 부분이 클리핑 영역 내에 있는지를 알아낸다. 


선 출력 함수

GetCurrentPosition : 펜의 현재 좌표를 얻는다.

MoveTo : 현재 좌표를 이동한다.

LineTo : 현재 좌표에서 지정된 좌표까지 선을 그린다.

Arc : 타원형의 호를 그린다.

Arcto : 타원형의 호를 그린다. (현재 좌표가 갱신되는 것을 제외하면 Arc와 비슷하다.)

AngleArc : 선분과 호를 그리고 현재 좌표를 호의 끝점으로 이동한다.

GetArcDirection : 디바이스 컨텍스트에서 현재 호를 그리는 방향을 반환한다.

SetArcDirection : 호와 사각형을 그리기 위한 방향을 설정한다.

PolyDraw : 선분과 베지어 스플라인을 그린다. 이 함수는 현재 좌표를 갱신한다.

PolyLine : 지정된 점들을 연결하는 선을 그린다.

PolyPolyLine : 연결된 선을 여러 개 그린다. 현재 좌표는 함수에 의해서 사용되거나 갱신되지 않는다.

PolyLineTo : 하나 이상의 직선을 그리고 마지막 선의 끝점으로 현재 좌표를 이동한다.

PolyBezier : 하나 이상의 베지어 스플라인을 그린다. 현재 좌표는 사용되나 갱신되지 않는 다.

PolyBezierTo : 하나 이상의 베지어 스플라인을 그리고 마지막 베지어 스플라인의 끝점으로 현재 좌표를 이동한다. 


단순 드로잉 함수

FillRect : 특정 브러시를 사용하여 지정된 사각형을 채운다.

FrameRect : 사각형 주변에 경계선을 그린다.

InvertRect : 사각형 내부를 반전시킨다.

DrawIcon : 아이콘을 그린다.

DrawDragRect : 드래그된 사각형을 지우거나 다시 그린다.

FillSolidRect : 솔리드 컬러로 사각형을 채운다.

Draw3dRect : 3차원 형태의 사각형을 그린다.

DrawEdge : 사각형의 모서리를 그린다.

DrawFrameControl : 프레임 컨트롤을 그린다.

DrawState : 이미지를 출력하고 현재 상태를 나타내는 효과를 적용한다. 


타원과 다각형(Polygon) 함수

Chord : 현을 그린다.

DrawFocusRect : 포커스를 가지고 있는 형태로 사각형을 그린다.

Ellipse : 타원을 그린다.

Pie : 파이 모양을 그린다.

Polygon : 선들에 의해서 연결된 두 개 이상의 점들로 이루어지는 다각형을 그린다.

PolyPolygon : 현재의 다각형 채우기 모드를 사용하여 두 개 이상의 다각형을 그린다. 이 다각형들은 합쳐지지는 않지만 겹쳐질 수는 있다.

Polyline : 지정된 점들을 연결하는 선들의 조합으로 이루어진 다각형을 그린다.

Rectangle : 현재의 펜을 사용하여 사각형을 그리고 현재의 브러시를 사용하여 사각형을 채운다.

RoundRect : 현재의 펜을 사용하여 모서리가 둥근 형태의 사각형을 그리고, 현재의 브러시 를 사용하여 채운다. 


비트맵 함수

PatBlt : 비트 패턴을 만든다.

BitBlt : 지정된 디바이스 컨텍스트에서 비트맵을 복사한다.

StretchBlt : 디바이스의 원본 사각형에서 대상 사각형으로 비트맵을 이동시킨다. 비트맵의 크기가 대상 사각형의 원본보다 크거나 작다면 비트맵을 적당히 늘리거나 줄여서 이동시킨다.

GetPixel : 지정된 픽셀의 RGB컬러 값을 얻는다.

SetPixel : 지정된 컬러의 근사값으로 지정된 좌표에 점을 찍는다.

SetPixelV : 지정된 컬러의 근사값으로 지정된 좌표에 점을 찍는다. SetPixelV는 찍힌 점의 컬러 값을 반환할 필요가 없기 때문에 SetPixel보다 더 빠르다.

FloodFill : 현재의 브러시를 사용하여 영역을 채운다.

ExtFloodFill : 현재의 브러시로 영역을 채운다. FloodFill 멤버함수보다는 약간의 유연성을 제공한다.

MaskBlt : 주어진 마스크와 래스터 연산을 사용하여 원본과 대상 비트맵에 대한 컬러 데이터를 합친다.

PlgBlt : 원본 디바이스 컨텍스트의 지정된 사각형에서 주어진 디바이스 컨텍스트의 지정 된 평행사변형 영역에 비트맵을 복사한다. 


텍스트 관련 함수

TextOut : 현재의 선택된 폰트를 사용하여 지정된 위치에 문자열을 출력한다.

ExtTextOut : 현재의 선택된 폰트를 사용하여 지정된 사각형의 영역 내에 문자열을 출력 한다.

TabbedTextOut : 탭이 멈추는 위치를 지정해 주면 그 위치에 문자열을 출력한다.

DrawText : 지정된 사각형 안에 포맷된 형태의 텍스트를 출력한다.

GetTextExtent : 크기를 결정하기 위해서 현재 폰트를 사용한 속성 디바이스 컨텍스트 상 에서 텍스트의 폭과 높이를 얻는다.

GetOutputTextExtent : 출력 디바이스 컨텍스트 상에서 텍스트의 폭과 높이를 얻는다.

GetTabbedTextExtent : 속성 디바이스 컨텍스트 상에서 주어진 탭 지정 문자열의 폭과 높이를 얻는다.

GetOutputTabbedTextExtent : 출력 디바이스 컨텍스트 상에서 주어진 탭 지정 문자열의 폭 과 높이를 얻는다.

GrayString : 주어진 위치에 희미하게 출력되는 텍스트를 출력한다.

GetTextAlign : 텍스트 정렬 플래그 값을 얻는다.

SetTextAlign : 텍스트 정렬 플래그 값을 설정한다.

GetTextFace : 버퍼에 현재 폰트의 폰트 이름을 복사한다.

GetTextMetrics : 속성 디바이스 컨텍스트에서 현재의 폰트에 대한 크기를 얻는다.

GetOutputTextMetrics : 출력 디바이스 컨텍스트에서 현재의 폰트에 대한 크기를 얻는다.

SetTextJustification : 문자열의 사이에 공백을 추가한다.

GetTextCharacterExtra : 현재 설정된 문자 사이의 공백을 얻는다.

SetTextCharacterExtra : 문자 사이의 공백을 설정한다. 


폰트 함수

GetFontData : 폰트의 크기 정보를 가변폭 폰트 파일로 얻는다. 얻기 위한 정보는 폰트 파일 안에 오프셋을 지정함으로써 구별되고, 반환된 정보의 길이 역시 구별된다.

GetKerningPairs : 현재 지정된 디바이스 컨텍스트에서 선택된 폰트에 대한 문자 kerning 쌍을 얻는다.

GetOutputTextMetrics : 트루 타입 폰트에 대한 폰트 크기 정보를 얻는다.

GetGlyphOutline : 현재의 폰트에서 외곽선 문자에 대한 곡선 또는 비트맵을 얻는다.

GetCharABCWidths : 지정된 범위에 있는 연속된 문자의 폭을 논리 단위로 얻는다.

GetCharWidth : 속성 디바이스 컨텍스트에서 연속된 문자열에 대한 개별 문자의 폭을 얻는다.

GetOutputCharWidth : 출력 디바이스 컨텍스트에서 연속된 문자열에 대한 개별 문자의 폭 을 얻는다.

SetMapperFlags : 논리적인 폰트를 물리적인 폰트로 매핑할 때 폰트 매퍼가 사용할 알고리즘을 설정한다.

GetAspectRatioFilter : 현재 폰트의 종횡비 필터에 대한 설정 값을 얻는다. 


프린터 확장 함수

QueryAbort : 애플리케이션에서 인쇄를 수행하거나 혹은 인쇄가 종료되었는지를 쿼리하기 위한 AbortProc 콜백함수를 호출한다.

Escape : GDI를 통해서 특별한 디바이스에 직접 사용할 수 없는 부분을 참조하기 위해서 애플리케이션을 허용하도록 한다. 또한 윈도우 확장 함수에 대한 참조를 허가한다

. 애플리케이션에 의해서 만들어진 Escape 호출은 적절히 변환되어 디바이스 드라이버에게 보내진다.

DrawEscape : GDI를 통해서 직접적으로 이용할 수 없는 비디오 디스플레이의 드로잉 능력을 참조한다.

StartDoc : 새로운 인쇄 작업이 시작되었음을 디바이스 드라이버에게 알린다.

StartPage : 새로운 페이지가 시작되었음을 디바이스 드라이버에게 알린다.

EndPage : 페이지가 끝났음을 디바이스 드라이버에게 알린다.

SetAbortProc : 인쇄 작업이 중단될 때 프로그래머가 작성한 콜백 함수를 호출할 수 있도록 설정한다.

AbortDoc : 애플리케이션이 StartDoc 멤버 함수의 마지막 호출 후에 디바이스 컨텍스트에 출력한 모든 내용을 지우고 현재의 인쇄 작업을 종결한다.

EndDoc : StartDoc 멤버 함수에 의해서 시작된 인쇄 작업을 마친다. 


스크롤 관련 함수

ScrollDC : 직사각형 영역을 수평과 수직으로 스크롤한다. 


메타 파일 관련 함수

PlayMetaFile : 주어진 디바이스 상에서 지정된 메타 파일의 내용을 수행한다. PlayMetaFile 의 확장된 버전은 주어진 확장 포맷 메타 파일에 저장된 그림을 출력한다. 메타 파일 은 원하는 만큼 재생이 가능하다.

AddMetaFileComment : 버퍼에서 지정된 확장 포맷 형태의 메타 파일로 주석을 복사한다. 


경로 함수

AbortPath : 디바이스 컨텍스트에서 임의의 경로를 닫고 없앤다.

BeginPath : 디바이스 컨텍스트에서 경로 대괄호를 연다.

CloseFigure : 경로에서 열려있는 도형을 닫는다.

EndPath : 경로 대괄호를 닫고 디바이스 컨텍스트에서 대괄호로 정의된 경로를 선택한다.

FillPath : 현재 경로에 열려 있는 도형들을 닫고 현재의 브러시와 다각형을 채우기 위한 모드를 사용하여 경로의 내부를 채운다.

FlattenPath : 현재의 디바이스 컨텍스트의 선택된 경로에서 임의의 곡선을 전달하고 연속 된 선으로 변환한다.

GetMiterLimit : 디바이스 컨텍스트에 대한 미터 제한을 반환한다.

GetPath : 선의 끝점을 정의하는 좌표를 얻고 곡선의 제어점을 디바이스 컨텍스트에서 선택된 경로에서 찾는다.

SelectClipPath : 현재의 경로를 지정된 모드를 사용하여 기존의 클리핑 영역과 새로운 영 역을 결합한 디바이스 컨텍스트를 위한 클리핑 영역을 선택한다.

SetMiterLimit : 디바이스 컨텍스트를 위한 미터 결합의 한계를 설정한다.

StrockeAndFillPath : 경로 상에 열려 있는 도형을 닫고, 현재의 펜을 사용하여 경로의 외곽선을 그린 후에 현재의 브러시를 사용하여 내부를 채운다.

StrockPath : 현재의 펜을 사용하여 지정된 경로를 표현한다.

WidenPath : 디바이스 컨텍스트에서 선택된 현재의 펜으로 경로가 그려지면, 그 영역이 그려짐으로 인해서 현재 경로를 다시 정의하게 된다. 



2) CDC 파생 클래스들 

  • CPaintDC 클래스 


    데이터 멤버

    m_ps : 클라이언트 영역을 그리기 위해서 PAINTSTRUCT 를 포함한다.

    m_hWnd : CPaintDC 객체에 추가되는 HWND 


    생성

    CPaintDC : 지정된 CWnd와 연결된 CPaintDC를 생성한다. 


  • CClientDC 클래스 

    데이터 멤버

    m_hWnd : CClientDC 객체에 추가되는 HWND 

    생성

    CClientDC : 지정된 CWnd에 연결된 CClientDC를 생성한다. 

  • CWindowDC 클래스 

    데이터 멤버

    m_hWnd : CWindowDC 객체에 추가되는 HWND 

    생성

    CWindowDC : CWindowDC 객체를 생성한다. 


  • CMetaFileDC 클래스

    생성

    CMetaFileDC : CMetaFileDC 객체를 생성한다. 


    초기화

    Create : 윈도우 메타파일 디바이스 컨텍스트를 생성하여 CMetaFileDC객체에 추가한다.

    CreateEnhanced : 개선된 포맷의 메타파일에 대한 디바이스 컨텍스트를 생성한다. 


    역할

    Close : 디바이스 컨텍스트를 종료하고 메타파일의 핸들을 생성한다.

    CloseEnhanced : 개선된 포맷의 메타파일에 대한 디바이스 컨텍스트를 종료하고 개선된 포맷의 메타파일에 대한 핸들을 생성한다. 


    3) CGdiObject 클래스

    - CGdiObject 클래스는 비트맵, 영역, 브러시, 팬, 폰트처럼 그래픽 처리를 위한 다양한 GDI 객체를 사용하기 위한 베이스 클래스를 제공한다. 그러나 직접 CGdiObject 객체를 생성 할 수는 없다. CBitmap, CBrush, CFont, CPalette, CPen, CRgn 와 같은 파생 클래스로 부터 객체를 생성해야 한다. 

    데이터 멤버

    m_hObject : 이 객체에 추가된 HBITMAP, HPALETTE, HRGN, HBRUSH, HPEN, HFONT를 포함하 는 핸들값이다. 

    생성

    CGdiObject : CGdiObject 객체를 생성한다. 


    역할

    GetSafeHandle : this 포인터가 NULL이 아니면 m_hObject를 반환하고 그렇지 않으면 NULL을 반환한다.

    FromHadle : 윈도우 GDI 객체의 핸들에 부여된 CGdiObject에 대한 포인터를 반환한다.

    Attach : 윈도우 GDI 객체를 CGdiObject 객체에 추가한다.

    Detach : CGdiObject 객체에서 윈도우 GDI 객체를 분리하고 윈도우 GDI 객체에 대한 핸들 을 반환한다.

    DeleteObject : 객체와 관련된 시스템 저장 장소를 모두 해제함으로써 메모리에서 CGdiObject 객체에 추가된 윈도우 GDI 객체를 삭제한다.

    DeleteTempMap : FromHandle에 의하여 작성된 임시 CGdiObject 객체를 삭제한다.

    GetObject : CGdiObject 객체에 추가된 윈도우 GDI 객체를 설명하기 위한 데이터를 저장하 는 버퍼를 채운다.

    CreateStockObject : 이미 정의된 스톡펜, 브러시, 폰트 중에서 하나의 핸들을 얻는다.

    UnrealizeObject : 논리 팔레트나 브러시의 원점을 재설정한다.

    GetObjectType : GDI 객체의 타입을 얻는다.


  • ----------------------------------------------------------------------
    출처 : http://user.chollian.net/~ksupark/mfc.htm
    신고
    TRACKBACK 1 AND COMMENT 0

    리스트뷰 컨트롤(ListView Control)

    이 강좌는 Zafir Anjum 의 홈페이지에 올라와 있는 ListView 컨트롤에 대한 내용들을 번역한 것입니다. 다른곳에 올리셔도 상관은 없지만 편집은 하지말아 주시기 바랍니다.영어실력이 짧아서 번역이 좀 매끄럽지 못하네요.. 더군다나 MFC 도 잘모르니...보시고 수정할 부분 있으시면 메일주셔용..

    Zafir 의 홈페이지는 http://www.dsp.com/zafir/ 입니다.

    이곳에 ListView 말고도 TreeView,Property Sheet 에 대한 강좌도 올라와 있습니다. 물론 영어로요... ( ListView 번역이 끝나면 요것들도 할예정 입니다.) MFC&T 소모임 시삽 권정혁

    리스트뷰 컨트롤(ListView Control) Tips & Tricks #1

    1. 서론 (Introduction)
    파생된 CListCtrl 을 CListView 와 같이 쓸려면 어떻게 하나요 ?
    파생된 CListCtrl 을 CListView 안에서 사용하기 - Undocumented
    2. 이미지 사용하기 (Using Images)
    이미지 리스트초기화
    아이템에 대한 이미지를 설정하거나 제거하기
    비규격(Non-Standard)크기의 이미지 설정하기
    이미지의 Late Binding(음.. 이걸 한글로 뭐라 하죠?) - I_IMAGECALLBACK
    3. 뷰(View)
    보기형태(View Style)를 바꾸기
    4. 컬럼(Columns)
    Header 컨트롤
    자세히 보기(Report View)모드에서 컬럼갯수 알아내기
    컬럼 추가하기
    클릭된 아이템의 컬럼인덱스 알아내기
    컬럼크기 조정 방지하기
    최소 컬럼 넓이 설정하는 방법은 ?
    5. 선택(Selection)
    프로그램적으로(Programmatically) 아이템 선택하기
    왼쪽끝컬럼에 클릭하지 않았더라도 아이템 선택하기
    열들을 선택,해제(Selecting & Deselecting)하기
    6. 아이템과 하부아이템 편집하기(Editing items and subitems)
    아이템들을 편집가능하도록 하기
    프로그램적으로 아이템 편집하기
    편집가능한 하부아이템들
    하부아이템 편집을 위해 드롭다운 리스트 사용하기
    7. 정렬(Sorting)
    리스트를 컬럼에 관계없이 문자열기준으로 정렬하기
    편집후에 자동적으로 재정렬 하기
    사용자가 컬럼 헤더에 클릭시 리스트 정렬하기
    8. 격자선(Grid lines)
    컬럼 테두리를 위한 세로줄
    가로,세로 격자선 그리기
    9. 툴팁과 타이틀팁(Tooltip & Titletip)
    헤더를 위한 툴팁
    각각의 컬럼 헤더를 위한 툴팁
    각 셀을 위한 툴팁
    각 셀을 위한 타이틀팁
    10.드래그 와 드롭(Drag & Drop)
    컬럼 순서를 바꾸기위해 컬럼 드래깅하기
     
     

     

    1. 서론 ( Introduction )

     

    1.1 파생된 CListCtrl 을 CListView 와 같이 쓸려면 어떻게 하나요 ?

    짧은 답은 "할필요가 없습니다." 입니다.

    길게 답변하면 , 파생된 CListCtrl을 CListView와 같이 사용하는 대신CListView로 부터 파생해서 이 파생된 클래스에 같은 기능들을 추가하십시오.이렇게 하는 이유는 MFC가 하나의 윈도우나 컨트롤에 단 하나의 C++ 객체가 연결되도록 디자인 되었기 때문입니다. CListView을 사용한다면 리스트 뷰컨트롤이 이미 View 클래스와 연결되어있고, 때문에 당신은 이것에 연결된 다른 C++ 객체를 가질수 없습니다.GetListCtrl() 함수는 실제로 CListCtrl 에 대한 포인터로 캐스팅된 CListView에 대한 포인터를 리턴합니다. 따라서 GetListCtrl() 함수가 리턴한 포인터는 실제로 CListCtrl 이 아닌 CListView 를 가리키고 있습니다.

    이제 해야할 작업은 CListView 로 부터 상속받아서 CListCtrl 에 해야할 일들,즉 함수와 메소드 핸들러를 만드는 일들입니다. 클래스 위자드는 CListCtrl에 제공하는 모든 윈도우 메시지들을 CListView로부터 파생된 클래스들에게 똑같이 제공합니다.

    파생한 CListCtrl이 LVN_ENDLABELEDIT 통지(Notification)를 처리해야 한다고 가정해 봅시다. 이 기능을 CListView 로부터 파생한 클래스에 추가하려면,간단히 클래스 위자드를 사용해서 메시지 핸들러를 CListCtrl 파생클래스에 추가하고, CListView 로 부터 파생된 클래스에 그 코드를 복사하는 겁니다.그리고, 마지막으로 CListCtrl의 모든 메소드앞에 GetListCtrl()-> 를 써주는 겁니다.

    (아래 예제에서 /********/ 된 윗 부분을 보세요)
    void CMyListCtrl::OnEndLabelEdit(LPNMHDR pnmhdr, LRESULT *pLResult)
    {
    LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pnmhdr;
    LV_ITEM *plvItem = &plvDispInfo->item;
    if (plvItem->pszText != NULL)
    SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
    }
    void CMyListView::OnEndLabelEdit(LPNMHDR pnmhdr, LRESULT *pLResult)
    {
    LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pnmhdr;
    LV_ITEM *plvItem = &plvDispInfo->item;
    if (plvItem->pszText != NULL)
    GetListCtrl()->SetItemText(plvItem->iItem, plvItem->iSubItem,
    /***************/ plvItem->pszText);
    }
     

    1.2 파생된 CListCtrl 을 CListView 안에서 사용하기 - Undocumented

    1.1의 답변으로 만족하지 못했다면 이번것이 만족시켜 줄지도 모르겠군요...어쨋든 좀 위험이 있습니다. 이것은 MFC 의 문서화되지 않은 기능(?)을 사용하며 제가 모든 부분을 알지는 못 할수도 있습니다. 그러니 위험부담을 가지고 사용하십시오. 이일이 가능하도록 하는데 기본 아이디어는, 두개의 CListCtrl 멤버 변수를 만들어 실제 컨트롤에 연결하고 윈도우 메시지를 CListCtrl 객체에 흘리는(funnel) 것입니다. 실제 List View 컨트롤은 CListView 파생객체가 소유하고 있으며 MFC 는 한 개의 컨트롤이 여러 개의 C++ 객체에 소유되는 것을 허락하지 않습니다. 아래에서 CMyListCtrl 은 CListCtrl 파생 클래스로 CListView로부터 파생한 CListVw 안에서 사용하기 위한 클래스입니다.

    단계 1: CMyListCtrl로부터 새로운 클래스 상속 받기 새로운 클래스를 상속 받는데는 2가지 이유가 있습니다. 첫째, ClistView 파생 클래스가 CListCtrl의 Protected Member들중 몇개에 접근해야 하기 때문입니다. 따라서 이 클래스는 CListView 파생 클래스를 프렌드로 선언 합니다. 둘째, AssertValid() 함수를 오버라이드 합니다. AssertValid() 함수는 디버그 빌드에 대해 정의되어 있고, 우리가 오버라이드한 함수는 아무 일도 하지 않습니다. 원래 버젼은 우리가 만든 객체가 MFC 가 보기에 제대로된 상태에 있지않다고 얘기 할것입니다(assert).

     

    class CFriendlyListCtrl : public CMyListCtrl
    {
    CFriendlyListCtrl() {};
    #ifdef _DEBUG
    void AssertValid() const {}
    #endif
    friend class CListVw;
    };
     

    단계 2: CListVw 에 멤버변수를 추가합니다.

    CListVw에 CFriendlyListCtrl타입의 Protected 멤버를 추가합니다. 우리는 이 객체를 리스트 뷰 컨트롤에 연결하고 메시지를 보내는 경로로 사용할것 입니다. 이 객체를 GetListCtrl()을 사용해야할 모든 곳에 사용하십시오.

    protected:
    CFriendlyListCtrl m_listctrl;

    단계 3: CListVw 의 OnCreate를 오버라이드 합니다.

    OnCreate() 함수를 오버라이드 합니다. 프레임워크는 윈도우가 만들어지자 마자 바로 이 함수를 호출합니다. Base Class Version의 이 함수를 호출 하고나서 우리는 멤버변수 m_listctrl 을 초기화 합니다. 컨트롤의 핸들을 m_hWnd 멤버에 지정(assign)합니다. 이 멤버는 CWnd 파생클래스의 수많은 함수들에서 사용됩니다. 아마도 다음 변수는 익숙치 않을것입니다. m_pfnSuper 변수는 함수에 대한 포인터로 MFC 에 의해 서브클래스되기 전의 WndProc 주소를 가리키고 있습니다. 우리는 PreSubclassWindow()함수 를 호출하여 이 함수안의 모든 코드를 실행되도록 합니다.

    int CListVw::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    if (CListView::OnCreate(lpCreateStruct) == -1)
    return -1;
    m_listctrl.m_hWnd = m_hWnd;
    m_listctrl.m_pfnSuper = m_pfnSuper;
    m_listctrl.PreSubclassWindow();
    }
     

    단계 4: 메시지 핸들러 함수를 오버라이드 하기

    우리가 오버라이드해야할 메시지 핸들러 함수는 모두 세개 입니다. 이들 각각에서 만약 CListVw 클래스가 메시지를 처리하지 않는다면 우리는 그것을 CMyListCtrl 클래스로 전달해야 합니다.

    BOOL CListVw::PreTranslateMessage(MSG* pMsg)
    {
    if( ! CListView::PreTranslateMessage(pMsg) )
    return m_listctrl.PreTranslateMessage(pMsg);
    return FALSE;
    }
    LRESULT CListVw::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
    {
    LRESULT lResult = 0;
    if (!OnWndMsg(message, wParam, lParam, &lResult))
    if( !m_listctrl.OnWndMsg(message, wParam, lParam, &lResult))
    lResult = DefWindowProc(message, wParam, lParam);
    return lResult;
    }
    BOOL CListVw::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam,
    LRESULT* pLResult)
    {
    if( !CListView::OnChildNotify(message, wParam, lParam, pLResult) )
    return m_listctrl.OnChildNotify(message, wParam, lParam, pLResult);
    return FALSE;
    }
     

    2. 이미지 사용하기 (Using Images)


    2.1 이미지 리스트 초기화

    리스트 뷰 컨트롤은 CDialog 의 OnInitDialog() 함수나 CFormView의 OnInitialUpdate() 함수에서 초기화가 되어야 합니다. 리스트뷰 컨트롤은 세 개의 이미지 리스트를 연결 할 수있습니다. 두개는 아이콘들을 위한것이고, 하나는 상태 이미지(State Image)를 위한것입니다.

    단계는 다음과 같습니다.

    1. CDialog 나 CFormView 상속 클래스에서 CImageList 형의 변수들을 선언합니다.
    2. OnInitDialog() 나 OnInitialUpdate() 함수에서 CImageList 멤버 변수들에게 Create() 함수를 호출합니다.
    3. 리스트 뷰 컨트롤의 SetImageList() 함수를 호출합니다.
     
    예제 코드 입니다.
    //Create from bitmap resource
    m_imgIcon.Create( IDB_LARGEICONS, 32, 1, (COLORREF)-1 );
    //Set the image list
    m_listctrl.SetImageList( &m_imgIcon, LVSIL_NORMAL );
    m_imgIconSmall.Create( IDB_SMALLICONS, 16, 1, (COLORREF)-1 );
    m_listctrl.SetImageList( &m_imgIconSmall, LVSIL_SMALL );

    이미지 리스트는 LVS_ICON 모드를 위해서만 LVSIL_NORMAL로 세트 되어야 합니다. 이 모드에서는 32X32 아이콘이 보통 사용됩니다. 다른 보기모드를 위해서는 LVSIL_SMALL이 사용됩니다. 이 모드의 표준 아이콘크기는 16X16 입니다. 꼭 규격 크기를 사용 해야 되는 것은 아니며, 또한 꼭 정사각형의 이미지를 사용해야 하는 것도 아닙니다. 이미지는 어떤 모양(Aspect)이든 상관 없습니다.

    2.2 아이템에 대한 이미지를 설정하거나 제거하기

    아이템에 대한 이미지(그림)은 아이템을 처음에 리스트뷰에 추가 할 때 지정 할 수 있습니다.
    m_listctrl.InsertItem( LVIF_TEXT | LVIF_IMAGE, nRow, sItemText, 0, 0, nImage, NULL);
    이 그림은 나중에 SetItem() 함수를 호출함으로써 변경 할 수 있습니다. CListCtrl은 SetImage() 함수를 가지고 있지 않습니다.
    m_listctrl.SetItem( 0, 0, LVIF_IMAGE, NULL, nImage, 0, 0, 0 );
    그림을 제거하려면 nImage 값에 -1 을 사용하십시오. 그 외엔, nImage 값은 0 이상의 값입니다.

    2.3 비규격(Non-Standard)크기의 이미지 설정하기

    비록 아이콘은 언제나 정사각형이여야 하지만, 리스트 뷰컨트롤에서 사용하는 이미지들을 그렇지 않아도 상관없습니다. 예를 들어, 다음코드는 62 픽셀 넓이의 이미지를 생성합니다. 이미지의 높이는 리소스에있는 비트맵의 높이와 같습니다.

    <그림>
    m_img.Create( IDB_CUSTOMBITMAP, 62, 1, (COLORREF)-1 );
    m_listctrl.SetImageList( &m_img, LVSIL_SMALL );

    2.4 이미지의 Late Binding - I_IMAGECALLBACK

    리스트뷰 컨트롤에 아이템을 추가할때, 그때 당장 이미지를 지정하지 않아도 상관은 없습니다. 이럴때, 콜백 아이템을 사용하여 이미지의 선택을 늦출 수 있습니다. 콜백 아이템은 리스트뷰 컨트롤이 아이템을 디스플레이 하는데 정보가 필요할때 리스트뷰 컨트롤의 부모(Parent)에게 LVN_GETDISPINFO 를 보내도록하는 아이템 으로, LVN_GETDISPINFO 통지는 부모윈도우에 의해 처리되거나 리스트뷰 컨트롤에게 다시 반사(reflect back)될 수도 있습니다. 후자가 더 많이 사용되며 메시지 반사(Message Reflection)에 대한 단계는 다음과 같습니다.

    - CListCtrl 파생 클래스에 =LVN_GETDISPINFO에 대한 메시지 핸들러를 추가합니다. '=' 표시는 반사된 메시지라는것을 나타내며, 이것은 메시지맵 섹션에 다음과 같은 줄을 추가합니다.

    ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetDispInfo)

    - 메시지 핸들러를 구현합니다. 아래에 보이는 메시지 핸들러는 이미지 인덱스를 결정하는것에 대한 어떤 로직도 가지고 않습니다. 이미지 인덱스는 아이템 인덱스의 함수이면서/이거나(and/or) 아이템의 데이타와 비슷합니다.

    ( pItem->lParam )
    void CMyListCtrl::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult)
    {
    LV_ITEM *pItem = &((LV_DISPINFO*)pNMHDR)->item;
    if( pItem->mask & LVIF_IMAGE )
    {
    // GetImageFor() needs to be defined and should return image number
    pItem->iImage = GetImageFor( pItem-> iItem);
    }
    *pResult = 0;
    }
    - 이미지 인덱스에 I_IMAGECALLBACK 값을 사용하여 아이템을 추가합니다.예를 들어 다음과 같이 말이죠.

    m_listctrl.InsertItem( nRow, sItemText, I_IMAGECALLBACK );

    3. 뷰(View)


    3.1 보기형태(View Style)를 바꾸기

    리스트뷰 컨트롤은 4가지의 다른 보기 형태를 지원합니다. 이 4가지는 LVS_ICON (큰 아이콘) , LVS_SMALLICON (작은 아이콘) , LVS_LIST (목록) LVS_REPORT (자세히) 입니다. 이들간에 서로 전환 하려면 GetWindowLong() 과 SetWindowLong() 을 이용하여 윈도우 스타일을 수정하여야 합니다.

    // 자세히 보기로 바꾸기
    ModifyStyle( LVS_TYPEMASK, LVS_REPORT);
    LVS_TYPEMASK는 모든 보기 형태를 표현하는 비트 마스크입니다. 아래 코드는 확장(Extended) 리스트뷰 컨트롤 클래스에 대한 SetView() 멤버 함수입니다.
    void CMyListCtrl::SetView(DWORD dwView)
    {
    ModifyStyle( LVS_TYPEMASK, dwView & LVS_TYPEMASK );
    }

    4. 컬럼(Columns)

    4.1 Header 컨트롤

    리스트 뷰 컨트롤이 목록보기 상태에 있을때, 보통 컬럼에 이름을 보여주기위해 헤더컨트롤을 보여줍니다. 헤더컨트롤은 리스트 뷰의 자식 윈도우(Child Window) 이며 언제나 ID 는 0 입니다.

    CHeaderCtrl* pHeader =(CHeaderCtrl*)m_listctrl.GetDlgItem(0);

    헤더컨트롤은 리스트뷰가 목록보기상태가 아니더라도존재하며, 보기모드가 LVS_REPORT가 아닌 상태에서는 크기(dimension)가 0 입니다.

    4.2 자세히 보기(Report View)모드에서 컬럼갯수 알아내기

    리스트뷰 컨트롤의 컬럼수를 알아내려면, 먼저 헤더컨트롤에 대한 포인터를 가져야 하고 그 다음에 헤더컨트롤을 사용하여 요 놈이 몇개의 컬럼들을 가지고 있는지 물어봐야 합니다.

    CHeaderCtrl* pHeader = (CHeaderCtrl*) m_listctrl.GetDlgItem(0);

    int nColumnCount = pHeader->GetItemCount();

    이것은 리스트뷰 컨트롤이 LVS_NOCOLUMNHEADER 스타일 일때도 작동합니다. 또한 컨트롤이 자세히 보기 모드가 아니더라도 동작합니다.

    4.3 컬럼 추가하기

    CListCtrl::InsertColumn() 함수가 리스트뷰 컨트롤에 컬럼을 추가하기 위해 사용됩니다. 이 함수는 컨트롤이 자세히 보기 모드가 아니더라도 사용이 가능하며, 이 함수를 사용할때는 nSubItem 인자를 지정해야하는 것을 알고 있어야 합니다. (LV_COLUMN 구조체를 사용한다면, iSubItem 필드를 지정하는것을 기억해야 합니다.) nSubItem 은 보통 컬럼 번호와 같습니다. 아래는 컬럼추가를 쉽게해주는 Helper 함수 입니다.

    // AddColumn - 오른쪽끝의 컬럼뒤에 새로운 컬럼을 추가하는 함수
    // Returns - 성공시 새로운 아이템의 컬럼번호, 실패시는 -1
    // sColHeading - 컬럼의 헤더 문자열
    // nWidth - 컬럼의 넓이(픽셀단위), 만약 -1을 보내면 컬럼의 넓이는
    // 바로 앞의 컬럼넓이와 같게 만들어 집니다.
    // nFormat - 컬럼의 정렬모드(Alignment) LVCFMT_LEFT,LVCFMT_RIGHT,
    // 또는 LVCFMT_CENTER 값이 될수 있다.
    int CMyListCtrl::AddColumn(LPCTSTR sColHeading, int nWidth /* = -1*/,
    int nFormat /* = LVCFMT_LEFT*/)
    {
    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();
    if( nWidth == -1 )
    {
    // 아래줄은 ICON 보기 상태에서는 0을 리턴합니다.
    //nWidth = GetColumnWidth( nColumnCount - 1 );
    // 헤더컨트롤로부터 바로 전 컬럼의 넓이를 가져옵니다.
    HD_ITEM hd_item;
    hd_item.mask = HDI_WIDTH; //넓이지정을 한다는 것을 알려줍니다.
    pHeader->GetItem( nColumnCount - 1, &hd_item );
    nWidth = hd_item.cxy;
    }
    return InsertColumn( nColumnCount, sColHeading, nFormat, nWidth,
    nColumnCount );

    }

    4.4 클릭된 아이템의 컬럼인덱스 알아내기

    CListCtrl 클래스에 의해서 제공되는 HitTest() 함수는 단지 현재 마우스가 위치한 (Tested)곳에 해당되는 아이템의 Row 인덱스만을 리턴합니다. 또한 HitTest() 함수 는 만약 마우스 포인터가 첫번째 컬럼의 위에 있지않다면 실패(fail)하는 결점을 가지고 있습니다. 현재 마우스가 가리키고 있는 아이템의 Row 인덱스를 알기위해,GetItemRect() 함수 를 호출하여, 각 Row 에대한 사각형 경계(Boundary)를 알아내고 PtInRect() 함수를 사용하여 이 사각형안에 점이 위치하는지를 알아냅니다. 이렇게 Row 인덱스를 알게 되면, GetColumnWidth() 함수를 사용하여 각 셀에대한 경계 사각형을 알아낸 다음 각 경계 사각형에 대해 점이 위치하는지를 테스트합니다.

    // HitTestEx - 포인트에 대한 Row 인덱스와 Column 인덱스 알아내는 함수
    // Returns - 성공시 Row 인덱스, 실패시 -1 (점이 Row위에 없을때)
    // point - Test 될 점(Point)
    // col - 컬럼의 인덱스를 받을 변수
    int CMyListCtrl::HitTestEx(CPoint &point, int *col) const
    {
    int colnum = 0;
    int row = HitTest( point, NULL );
    if( col ) *col = 0;
    if( row != -1 )
    {
    return row;
    }
    // 리스트뷰가 LVS_REPORT 모드에있는지 확인
    if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT)
    return row;
    // 현재 화면에 보이는 처음과 끝 Row 를 알아내기
    row = GetTopIndex();
    int bottom = row + GetCountPerPage();
    if( bottom > GetItemCount() )
    bottom = GetItemCount();
    // 컬럼갯수 알아내기
    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();
    // 현재보이는 Row 들간에 루프 돌기
    for( ;row <=bottom;row++)
    {
    // 아이템의 경계 사각형을 가져오고, 어디에 점이 포함되는지 찾기
    CRect rect;
    GetItemRect( row, &rect, LVIR_BOUNDS );
    if( rect.PtInRect(point) )
    {
    // 컬럼 찾기
    for( colnum = 0; colnum < nColumnCount; colnum++ )
    {
    int colwidth = GetColumnWidth(colnum);
    if( point.x >= rect.left
    ?
    && point.x <= (rect.left + colwidth ) )
    {
    if( col ) *col = colnum;
    return row;
    }
    rect.left += colwidth;
    }
    }
    }
    return -1;
    }

    음.. 4.4 까지 했는지 500줄이 다 되어가네요.. 다음것은 번역하는데 좀 오래걸릴것 같네요.. 제가 6일부터 휴가거든요.. 빠른시일내에 해서 올리도록 하지요..

    4.5 컬럼크기 조정 방지하기

    리스트뷰 컨트롤안의 헤더 컨트롤은 컬럼크기를 바꾸기(Resizing)전에 자신의 부모 윈도우에게 통지(notification)를 보냅니다. 우리는 CListCtrl 파생 클래스에서 이 통지 메시지를 처리하기위해 OnNotify() 함수를 오버라이드 할수있습니다.

    BOOL CMyListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
    {
    switch (((NMHDR*)lParam)->code)
    {
    case HDN_BEGINTRACKW:
    case HDN_BEGINTRACKA:
    *pResult = TRUE; // 마우스의 트래킹 방지(실제 크기 조정)
    return TRUE; // 메시지를 처리했으므로
    }
    return CListCtrl::OnNotify(wParam, lParam, pResult);
    }
     
    만약 단 하나의 컬럼만 크기조정을 방지하고자 한다면, HD_NOTIFY 구조체 안에 있는 iItem 필드의 값을 살펴봐야 할것입니다. 아래 코드는 첫 컬럼의 크기조정만을 막 습니다.
    BOOL CMyListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
    {
    HD_NOTIFY젨 *pHDN = (HD_NOTIFY*)lParam;
    if((pHDN->hdr.code== HDN_BEGINTRACKW || pHDN->hdr.code== HDN_BEGINTRACKA)
    && pHDN->iItem == 0) // 첫번재 컬럼(Column 0)만 크기조정 방지
    {
    *pResult = TRUE; // 마우스의 트래킹 방지(실제 크기 조정)
    return TRUE; // 메시지를 처리했으므로
    }
    return CListCtrl::OnNotify(wParam, lParam, pResult);
    }
     
    4.6 최소 컬럼 넓이 설정하는 방법은 ?

    다시 OnNotify() 함수를 오버라이드 합니다. 아래 코드는 컬럼크기를 최소 80픽셀로 제한합니다. 이 로직은 컬럼의 넓이를 범위 안으로 제한하도록 또는 각각의 컬럼에 다른 범위를 가지도록 확장할수 있습니다. 기능을 확장하기위해서는 각각의 세팅을 추적(Tracking)할수있도록 클래스에 멤버변수를 추가할 필요가 있습니다.

    BOOL CMyListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
    {
    HD_NOTIFY *pHDN = (HD_NOTIFY*)lParam;
    if((pHDN->hdr.code==HDN_ITEMCHANGINGW ||pHDN->hdr.code==HDN_ITEMCHANGINGA)
    && pHDN->pitem->cxy < 80)
    {
    *pResult = TRUE; // 변경을 방지한다.
    return TRUE; // 메시지를 처리했으므로
    }
    return CListCtrl::OnNotify(wParam, lParam, pResult);
    }
     

     5. 선택(Selection)


    5.1 프로그램적으로(Programmatically) 아이템 선택하기

    리스트박스 컨트롤과 달리, 리스트뷰 컨트롤은 SetCurSel()이나 SetSel()같은 함수를 가지고 있지 않습니다. 이런 기능을 수행하기위해서 다음과 같은 문장을 실행하 여야 합니다.

    m_listctrl.SetItemState( rownum,LVIS_SELECTED | LVIS_FOCUSED ,
    LVIS_SELECTED | LVIS_FOCUSED);

    만약 LVIS_FOCUSED 플래그를 사용하지 않는데, 컨트롤이 다중선택을 허용한다면,포커스를 가진 아이템과 현재 당신이 선택한 아이템, 이 두개의 아이템이 모두 선택(Selected)될것입니다. 만약 리스트뷰 컨트롤에 LVS_SHOWSELALWAYS 스타일을 지정하지 않았다면, 컨트롤이 포커스를 가지기전에는 highlight 된것을 보지못할것입니다.

    5.2 왼쪽끝컬럼에 클릭하지 않았더라도 아이템 선택하기

    1. CListCtrl 파생 클래스에 WM_LBUTTONDOWN 핸들러를 추가합니다.
    2. OnLButtonDown() 함수에 대한 코드는 아래 있습니다.
    3. HitTest() 함수를 호출하기 전에 x 좌표가 2로 바뀌었습니다.이것은 현재 테스트되는 점이 첫번재 컬럼에 위치되도록 합니다.2보다 작은값은 테두리(Border)때문에 실패할것입니다.
    4. 베이스 클래스의 OnLButtonDown()호출이 SetItemState() 보다 선행 한다는 것에 주의하십시오.
    5. 이 방법은 만약 첫번재 컬럼이 보이지 않는다면 실패합니다.4.4에서 본 HitTestEx() 함수로 첫번재 컬럼이 보이지 않는 경우를 처리 할 수 있습니다.
     
    void CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
    {
    CListCtrl::OnLButtonDown(nFlags, point);
    int index;
    point.x = 2;
    if( ( index = HitTest( point, NULL )) != -1 )
    {
    SetItemState( index, LVIS_SELECTED | LVIS_FOCUSED ,
    LVIS_SELECTED | LVIS_FOCUSED);
    }
    }
     

    5.3 열들을 선택,해제(Selecting & Deselecting)하기

    리스트박스 컨트롤은 SelItemRange() 라는 선택함수를 가지고 있습니다. CListCtrl에는 없는 이 함수는 쉽게 구현될수 있습니다.

    // SelItemRange - 범위내의 아이템들을 선택/해제합니다.
    // Returns - 새로 선택된 아이템의 개수를 리턴합니다.
    // bSelect - TRUE : 선택시 , FALSE : 해제시
    // nFirstItem - 선택될 아이템들중 첫번째 아이템의 인덱스
    // nLastItem - 선택될 아이템들중 마지막 아이템의 인덱스
    int CMyListCtrl::SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem)
    {
    // nFirstItem 과 nLastItem이 유효한지 검사
    if( nFirstItem >= GetItemCount() || nLastItem >= GetItemCount() )
    return 0;
    int nItemsSelected = 0;
    int nFlags = bSelect ? 0 : LVNI_SELECTED;
    int nItem = nFirstItem - 1;
    while((nItem = GetNextItem(nItem, nFlags)) >=0 && nItem <= nLastItem)
    {
    nItemsSelected++;
    SetItemState(nItem, bSelect ? LVIS_SELECTED : 0, LVIS_SELECTED );
    }
    return nItemsSelected;
    }
     

    6. 아이템과 하부아이템 편집하기(Editing items and subitems)

    6.1 아이템들을 편집가능하도록 하기

    리스트뷰 컨트롤은 편집이 가능하도록 LVS_EDITLABELS 스타일을 가지고 있습니다. 이 스타일은 컨트롤을 생성할때 지정할수도 있고, 후에 ModifyStyle() 함수로도 지정이 가능합니다. 한번 LVS_EDITLABELS 스타일이 지정되면, 사용자는 아이템에 포커스를 둔다음 다시 클릭함으로써 아이템을 편집할 수 있습니다. 어쨌든,컨트롤의 기본 동작(default behaviour)은 편집이 끝났을때 이 변경사항들(changes)을 무시 하는 것입니다. 변경사항을 승락하기 위해서는 LVN_ENDLABELEDIT통지에 대한 처리를 해야한다. 아래는 반사 메시지 핸들러의 예제입니다.(메시지는 부모윈도우가 아닌, 리스트뷰 컨트롤 자신에 의해 처리됩니다.)

    void CMyListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
    {
    *pResult = TRUE;
    }

    만약 우리가 *pLResult를 FALSE로 지정한다면,변경사항은 무시됩니다. 하부아이템에 대한 편집은 컨트롤에 의해서는 직접 지원되지 않으나 쉽게 구현될수있습니다. 이것은 뒤에서 다루게 됩니다.

    6.2 프로그램적으로 아이템 편집하기

    보통 편집은 포커스가 있는 아이템이 사용자가 클릭함으로써 시작됩니다. 사용자가 버튼을 클릭했을때 편집을 시작해야 한다고 가정해 봅시다. 아래는 편집을 시작하게 하는 코드입니다.

    m_listctrl.SetFocus();
    m_listctrl.EditLabel(nItem);

    만약 리스트뷰가 포커스를 가지고 있지 않는 경우를 위해 SetFocus() 함수를 꼭 기억해야 합니다. 물론 이것이 실행되려면 리스트뷰 컨트롤은 LVM_EDITLABEL 스타일 을 가지고 있어야 합니다.

    6.3 편집가능한 하부아이템들

    리스트뷰 컨트롤의 기본 구현은 첫번째 컬럼만 편집을 허용하는 것입니다. 하부아이 템(두번째 이후의 컬럼들)을 편집하려면 자신만의 Edit 컨트롤을 생성해야 합니다.

    <그림>

    단계 1: CListCtrl로 부터 클래스를 상속받습니다.

    아래의 코드에서 CMyListCtrl이 파생클래스의 이름입니다. 또한 이기능을 컨트롤이 아닌 CView 에서 구현하고자 한다면 CListView로 부터 상속받아야 합니다. 만약, 파생한 CListCtrl 클래스로 작업하고 있다면 그 클래스를 수정할수 있습니다.

    단계 2: HitTestEx()함수 정의

    CMyListCtrl 클래스에 확장된 HitTest 함수를 정의합니다. 이 함수는 클릭한 점의 Row 인덱스와 컬럼을 결정할것입니다. HitTestEx() 함수는 이미 4.4에서 살펴 보았습니다. 클릭이나 더블 클릭시 편집이 시작되도록 이 함수를 필요로 합니다.

    단계 3: 편집을 시작하기 위한 함수를 추가합니다.

    사용자 인터페이스는 이미 선택된 로우에 클릭,더블클릭,또는 버튼을 누름으로써 편집이 가능 하도록합니다. 에디트 컨트롤을 생성하기위해 헬퍼함수를 만듭니다. 헬퍼함수는 하부아이템의 컬럼 인덱스와 로우 인덱스를 인자로 받습니다. 그리고 알맞은 사이즈와, 적절한 정렬방식으로 에디트 컨트롤을 생성합니다. 생성된 에디트 컨트롤은 CInPlaceEdit 형으로 뒤에 정의 됩니다.

    // EditSubLabel - 하부아이템의 편집을 시작합니다.
    // Returns - 새 에디트 컨트롤에 대한 임시 포인터
    // nItem - 편집할 아이템의 로우 인덱스
    // nCol - 편집할 하부아이템의 컬럼 인덱스
    CEdit* CMyListCtrl::EditSubLabel( int nItem, int nCol )
    {
    // 리턴된 포인터는 저장되면 안됨(Save)
    // 아이템이 보이는지 확인
    if( !EnsureVisible( nItem, TRUE ) ) return NULL;
    // nCol 이 유효한지 확인
    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();
    if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 )
    return NULL;
    // 컬럼 오프셋(Offset) 가져오기
    int offset = 0;
    for( int i = 0; i < nCol; i++ )
    offset += GetColumnWidth( i );
    CRect rect;
    GetItemRect( nItem, &rect, LVIR_BOUNDS );
    // 컬럼을 보이기 위해 필요하면 스크롤한다.
    CRect rcClient;
    GetClientRect( &rcClient );
    if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
    {
    CSize size;
    size.cx = offset + rect.left;
    size.cy = 0;
    Scroll( size );
    rect.left -= size.cx;
    }
    // 컬럼의 정렬방식 알아내기
    LV_COLUMN lvcol;
    lvcol.mask = LVCF_FMT;
    GetColumn( nCol, &lvcol );
    DWORD dwStyle ;
    if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
    dwStyle = ES_LEFT;
    else if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
    dwStyle = ES_RIGHT;
    else dwStyle = ES_CENTER;
    rect.left += offset+4;
    rect.right = rect.left + GetColumnWidth( nCol ) - 3 ;
    if( rect.right > rcClient.right) rect.right = rcClient.right;
    dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL;
    CEdit *pEdit = new CInPlaceEdit(nItem, nCol, GetItemText( nItem, nCol ));
    pEdit->Create( dwStyle, rect, this, IDC_IPEDIT );
    return pEdit;
    }

    단계 4: 스크롤 메시지 처리하기

    CInPlaceEdit 클래스는 포커스를 잃었을때 에디트 컨트롤을 파괴하고 객체를 없애기 위해 만들어 졌습니다. 리스트뷰의 스크롤바를 클릭하는것은 에디트 컨트롤 에서 포커스를 뺐지 않습니다. 그러므로 우리는 리스트뷰 컨트롤에 포커스를 줌으로 써 포커스를 에디트 컨트롤에서 빼았기는 것을 방지하는 스크롤바 메시지에 대한 핸들러를 작성해야 합니다. ( 음.. 번역이 무지 이상하군... )

    void CMyListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
    if( GetFocus() != this ) SetFocus();
    CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
    }
    void CMyListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
    if( GetFocus() != this ) SetFocus();
    CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);

    }

    단계 5: EndLabelEdit 처리

    첫번째 컬럼에 대한 내장 에디트 컨트롤처럼, 우리의 에디트 컨트롤도 편집이 끝났을때 LVN_ENDLABELEDIT 통지를 보냅니다. 만약 이 통지 메시지가 이미 처리되지 않았다면, 에디트 컨트롤에 의한 변경사항이 받아 들여질수 있도록 핸들러를 추가 합니다.

    void CMyListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
    {
    LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pNMHDR;
    LV_ITEM *plvItem = &plvDispInfo->item;
    if (plvItem->pszText != NULL)
    {
    SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
    }
    *pResult = FALSE;
    }

    단계 6: 사용자가 편집을 시작할수 있도록 하는 방법을 추가합니다.

    권하는 방법은 이미 포커스를 가지는 아이템에 서브아이템을 클릭했을때 편집이 시작되도록 하는것입니다. 다른 방법을 제공해도 상관없습니다. 아래코드는 WM_LBUTTONDOWN 메시지에 대한 핸들러입니다. 포커스가 있는 아이템의 서브아이템이 클릭되었을때 에디트 컨트롤이 서브아이템편집을 위해서 만들어집니다. 아래코드는 에디트 컨트롤을 만들기 전에 먼저 LVS_EDITLABELS 스타일을 체크합니다. 또한 첫번째 컬럼의 에디팅은 기본적으로 리스트뷰 컨트롤에의해 제공되므로 첫번째컬럼 에 대해서는 수행하지 않습니다.

    void CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
    {
    int index;
    CListCtrl::OnLButtonDown(nFlags, point);
    int colnum;
    if( ( index = HitTestEx( point, &colnum )) != -1 )
    {
    UINT flag = LVIS_FOCUSED;
    if( (GetItemState( index, flag ) & flag) == flag && colnum > 0)
    {
    // LVS_EDITLABELS 에 대한 체크
    if( GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS )
    EditSubLabel( index, colnum );
    }
    else
    SetItemState( index, LVIS_SELECTED | LVIS_FOCUSED ,
    LVIS_SELECTED | LVIS_FOCUSED);
    }
    }

    단계 7: CEdit 클래스 서브클래싱

    우리의 특별한 요구사항을 제공하기위해 CEdit 클래스를 서브클래싱해야 합니다.이 클래스에 대한 주요 요구사항은 아래와 같습니다.

    - 편집이 끝났을시 LVN_ENDLABELEDIT 메시지를 보내야 한다.
    - 텍스트에 맞게 크기가 조절되어야 한다.
    - 편집이 끝났을때 자기자신을 파괴해야 한다.
    - 사용자가 ESC 또는 엔터키를 누르거나 에디트 컨트롤이 포커스를 잃을때 편집이 끝나야한다.

    헤더파일은 구현화일(Implementation File)앞에 있습니다. CInPlaceEdit는 4개의 Private 변수를 선언합니다. 이들은 LVN_ENDLABELEDIT 통지를 보낼때 사용됩니다.

    // InPlaceEdit.h : 헤더 파일
    //
    /////////////////////////////////////////////////////////////////////////////
    // CInPlaceEdit window
    class CInPlaceEdit : public CEdit
    {
    // Construction
    public:
    CInPlaceEdit(int iItem, int iSubItem, CString sInitText);
    // Attributes
    public:
    // Operations
    public:
    // Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CInPlaceEdit)
    public:
    virtual BOOL PreTranslateMessage(MSG* pMsg);
    //}}AFX_VIRTUAL
    // Implementation
    public:
    virtual ~CInPlaceEdit();
    // Generated message map functions
    protected:
    //{{AFX_MSG(CInPlaceEdit)
    afx_msg void OnKillFocus(CWnd* pNewWnd);
    afx_msg void OnNcDestroy();
    afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    private:
    int m_iItem;
    int m_iSubItem;
    CString m_sInitText;
    BOOL m_bESC; // ESC 키가 눌렸는지 나타내기 위해
    };
    /////////////////////////////////////////////////////////////////////////////

    구현파일이 아래있습니다.

    CInPlaceEdit 의 생성자는 인자로 넘어온 값들을 저장하고 m_bESC를 FALSE로 초기화 합니다. PreTranslateMessage()함수는 에디트 컨트롤에 전달되는 특별한 키 확인을 위해 오버라이드됩니다. ESC 키와 엔터키는 보통 CDialog 나 CFormView 객체에 의해 Pre-Translate 됩니다. 그러므로 우리는 이것들에 대해 특별히 체크하여 에디트 컨트롤로 넘깁니다. GetKeyState(VK_CONTROL)의 테크는 Ctrl-C,Ctrl-V,Ctrl-X 같은 키조합을 확인하고 에디트 컨트롤로 전송합니다.

    OnKillFocus()함수는 LVN_ENDLABELEDIT통지를 보내고 에디트 컨트롤을 파괴합니다.통지 메시지는 리스트뷰컨트롤이 아닌 리스트뷰의 부모에게 보내집니다. 통지를 보낼때 m_bESC 멤버 변수를 가지고 NULL 스트링을 보낼지를 결정합니다. OnNcDestroy() 함수가 C++ 객체를 파괴하는데 적절한 장소입니다.

    OnChar() 함수는 ESC 나 엔터가 눌렸을때 편집을 끝냅니다. 이 함수는 리스트뷰에 포커스를 줌으로써 에디트 컨트롤의 OnKillFocus() 함수가 불려지도록 합니다. OnChar() 함수는 다른 문자에 대해선 컨트롤이 크기조정이 되야 할지 결정 하기 전에 베이스 클래스 함수가 처리하도록 합니다. OnChar()함수는 적절한 폰트를 사용하여

    문자열의 길이를 알아 네고, 현재 에디트컨트롤의 크기와 비교합니다. 만약,스트링이 에디트 컨트롤크기에 맞지 않을때는 부모윈도우(리스트뷰 컨트롤)가 에디트컨트롤이 확장하는데 필요한 공간이 있는지를 검사한후에 에디트컨트롤의 크기를 변경합니다.

    OnCreate() 함수는 에디트 컨트롤을 생성하고 적당한 값으로 초기화 합니다.
    // InPlaceEdit.cpp : 구현파일
    //
    #include "stdafx.h"
    #include "InPlaceEdit.h"
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    /////////////////////////////////////////////////////////////////////////////
    // CInPlaceEdit
    CInPlaceEdit::CInPlaceEdit(int iItem, int iSubItem, CString sInitText)
    :m_sInitText( sInitText )
    {
    m_iItem = iItem;
    m_iSubItem = iSubItem;
    m_bESC = FALSE;
    }
    CInPlaceEdit::~CInPlaceEdit()
    {
    }
    BEGIN_MESSAGE_MAP(CInPlaceEdit, CEdit)
    //{{AFX_MSG_MAP(CInPlaceEdit)
    ON_WM_KILLFOCUS()
    ON_WM_NCDESTROY()
    ON_WM_CHAR()
    ON_WM_CREATE()
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    /////////////////////////////////////////////////////////////////////////////
    // CInPlaceEdit message handlers
    BOOL CInPlaceEdit::PreTranslateMessage(MSG* pMsg)
    {
    if( pMsg->message == WM_KEYDOWN )
    {
    if(pMsg->wParam == VK_RETURN || pMsg->wParam == VK_DELETE || pMsg->wParam == VK_ESCAPE || GetKeyState( VK_CONTROL) )
    {
    ::TranslateMessage(pMsg);
    ::DispatchMessage(pMsg);
    return TRUE; // 더이상 처리하지 않는다.
    }
    }
    return CEdit::PreTranslateMessage(pMsg);
    }
    void CInPlaceEdit::OnKillFocus(CWnd* pNewWnd)
    {
    CEdit::OnKillFocus(pNewWnd);
    CString str;
    GetWindowText(str);
    // 리스트뷰 컨트롤의 부모에게 통지 보내기
    LV_DISPINFO dispinfo;
    dispinfo.hdr.hwndFrom = GetParent()->m_hWnd;
    dispinfo.hdr.idFrom = GetDlgCtrlID();
    dispinfo.hdr.code = LVN_ENDLABELEDIT;
    dispinfo.item.mask = LVIF_TEXT;
    dispinfo.item.iItem = m_iItem;
    dispinfo.item.iSubItem = m_iSubItem;
    dispinfo.item.pszText = m_bESC ? NULL : LPTSTR((LPCTSTR)str);
    dispinfo.item.cchTextMax = str.GetLength();
    GetParent()->GetParent()->SendMessage( WM_NOTIFY,
    GetParent()->GetDlgCtrlID() , (LPARAM)&dispinfo );
    DestroyWindow();
    }
    void CInPlaceEdit::OnNcDestroy()
    {
    CEdit::OnNcDestroy();
    delete this;
    }
    void CInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
    {
    if( nChar == VK_ESCAPE || nChar == VK_RETURN)
    {
    if( nChar == VK_ESCAPE )
    m_bESC = TRUE;
    GetParent()->SetFocus();
    return;
    }
    CEdit::OnChar(nChar, nRepCnt, nFlags);
    // 필요하다면 에디트컨트롤의 크기를 변경한다.
    // 문자열의 크기를 알아낸다.
    CString str;
    GetWindowText( str );
    CWindowDC dc(this);
    CFont *pFont = GetParent()->GetFont();
    CFont *pFontDC = dc.SelectObject( pFont );
    CSize size = dc.GetTextExtent( str );
    dc.SelectObject( pFontDC );
    size.cx += 5; // 여분의 버퍼를 추가한다.
    // 클라이언트 사격형 크기를 알아낸다.
    CRect rect, parentrect;
    GetClientRect( &rect );
    GetParent()->GetClientRect( &parentrect );
    // 부모의 좌표로 사각형을 변환한다.
    ClientToScreen( &rect );
    GetParent()->ScreenToClient( &rect );
    // 컨트롤이 크기변경될 필요가 있느지 체크하고
    // 늘어날 공간이 있는지 체크
    if( size.cx > rect.Width() )
    {
    if( size.cx + rect.left < parentrect.right )
    rect.right = rect.left + size.cx;
    else
    rect.right = parentrect.right;
    MoveWindow( &rect );
    }
    }
    int CInPlaceEdit::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    if (CEdit::OnCreate(lpCreateStruct) == -1)
    return -1;
    // 적당한 폰트를 지정
    CFont* font = GetParent()->GetFont();
    SetFont(font);
    SetWindowText( m_sInitText );
    SetFocus();
    SetSel( 0, -1 );
    return 0;
    }
     

    6.4 하부아이템 편집을 위해 드롭다운 리스트 사용하기

    때때로, 사용자가 마음대로 아이템을 편집하게 하는 것보다, 사용자에게 선택 값들을 주는것이 좋을수도 있습니다. 에디트 컨트롤대신 드롭다운 리스트를 사용함으로써 이것이 가능합니다. 구현하려면, 하부아이템편집과 같은 패턴을 따릅니다.

    <그림>

    단계 1: CListCtrl 상속클래스 생성

    CListCtrl 로 부터 새로운 클래스를 파생하거나 존재하는 서브클래스에 수정을 합니다. 만약 이미 6.3에서 설명한 하부아이템 편집이 가능한 클래스를 사용한다면 그 클래스를 사용할수 있습니다.

    단계 2: HitTestEx() 함수 정의

    CMyListCtrl 클래스에 확장된 HitTest 함수를 정의합니다. 이 함수는 클릭한 점의 Row 인덱스와 컬럼을 결정할것입니다. HitTestEx() 함수는 이미 4.4 에서 살펴보았 습니다. 클릭이나 더블클릭시 편집이 시작되도록 이 함수를 필요로 합니다.

    단계 3: 드롭다운 리스트를 생성하는 함수를 작성합니다.

    이 함수는 6.3에서 설명했던 EditSubLabel() 함수와 매우 비슷합니다. 차이점은 마지막에 CInPlaceList 클래스로부터 콤보박스를 만든다는것입니다. 이것은 인자로 문자열들의 리스트를 필요로 한다는것을 주의하십시오. 이 리스트는 드롭다운리스트 를 채우기 위해 필요합니다. 마지막인자는 기본적으로 선택될 아이템의 번호입니다.

    // ShowInPlaceList - 리스트뷰의 아무셀에나 드롭다운리스트 생성
    // Returns - 콤보박스에 대한 임시 포인터
    // nItem - 편집할 아이템의 로우 인덱스
    // nCol - 편집할 아이템의 컬럼 인덱스
    // lstItems - 컨트롤을 채울 스트링의 리스트
    // nSel - 기본적으로 선택될 아이템의 번호
    CComboBox* CMyListCtrl::ShowInPlaceList( int nItem , int nCol ,
    CStringList &lstItems, int nSel )
    {
    // 리턴된 포인터는 저장되면 안됨(Save)
    // 아이템이 보이는지 확인
    if( !EnsureVisible( nItem, TRUE ) ) return NULL;
     
    // nCol 이 유효한지 확인
    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();
    if( nCol >= nColumnCount || GetColumnWidth(nCol) < 10 )
    return NULL;
    // 컬럼 오프셋(Offset) 가져오기
    int offset = 0;
    for( int i = 0; i < nCol; i++ )
    offset += GetColumnWidth( i );
    CRect rect;
    GetItemRect( nItem, &rect, LVIR_BOUNDS );
    // 컬럼을 보이기 위해 필요하면 스크롤한다.
    CRect rcClient;
    GetClientRect( &rcClient );
    if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
    {
    CSize size;
    size.cx = offset + rect.left;
    size.cy = 0;
    Scroll( size );
    rect.left -= size.cx;
    }
    rect.left += offset+4;
    rect.right = rect.left + GetColumnWidth( nCol ) - 3 ;
    int height = rect.bottom-rect.top;
    rect.bottom += 5*height;
    if( rect.right > rcClient.right) rect.right = rcClient.right;
    DWORD dwStyle = WS_BORDER|WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL
    |CBS_DROPDOWNLIST|CBS_DISABLENOSCROLL;
    CComboBox *pList = new CInPlaceList(nItem, nCol, &lstItems, nSel);
    pList->Create( dwStyle, rect, this, IDC_IPEDIT );
    pList->SetItemHeight( -1, height);
    pList->SetHorizontalExtent( GetColumnWidth( nCol ));
    return pList;

    }

    단계 4: 스크롤 메시지 처리하기

    Step 4: Handle the scroll messages

    CInPlaceList클래스는 포커스를 잃었을때 드롭다운리스트 컨트롤을 파괴하고 객체를 없애기 위해 만들어 졌습니다. 리스트뷰의 스크롤바를 클릭 하는것은 리스트 컨트롤에서 포커스를 뺐지 않습니다. 그러므로 우리는 리스트뷰 컨트롤에 포커스를 줌으로 써 포커스를 리스트 컨트롤에서 빼았기는 것을 방지하는 스크롤바 메시지에 대한 핸들러를 작성해야 합니다.

    void CMyListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
    if( GetFocus() != this ) SetFocus();
    CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
    }
    void CMyListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
    if( GetFocus() != this ) SetFocus();
    CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
    }

    단계 5: EndLabelEdit 처리

    내장 에디트 컨트롤처럼, 우리의 드롭다운 리스트 컨트롤도 사용자가 아이템을 선택 했을때 LVN_ENDLABELEDIT 통지를 보냅니다. 만약 이 통지 메시지가 이미 처리되지 않았다면, 변경사항이 받아들여질수 있도록 핸들러를 추가합니다.

    void CMyListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
    {
    LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pNMHDR;
    LV_ITEM *plvItem = &plvDispInfo->item;
    if (plvItem->pszText != NULL)
    {
    SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
    }
    *pResult = FALSE;
    }

    단계 6: 사용자가 편집을 시작할수 있도록 하는 방법을 추가합니다.

    아래코드는 WM_LBUTTONDOWN 메시지에 대한 핸들러입니다. 포커스가 있는 아이템의 서브아이템이 클릭되었을때 드롭다운 리스트 컨트롤을 생성합니다. 이 코드는 드롭 다운 리스트 컨트롤을 만들기 전에 먼저 LVS_EDITLABELS 스타일을 체크합니다. 물론, 이것은 매우 간단한 구현이므로 필요에 따라 수정될 필요가 있습니다.

    void CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
    {
    int index;
    CListCtrl::OnLButtonDown(nFlags, point);
    int colnum;
    if( ( index = HitTestEx( point, &colnum )) != -1 )
    {
    UINT flag = LVIS_FOCUSED;
    if( (GetItemState( index, flag ) & flag) == flag )
    {
    // LVS_EDITLABELS 에 대한 체크
    if( GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS )
    {
    CStringList lstItems;
    lstItems.AddTail( "First Item");
    lstItems.AddTail( "Second Item");
    lstItems.AddTail( "Third Item");
    lstItems.AddTail( "Fourth Item");
    lstItems.AddTail( "Fifth Item");
    lstItems.AddTail( "Sixth Item");
    ShowInPlaceList( index, colnum, lstItems, 2 );
    }
    }
    else
    SetItemState( index, LVIS_SELECTED | LVIS_FOCUSED ,
    LVIS_SELECTED | LVIS_FOCUSED);
    }

    }

    단계 7: CComboBox 클래스 서브클래싱

    우리의 특별한 요구사항을 제공하기위해 CComboBox클래스를 서브클래싱해야 합니다.이 클래스에 대한 주요 요구사항은 아래와 같습니다.

    - 유저가 아이템 선택을 끝냈을시 LVN_ENDLABELEDIT 메시지를 보내야 한다.

    - 편집이 끝났을때 자기자신을 파괴해야 한다.

    - 사용자가 ESC 또는 엔터키를 누르거나 유저가 아이템을 선택했을때, 컨트롤이

    입력 포커스를 잃을때 편집이 끝나야한다.

    헤더파일은 구현화일(Implementation File)앞에 있습니다. CInPlaceList는 5개의 Private 변수를 선언합니다.이들은 드롭다운 리스트를 초기화할때와 LVN_ENDLABELEDIT 통지를 보낼때 사용됩니다.

    // InPlaceList.h : header file
    //
    /////////////////////////////////////////////////////////////////////////////
    // CInPlaceList window
    class CInPlaceList : public CComboBox
    {
     
    // Construction
    public:
    CInPlaceList(int iItem, int iSubItem, CStringList *plstItems, int nSel);
    // Attributes
    public:
    // Operations
    public:
    // Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CInPlaceList)
    public:
    virtual BOOL PreTranslateMessage(MSG* pMsg);
    //}}AFX_VIRTUAL
    // Implementation
    public:
    virtual ~CInPlaceList();
    // Generated message map functions
    protected:
    //{{AFX_MSG(CInPlaceList)
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnKillFocus(CWnd* pNewWnd);
    afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
    afx_msg void OnNcDestroy();
    afx_msg void OnCloseup();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    private:
    int m_iItem;
    int m_iSubItem;
    CStringList m_lstItems;
    int m_nSel;
    BOOL m_bESC; // ESC 키가 눌렸는지 나타내기 위해
    };
    /////////////////////////////////////////////////////////////////////////////

    구현파일이 아래있습니다.

    CInPlaceList 의 생성자는 인자로 넘어온 값들을 저장하고 m_bESC를 FALSE로 초기화 합니다. OnCreate()함수는 드롭다운리스트 컨트롤을 생성하고 적당한 값으로 초기화 합니다. PreTranslateMessage()함수는 에디트 컨트롤에 전달되는 ESC와 엔터키 확인 을 위해 오버라이드됩니다. ESC 키와 엔터키는 보통 CDialog 나 CFormView 객체에 의해 Pre-Translate 됩니다. 그러므로 우리는 이것들에 대해 특별히 체크하여 드롭다운 리스트 컨트롤로 넘깁니다.

    OnKillFocus()함수는 LVN_ENDLABELEDIT통지를 보내고 콤보박스컨트롤을 파괴합니다.통지 메시지는 리스트뷰 컨트롤이 아닌 리스트뷰의 부모에게 보내집니다. 통지를 보낼때 m_bESC 멤버 변수를 가지고 NULL 스트링을 보낼지를 결정합니다. OnNcDestroy() 함수가 C++ 객체를 파괴하는데 적절한 장소입니다.

    OnChar() 함수는 ESC 나 엔터가 눌렸을때 선택을 끝냅니다. 이 함수는 리스트뷰에 포커스를 줌으로써 콤보박스 컨트롤의 OnKillFocus() 함수가 불려지도록 합니다. OnChar() 함수는 다른 문자에 대해선 베이스 클래스 함수가 처리하도록 합니다.

    OnCloseup()함수는 사용자가 드롭다운 리스트에서 선택했을때 호출됩니다. 이함수는 부모에서 입력 포커스를 줌으로써 아이템 선택을 끝마치게 합니다.

    // InPlaceList.cpp : implementation file
    //
    #include "stdafx.h"
    #include "InPlaceList.h"
     
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    /////////////////////////////////////////////////////////////////////////////
    // CInPlaceList
    CInPlaceList::CInPlaceList(int iItem, int iSubItem, CStringList *plstItems,
    int nSel)
    {
    m_iItem = iItem;
    m_iSubItem = iSubItem;
    m_lstItems.AddTail( plstItems );
    m_nSel = nSel;
    m_bESC = FALSE;
    }
    CInPlaceList::~CInPlaceList()
    {
    }
    BEGIN_MESSAGE_MAP(CInPlaceList, CComboBox)
    //{{AFX_MSG_MAP(CInPlaceList)
    ON_WM_CREATE()
    ON_WM_KILLFOCUS()
    ON_WM_CHAR()
    ON_WM_NCDESTROY()
    ON_CONTROL_REFLECT(CBN_CLOSEUP, OnCloseup)
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    /////////////////////////////////////////////////////////////////////////////
    // CInPlaceList message handlers
    int CInPlaceList::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    if (CComboBox::OnCreate(lpCreateStruct) == -1)
    return -1;
    // Set the proper font
    CFont* font = GetParent()->GetFont();
    SetFont(font);
    for( POSITION pos = m_lstItems.GetHeadPosition(); pos != NULL; )
    {
    AddString( (LPCTSTR) (m_lstItems.GetNext( pos )) );
    }
    SetCurSel( m_nSel );
    SetFocus();
    return 0;
    }
    BOOL CInPlaceList::PreTranslateMessage(MSG* pMsg)
    {
    if( pMsg->message == WM_KEYDOWN )
    {
    if(pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE )
    {
    ::TranslateMessage(pMsg);
    ::DispatchMessage(pMsg);
    return TRUE; // 더이상 처리하지 않는다.
    }
    }
    return CComboBox::PreTranslateMessage(pMsg);
    }
    void CInPlaceList::OnKillFocus(CWnd* pNewWnd)
    {
    CComboBox::OnKillFocus(pNewWnd);
    CString str;
    GetWindowText(str);
    // 리스트뷰 컨트롤의 부모에게 통지 보내기
    LV_DISPINFO dispinfo;
    dispinfo.hdr.hwndFrom = GetParent()->m_hWnd;
    dispinfo.hdr.idFrom = GetDlgCtrlID();
    dispinfo.hdr.code = LVN_ENDLABELEDIT;
    dispinfo.item.mask = LVIF_TEXT;
    dispinfo.item.iItem = m_iItem;
    dispinfo.item.iSubItem = m_iSubItem;
    dispinfo.item.pszText = m_bESC ? NULL : LPTSTR((LPCTSTR)str);
    dispinfo.item.cchTextMax = str.GetLength();
    GetParent()->GetParent()->SendMessage( WM_NOTIFY,
    GetParent()->GetDlgCtrlID(), (LPARAM)&dispinfo );
    DestroyWindow();
    }
    void CInPlaceList::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
    {
    if( nChar == VK_ESCAPE || nChar == VK_RETURN)
    {
    if( nChar == VK_ESCAPE )
    m_bESC = TRUE;
    GetParent()->SetFocus();
    return;
    }
    CComboBox::OnChar(nChar, nRepCnt, nFlags);
    }
    void CInPlaceList::OnNcDestroy()
    {
    CComboBox::OnNcDestroy();
    delete this;
    }
    void CInPlaceList::OnCloseup()
    {
    GetParent()->SetFocus();
    }

    7. 정렬(Sorting)

    7.1 리스트를 컬럼에 관계없이 문자열기준으로 정렬하기

    리스트뷰 컨트롤은 리스트에 있는 아이템들을 정렬(Sort)하는데 두가지 방법을 직접 제공합니다. 그중 하나는 컨트롤 생성시 LVS_SORTASCENDING이나 LVS_SORTDESCENDING 스타일을 사용하는것입니다. 리스트에 추가되는 아이템은 자동적으로 정렬된 순서로 들어가게 됩니다. 이것은 추가의 프로그래밍 작업을 필요로 하지는 않지만 , 언제나 아이템 텍스트에 의해 정렬되며, 서브아이템에 따른 정렬을 할수 없고, 아이템의 추후변경시나, 편집시 정렬순서를 갱신하지 않습니다.

    두번째 방법은 SortItems()함수를 사용하여 리스트를 정렬하는 것입니다. 이 방법은 매우 융통성이 있지만 프로그램이 아이템데이터를 이용하여 리스트에 있는 아이템 들을 계속 추적(Track)하는 것을 요구합니다. 그러므로 SortItems()함수가 사용되기 전에 리스트에 있는 각 아이템은 연결된 데이터를 필요로 합니다. 보통 당신은 InsertItem() 이나 SetItemData() 함수를 사용하여 아이템을 데이타와 연결합니다. 정렬작업중, 비교될 두개의 리스트 아이템의 상대적인 순서가 필요할때 비교함수가 호출됩니다. 비교함수는 클래스의 정적인 멤버이거나 , 어떤 클래스의 멤버도 아닌 독립형의 (Stand Alone) 함수이어야합니다. 비교함수는 비교될 아이템들을 인자로 호출됩니다. 공통적인 실수(mistake) 하나는 비교함수에 넘겨지는 인자가 Row인덱스 라고 가정하는 것입니다.

    아래보이는 코드는 정렬에 대해 커스텀한 접근을 시도하며, 재사용되기 쉽습니다. SortTextItems() 함수는 어떤컬럼이라도 문자열을 기준으로 정렬할수 있습니다. 이 함수의 단점은 만약 컬럼이 숫자값들을 가진다면 정렬순서가 당신이 원하는 대로 나오지 않을것이라는 겁니다. 마지막 2개의 인자는 주로 재귀호출에 사용되며, 클래스의 선언에는 0과 1을 디폴트 값으로 가지고 있어야 합니다. 두개의 줄을 바꿀 때는 하부이이템과 그림,상태정보까지 바꿔야(Swap)합니다.

    // SortTextItems - 리스트를 컬럼 텍스트에 따라 정렬하는 함수
    // Returns - 성공시 TRUE 리턴
    // nCol - 소트할 문자열을 가지고 있는 컬럼번호
    // bAscending - 소트순서 지정
    // low - 조사 시작 줄 - 기본값은 0
    // high - 조사 마지막줄 - -1은 마지막줄을 가리킵니다.
    BOOL CMyListCtrl::SortTextItems( int nCol, BOOL bAscending,
    int low /*= 0*/, int high /*= -1*/ )
    {
    if( nCol >= ((CHeaderCtrl*)GetDlgItem(0))->GetItemCount() )
    return FALSE;
    if( high == -1 ) high = GetItemCount() - 1;
    int lo = low;
    int hi = high;
    CString midItem;
    if( hi <= lo ) return FALSE;
    midItem = GetItemText( (lo+hi)/2, nCol );
    // 인덱스들이 교차될때까지 리스트를 돕니다(Loop).
    while( lo <= hi )
    {
    // rowText 변수가 한줄에 대한 모든 컬럼문자열을 가지게 됩니다.
    CStringArray rowText;
    //왼쪽 인덱스부터 시작하여 구역 요소보다 크거나 같은 첫째 요소를 찾음.
    if( bAscending )
    while( ( lo < high ) && ( GetItemText(lo, nCol) < midItem ) )
    ++lo;
    else
    while( ( lo < high ) && ( GetItemText(lo, nCol) > midItem ) )
    ++lo;
     
    //오른쪽 인덱스부터 시작하여 구역 요소보다 크거나 같은 요소를 찾음.
    if( bAscending )
    while( ( hi > low ) && ( GetItemText(hi, nCol) > midItem ) )
    --hi;
    else
    while( ( hi > low ) && ( GetItemText(hi, nCol) < midItem ) )
    --hi;
    // 만약 인덱스가 교차되지 않았다면 교환하고, 만약 아이템이 같지않다면,
    if( lo <= hi )
    {
    // 아이템이 같지 않을때만 교환한다.
    if( GetItemText(lo, nCol) != GetItemText(hi, nCol))
    {
    // 줄들을 교환한다.
    LV_ITEM lvitemlo, lvitemhi;
    int nColCount =?
    ((CHeaderCtrl*)GetDlgItem(0))->GetItemCount();
    rowText.SetSize( nColCount );
    int i;
    for( i=0; i<nColCount; i++)
    rowText[i] = GetItemText(lo, i);
    lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
    lvitemlo.iItem = lo;
    lvitemlo.iSubItem = 0;
    lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED |
    LVIS_FOCUSED | LVIS_SELECTED |
    LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;
    lvitemhi = lvitemlo;
    lvitemhi.iItem = hi;
    GetItem( &lvitemlo );
    GetItem( &lvitemhi );
    for( i=0; i<nColCount; i++)
    SetItemText(lo, i, GetItemText(hi, i));
    lvitemhi.iItem = lo;
    SetItem( &lvitemhi );
    for( i=0; i<nColCount; i++)
    SetItemText(hi, i, rowText[i]);
    lvitemlo.iItem = hi;
    SetItem( &lvitemlo );
    }
    ++lo;
    --hi;
    }
    }
    // 만약 오른쪽 인덱스가 배열의 왼쪽 끝에 닿지 않았다면 왼쪽 구역을
    // 정렬해야 한다.
    if( low < hi )
    SortTextItems( nCol, bAscending , low, hi);
    // 만약 왼쪽 인덱스가 배열의 오른쪽 끝에 닿지 않았다면 오른쪽 구역을
    // 정렬해야 한다.
    if( lo < high )
    SortTextItems( nCol, bAscending , lo, high );
    return TRUE;

    }

    7.2 편집후에 자동적으로 재정렬 하기

    리스트뷰 컨트롤이 정렬을 하는때는 리스트에 아이템을 추가할때 뿐입니다. 또한,컨트롤은 LVS_SORTASCENDING이나 LVS_SORTDESCENDING스타일을 가지고 있어야합니다.새로운 아이템이 추가될때 적당한 자리에 추가되면, 다른 아이템들은 같은 순서대로 있게됩니다.만약 사용자가 아이템을 편집한다면,리스트뷰는 순서를 지키기위해 다시 정렬되어야 합니다. 이렇게 하기위해서는 LVN_ENDLABELEDIT핸들러에서 재정렬코드가 시작되어야 합니다. 아래코드는 7.1 에서 다룬 SortTextItems() 함수를 사용합니다. 만약 정렬이 문자열에 의한 것이 아니라면 SortItems() 함수가 정렬에 사용되어야 할 것입니다.

    void CMyListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
    {
    LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pNMHDR;
    LV_ITEM젨 *plvItem = &plvDispInfo->item;
    if (plvItem->pszText != NULL)
    {
    SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
    SortTextItems( 0, TRUE );
    }
    *pResult = FALSE;
    }

    주의해야할것이 두가지 있습니다. 첫째로 정렬함수를 호출하기전에 아이템은 SetItemText() 함수를 통해 변경되어야 합니다. 이것이 안된다면 예전 데이타를 가지고 정렬하게 됩니다. 둘째로 *pResult 를 FALSE 로 지정해야 합니다. 이게 중요합니다. TRUE 로 지정한다면 윈도우즈에게 수정사항을 받아들이라고 말하게 됩니다. 이러면 변경된 줄이 이미 다른줄로 위치가 바뀌어있기 때문에 (정렬 했으므로) 이 자리가 바뀐줄이 다시 또 변경되게 됩니다.

    7.3 사용자가 컬럼 헤더에 클릭시 리스트 정렬하기

    만약 사용자가 헤더에 클릭함으로써 리스트를 정렬 하는것을 막고자 한다면,당신은 LVS_NOSORTHEADER 를 사용 할 수 있습니다. 그러나, 만약 정렬하는 것을 허락한다면, LVS_NOSORTHEADER 를 사용하면 안됩니다. 컨트롤은 아이템을 정렬하지는 않습니다. 당신은 헤더컨트롤로 부터의 HDN_ITEMCLICK 통지를 핸들링하고 적절하게 처리하여야 합니다. 아래코드에서는 7.1에서 만든 SortTextItems() 함수를 사용합니다. 다른 방식으로 아이템을 정렬하여도 됩니다.

    단계 1: 두개의 멤버 변수를 추가합니다.

    CListCtrl 에 두개의 멤버 변수를 추가합니다. 첫번째 변수는 정렬된 컬럼 번호를 기억하는 것이고, 두번째는 정렬이 오름차순인지,내림차순인지 기억합니다.

    int nSortedCol;

    BOOL bSortAscending;

    단계 2: 이들을 생성자에서 초기화 합니다.

    nSortedCol 을 -1로 지정함으로써 어떤 컬럼으로도 정렬되지 않았다는 것을 나타냅니다. 만약 리스트가 처음부터 정렬된다면, 이 변수가 그것을 보여주어야 합니다.

    nSortedCol = -1;

    bSortAscending = TRUE;

    단계 3: 메시지맵에 HDN_ITEMCLIK 핸들러를 추가합니다.

    실제로 당신은 HDN_ITEMCLICKA 와 HDN_ITEMCLICKW, 이렇게 두개의 엔트리를 필요로 합니다. 이것을 추가하기 위해 클래스 위자드를 사용하지 마십니오. 첫째로 당신은 구애의 엔트리를 추가해야 하지만, 클래스 위자드는 하나만을 허락합니다. 둘째로, 클래스 위자드는 엔트리에서 틀린 매크로를 사용합니다. 이놈은 ON_NOTIFY() 대신 ON_NOTIFY_REFLECT() 를 사용합니다. HDN_ITEMCLICK 통지는 헤더컨트롤로부터 리스트뷰 컨트롤로의 통지이기 때문에 직접통지(Direct Notification)이지 반사된 통지 (Reflected Notification)이 아닙니다.

    ON_NOTIFY(HDN_ITEMCLICKA, 0, OnHeaderClicked)

    ON_NOTIFY(HDN_ITEMCLICKW, 0, OnHeaderClicked)

    각 통지에 대해서 같은 함수를 지정했다는것을 주의하십시오. 실제로 프로그램은 둘중에 하나만을 받지 둘다 받지는 않습니다. 통지를 받는것은 는 OS에 따라 다르게 됩니다. 윈도우95 상에서의 리스트뷰 컨트롤은 ANSI 버젼(A) 을 보낼것이고, NT에서의 컨트롤은 UNICODE 버젼(W) 을 보낼것입니다.또한 두번째 인자가 0이라는 것을 주의하십시오, 이 값은 컨트롤의 ID 를 Filtering하며, 우리는 헤더컨트롤의 ID 가 0이라는것을 알고있습니다.

    단계 4: OnHeaderClicked() 함수를 작성합니다.

    여기가 사용자가 컬럼헤더에 클릭했을때 무엇을 해야하는지 결정하는곳입니다. 예상되는 동작은 그 컬럼의 값에 기초해서 리스트를 정렬하는것 입니다. 여기서도 7.1의SortTextItems() 함수를 사용합니다. 만약 어떤 컬럼이 숫자나 날짜형식의 값을 보인다면 당신은 이것들에 대해선 다른 정렬방식을 사용해야 합니다.

    void CMyListCtrl::OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult)
    {
    HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;
    if( phdn->iButton == 0 )
    {
    // 사용자가 왼쪽버튼으로 헤더를 선택했다.
    if( phdn->iItem == nSortedCol )
    bSortAscending = !bSortAscending;
    else
    bSortAscending = TRUE;
    nSortedCol = phdn->iItem;
    SortTextItems( nSortedCol, bSortAscending );
    }
    *pResult = 0;

    }

    8. 격자선(Grid lines)

    8.1 컬럼 테두리를 위한 세로줄

    리스트뷰 컨트롤은 자세히보기 모드에서 컬럼간의 나뉨을 비주얼하게 보이주지는 않습니다. 아래코드는 컬럼간에 세로선을 어떻게 추가하는지 보여줍니다. 직접 그리기 위해서 우리는 OnPaint()함수를 오버라이드 합니다. 우리가 모든 그리기를 하는것을 원하는 것은 아니기 때문에 선을 그리기 전에 DefWindowProc()에게 먼저 컨트롤을 그리게 합니다. 또한 리스트뷰 컨트롤이 자세히 보기모드에 있는지도 확인합니다.

    <그림>

    void CMyListCtrl::OnPaint()
    {
    // 먼저 컨트롤 그리기를 하도록 합니다.
    const MSG *msg = GetCurrentMessage();
    DefWindowProc( msg->message, msg->wParam, msg->lParam );
    // 자세히보기 모드일때만 선을 그리도록 합니다.
    if( (GetStyle() & LVS_TYPEMASK) == LVS_REPORT )
    {
    // 컬럼의 숫자를 가져옵니다.
    CClientDC dc(this );
    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();
    // 헤더의 밑부분이 선의 윗시작입니다.
    RECT rect;
    pHeader->GetClientRect( &rect );
    int top = rect.bottom;
    // 클라이언트 영역을 가져와 선의 길이와 언제 멈춰야 할지를 압니다.
    GetClientRect( &rect );
    // 컬럼의 테두리는 수평스크롤이 값이 오프셋(Offset)입니다.
    int borderx = 0 - GetScrollPos( SB_HORZ );
    for( int i = 0; i < nColumnCount; i++ )
    {
    // 다음 컬럼의 테두리를 가져옵니다.
    borderx += GetColumnWidth( i );
    // 만약 다음 테두리가 클라이언트 영역 바깥이라면 Break 합니다.
    if( borderx >= rect.right ) break;
    // 선을 그립니다.
    dc.MoveTo( borderx-1, top);
    dc.LineTo( borderx-1, rect.bottom );
    }
    }
    // Painting 메시지를 위해 CListCtrl::OnPaint()를 호출하지 마십시오.

    }

    세로선을 그리기위해 우리는 헤더컨트롤을 컬럼크기와 유효 클라이언트 영역을 알아내는데 사용합니다. 마지막으로 칵 컬럼의 오른쪽에 선을 그립니다.테두리를 알아낼때 수평 스크롤바의 위치가 참고되었다는 것을 주의하십시오. 만약 이렇게 하지 않는다면 리스트가 스크롤되었을때 컬럼의 중간에 있는 선에서 끝나게 될것입니다. GetScrollPos() 함수는 스크롤바가 없을때는 0을 리턴하므로 리스트뷰 컨트롤이 수평 스크롤바를 가지고 있는지를 먼저 확인할 필요가 없습니다.GetItemRect() 함수를 사용할수도 있겠지만, 이것은 리스트가 적어도 하나의 아이템을 가지고 있을때만 동작하게 됩니다.실제로 선은 컬럼 테두리의 한 픽셀 왼쪽에 그려지게 됩니다. 이것이 컬럼헤더와 더잘 정렬됩니다. 또한 이것은 하나의 버그가 있습니다. 만약 컬럼넓이를 키운다면 보이지 않는 컬럼영역은 갱신되지 않습니다. 그러므로 바로 전(Previous) 선의 자취가남게 되는것이죠. 이것의 해결책은 두가지가 있습니다. 첫째로 컬럼경계에 정확하게선을 그리는것입니다.(borderx 에서 1을 빼지 않는것이죠) 두번째는 헤더컨트롤에서HDN_TRACK 통지를 처리하는 것이죠.

    여기까지 하죠, 다음것이 들어가기엔 조금 부족하네요..다른 분들에게 도움이 되었으면..

    void CMyListCtrl::OnPaint()
    {
    // 먼저 컨트롤 그리기를 하도록 합니다.
    const MSG *msg = GetCurrentMessage();
    DefWindowProc( msg->message, msg->wParam, msg->lParam );
    // 자세히보기 모드일때만 선을 그리도록 합니다.
    if( (GetStyle() & LVS_TYPEMASK) == LVS_REPORT )
    {
    // 컬럼의 숫자를 가져옵니다.
    CClientDC dc(this );
    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();
    // 헤더의 밑부분이 선의 윗시작입니다.
    RECT rect;
    pHeader->GetClientRect( &rect );
    int top = rect.bottom;
    //클라이언트 영역을 가져와 선의 길이와 언제 멈춰야 할지를 압니다.
    GetClientRect( &rect );
    // 컬럼의 테두리는 수평스크롤이 값이 오프셋(Offset)입니다.
    int borderx = 0 - GetScrollPos( SB_HORZ );
    for( int i = 0; i < nColumnCount; i++ )
    {
    // 다음 컬럼의 테두리를 가져옵니다.
    borderx += GetColumnWidth( i );
    // 만약 다음 테두리가 클라이언트 영역 바깥이라면 Break 합니다.
    if( borderx >= rect.right ) break;
    // 선을 그립니다.
    dc.MoveTo( borderx-1, top);
    dc.LineTo( borderx-1, rect.bottom );
    }
    // 가로 격자선을 그립니다.
    // 먼저 아이템의 높이를 가져옵니다.
    if( !GetItemRect( 0, &rect, LVIR_BOUNDS ))
    return;
    int height = rect.bottom - rect.top;
    GetClientRect( &rect );
    int width = rect.right;
    for( i = 1; i <= GetCountPerPage(); i++ )
    {
    dc.MoveTo( 0, top + height*i);
    dc.LineTo( width, top + height*i );
    }
    }
    // Painting 메시지를 위해 CListCtrl::OnPaint()를 호출하지 마십시오.
    }

    Paul Gerhart 가 이것을 Owner-Drawn CListCtrl 로 구현해 놓았습니다. 그는 샘플 프로그램과 함께 http://www.voicenet.com/~pgerhart/_shware.html 에 코드를 올려놓았습니다.

    9. 툴팁과 타이틀팁(Tooltip & Titletip)

    9.1 헤더를 위한 툴팁

    헤더컨트롤을 위한 툴팁을 추가하는것은 매우 간단합니다.

    CListCtrl 파생 클래스에 CToolTipCtrl 타입의 멤버변수를 선언합니다.

    CToolTipCtrl m_tooltip;

    CListCtrl 파생 클래스에서 PreSubclassWindow() 함수를 오버라이드 합니다. 베이스클래스의 PreSubclassWindow()를 호출한후, 툴팁객체를 만듭니다. OnCreate()대신에 PreSubclassWindow()를 오버라이드 한 이유는 컨트롤은 보통 다이얼로그 리소스로부터 생성됨으로써 이미 만들어진후에 C++ 객체에 붙기(Attach) 때문에, OnCreate가 객체에 대해 전혀 호출이 되지 않기때문입니다.

    void CMyListCtrl::PreSubclassWindow()
    {
    CListCtrl::PreSubclassWindow();
    // Add initialization code
    m_tooltip.Create( this );
    m_tooltip.AddTool( GetDlgItem(0), "Right click for context menu" );
    }
    PreTranslateMessage()함수를 오버라이드해서 CToolTip 객체의 RelayEvents()함수를 호출합니다.
    BOOL CMyListCtrl::PreTranslateMessage(MSG* pMsg)
    {
    m_tooltip.RelayEvent( pMsg );
    return CListCtrl::PreTranslateMessage(pMsg);

    }

    9.2 각각의 컬럼 헤더를 위한 툴팁

    컬럼헤더에 툴팁을 제공하는것은 여러용도가 있습니다. 헤더툴팁이 정말 유용하다고 느낀 한가지 경우는 컬럼의 넓이가 제한되어있을때 입니다. 툴팁은 컬럼헤더가 제한된 넓이때문에 전달하지 못하는것을 전달할수있습니다. 코드를 Modular하게 하기 위해 우리는 CListCtrl 파생클래스에 툴팁기능을 구현할것입니다.

    CListCtrl 파생 클래스에 CToolTipCtrl 타입의 멤버변수를 선언합니다.

    CToolTipCtrl m_tooltip;

    CListCtrl 파생 클래스에서 PreSubclassWindow() 함수를 오버라이드 합니다. 베이스 클래스의 PreSubclassWindow()를 호출한후, 툴팁 객체를 만듭니다.

    void CMyListCtrl::PreSubclassWindow()
    {
    CListCtrl::PreSubclassWindow();
    // Add initialization code
    m_tooltip.Create( this );
    }

    PreTranslateMessage()함수를 오버라이드해서 CToolTip 객체의 RelayEvents()함수를 호출합니다. RelayEvents() 함수를 호출하는 것은 툴팁이 마우스가 툴 영역 어디에 들 어왔는지는 알수있는 기회를 제공합니다.비록 리스트뷰 컨트롤이 받는 모든 메시지를 패스하지만, 툴팁컨트롤은 WM_?BUTTONDOWN,WM_?BUTTONUP, 그리고 WM_MOUSEMOVE 메시지만을 처리합니다.

    BOOL CMyListCtrl::PreTranslateMessage(MSG* pMsg)
    {
    m_tooltip.RelayEvent( pMsg );
    return CListCtrl::PreTranslateMessage(pMsg);
    }

    툴팁을 추가하기위한 방법을 제공합니다.하나의 툴팁컨트롤은 여러개의 툴을 처리할수 있습니다. AddHeaderToolTip()헬퍼 함수는 툴팁컨트롤에 새로운 툴을 추가합니다

    // AddHeaderToolTip - 컬럼헤더에 대한 툴팁을 추가합니다.
    // 컨트롤은 자세히보기(LVS_REPORT) 모드여야 합니다.
    // Returns - 성공시 TRUE 리턴
    // nCol - 컬럼 인덱스
    // sTip - 툴팁텍스트
    BOOL CMyListCtrl::AddHeaderToolTip(int nCol, LPCTSTR sTip /*= NULL*/)
    {
    const int TOOLTIP_LENGTH = 80;
    char buf[TOOLTIP_LENGTH+1];
    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();
    if( nCol >= nColumnCount)
    return FALSE;
    if( (GetStyle() & LVS_TYPEMASK) != LVS_REPORT )
    return FALSE;
    // 헤더의 높이를 구합니다.
    RECT rect;
    pHeader->GetClientRect( &rect );
    int height = rect.bottom;
    RECT rctooltip;
    rctooltip.top = 0;
    rctooltip.bottom = rect.bottom;
    // 컬럼의 좌우 테두리를 구합니다.
    rctooltip.left = 0 - GetScrollPos( SB_HORZ );
    for( int i = 0; i < nCol; i++ )
    rctooltip.left += GetColumnWidth( i );
    rctooltip.right = rctooltip.left + GetColumnWidth( nCol );
    if( sTip == NULL )
    {
    // 컬럼 헤딩 문자열을 가져옵니다.
    LV_COLUMN lvcolumn;
    lvcolumn.mask = LVCF_TEXT;
    lvcolumn.pszText = buf;
    lvcolumn.cchTextMax = TOOLTIP_LENGTH;
    if( !GetColumn( nCol, &lvcolumn ) )
    return FALSE;
    }
    m_tooltip.AddTool( GetDlgItem(0), sTip ? sTip : buf, &rctooltip, nCol+1 );
    return TRUE;

    }

    OnNotify()를 오버라이드하여 컬럼 넓이에 대한 변동사항을 추적합니다.만약 사용자 가 컬럼크기를 조정했을때 툴팁정보를 갱신하지 않는다면 툴팁은 정확한 컬럼을 보여주지 않을 것입니다.

    BOOL CMyListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
    {
    HD_NOTIFY *pHDN = (HD_NOTIFY*)lParam;
    if((pHDN->hdr.code == HDN_ENDTRACKA || pHDN->hdr.code == HDN_ENDTRACKW))
    {
    // 툴팁의 정보를 갱신합니다.
    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();
    CToolInfo toolinfo;
    toolinfo.cbSize = sizeof( toolinfo );
    // 영향을 받은 각 컬럼을 tooltipinfo 를 통해 순환(Cycle)합니니다.
    for( int i = pHDN->iItem; i <= nColumnCount; i++ )
    {
    m_tooltip.GetToolInfo( toolinfo, pHeader, i + 1 );
    int dx; // 넓이의 변경사항을 저장합니다.
    if( i == pHDN->iItem )
    dx = pHDN->pitem->cxy - toolinfo.rect.right;
    else
    toolinfo.rect.left += dx;
    toolinfo.rect.right += dx;
    m_tooltip.SetToolInfo( &toolinfo );
    }
    }
    return CListCtrl::OnNotify(wParam, lParam, pResult);

    }

    9.3 각 셀을 위한 툴팁

    툴팁은 컬럼넓이가 제한된 화면 사이즈때문에 제한될때 매우 유용합니다. 이들은 단축되서 보여지는 컬럼의 문자열들을 확장하는데 사용 될수도 있습니다. 이 일을 위해 MFC 에 의해 제공되는 툴팁기능을 사용할것입니다. 아래코드는 셀의 문자열을 툴팁에 보여줍니다만, 이것은 쉽게 이미 셀에 보여주고 있는것을 보이기보다 좀 다른것을 보여 주는것으로 수정될수 있습니다.

    각 셀에 대해 툴팁을 추가하는 것은 상당히 쉽습니다. 어쨌든 문서는 별로 도움이 되지 못하며, 인식해야할 몇가지 사항이 있습니다. NT 4.0 과 Win95 의 리스트뷰 컨트롤은 몇가지 중요한 차이점을 가지고 있습니다. 첫째로 , 리스트뷰 컨트롤과 툴팁 컨트롤은 Windows 95 상에서는 ANSI 컨트롤입니다. 이것이 의미하는 것은 Windows 95 상에서는 메시지들이 ANSI 버젼이라는 것입니다. 프로젝트 세팅에 따라서 메시지 상수들(A 나 W 접미어가 없는것)이 맞는값으로 변환되는것에 의존하지 마십시오. 예를 들어 UNICODE 프로그램을 개발한다면 TTN_NEEDTEXT는 TTN_NEEDTEXTW로 번역되어야 합니다. 하지만 Windows 95 에서는 실제 메시지는 TTN_NEEDTEXTA 입니다. 이것은 또한 구조체와 문자열에도 적용됩니다. Windows 95 에서는 컨트롤에 전달되는 모든 문자열은 ANSI 문자열이어야 합니다. NT 4.0에선 컨트롤들이 모두 UNICODE 컨트롤입니다.

    둘째로, NT 4.0 에서는 리스트뷰 컨트롤이 자동으로 툴팁컨트롤을 만듭니다. 이내장 툴팁 컨트롤은 마우스가 리스트뷰 컨트롤위에 올라와 잠시 움직이지 않을때 자동적으로 TTN_NEEDTEXTW 통지를 보내게 됩니다. 아래코드는 이 내장 툴팁 컨트롤로부터의 통지를 무시합니다.

    PreSubclassWindow()를 오버라이드하고 베이스 클래스의 PreSubclassWindow()를 호출한후 EnableToolTips(TRUE)를 호출합니다. EnableToolTips()함수는 CWnd 클래스의멤버 함수이고, 따라서 모든 윈도우와 컨트롤에 사용이 가능합니다.

    void CMyListCtrl::PreSubclassWindow()
    {
    CListCtrl::PreSubclassWindow();
    // Add initialization code
    EnableToolTips(TRUE);
    }

    OnToolHitTest()함수를 오버라이드 합니다. OnToolHitTest()는 CWnd클래스에 정의된 가상 함수이고 프레임워크에 의해서 마우스포인터가 어떤 툴 위에 있는지 결정하기위해 호출됩니다. 툴은 컨트롤윈도우 이거나 또는 윈도우안의 사각형 영역일수도 있습니다 우리의 목적을 위해선 각 셀의 영역이 툴로 처리되어야 합니다.

    OnToolHitTest() 문서(Documentation)는 툴을 찾았다면 1을 못찾았다면 -1을 리턴하라고 암시합니다.하지만 실제로 프레임워크는 리턴값을 툴이 바뀌었는지 결정하는데 사용합니다. 프레임워크는 툴이 바뀌었을때만 툴팁을 갱신하므로, OnToolHitTest()는 지정된 점의 셀이 값(문자열)이 바뀌어었을때 다른 값을 리턴 해야합니다.

    int CMyListCtrl::OnToolHitTest(CPoint point, TOOLINFO * pTI) const
    {
    int row, col;
    RECT cellrect;
    row = CellRectFromPoint(point, &cellrect, &col );
    if ( row == -1 )
    return -1;
    pTI->hwnd = m_hWnd;
    pTI->uId = (UINT)((row<<10)+(col&0x3ff)+1);
    pTI->lpszText = LPSTR_TEXTCALLBACK;
    pTI->rect = cellrect;
    return pTI->uId;
    }

    이 함수는 처음에 CellRectFromPoint() 함수를 호출하여 로우와 컬럼, 그리고 셀의 경게 사각형을 알아냅니다. CellRectFromPoint() 는 아래에서 살펴봅니다. 함수는 그리고 TOOLINFO 구조체를 설정합니다. 'uId' 는 줄,열의 값을 결합한 값을 지정합 니다. 로우와 컬럼의 결합방법은 4194303 개의 로우와 1023개의 컬럼을 허용합니다.또한 결과에 1이 더해진것을 주의하십시오. 이렇게 하는 이유는 0이 아닌값만을 생성하기위해서 입니다. 우리는 NT4.0 에서 자동적으로 만들어진 툴팁에서 보낸 통지와 구별하기 위해서 0이 아닌값을 필요로 합니다. 앞에서 언급했듯이 NT 4.0 에서 만들어진 리스트뷰 컨트롤은 자동적으로 툴팁을 생성하며 이 툴팁의 ID 는 0입니다.

    다음 우리는 OnToolHitTest() 에서 사용된 CellRectFromPoint() 함수를 정의합니다.이 함수는 #1 - 4.4 에서 다루어진 HitTestEx() 함수와 매우 비슷합니다. 점 위치의 로우 와 컬럼값을 알아내는 것에 더해서 이 함수는 점 아래 셀의 경계 사각형도 알아냅니다.

    // CellRectFromPoint - 셀의 로우,컬럼,경계사각형을 알아냅니다.
    // Returns - 성공시 로우 인덱스, 아니면 -1
    // point - 검사될 점(현재 마우스 포인터)
    // cellrect - 경계사각형을 저장할 변수
    // col - 컬럼값을 저장할 변수
    int CMyListCtrl::CellRectFromPoint(CPoint & point, RECT * cellrect, int * col)
    const
    {
    int colnum;
    // 리스트뷰가 LVS_REPORT 모드에있는지 확인
    if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
    return -1;
    // 현재 화면에 보이는 처음과 끝 Row 를 알아내기
    int row = GetTopIndex();
    int bottom = row + GetCountPerPage();
    if( bottom > GetItemCount() )
    bottom = GetItemCount();
    // 컬럼갯수 알아내기
    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();
    // 현재보이는 Row 들간에 루프 돌기
    for( ;row <=bottom;row++)
    {
    // 아이템의 경계 사각형을 가져오고, 점이 포함되는지 체크
    CRect rect;
    GetItemRect( row, &rect, LVIR_BOUNDS );
    if( rect.PtInRect(point) )
    {
    // 컬럼찾기
    for( colnum = 0; colnum < nColumnCount; colnum++ )
    {
    int colwidth = GetColumnWidth(colnum);
    if( point.x >= rect.left?
    && point.x <= (rect.left + colwidth ) )
    {
    RECT rectClient;
    GetClientRect( &rectClient );
    if( col ) *col = colnum;
    rect.right = rect.left + colwidth;
    // 오른쪽 끝이 클라이언트 영역을 벗어나지 않도록 확인
    if( rect.right > rectClient.right )
    rect.right = rectClient.right;
    *cellrect = rect;
    return row;
    }
    rect.left += colwidth;
    }
    }
    }
    return -1;
    }

    OnToolTipText()함수를 정의합니다. 이것은 툴팁으로 부터의 TTN_NEEDTEXT통지에대한 핸들러입니다. 실제로 OnToolTipText()는 TTN_NEEDTEXTA와 TTN_NEEDTEXTW 통지 양쪽을 처리하며 프로그램자신이 ANSI든 UNICODE든 관계없이 전자를 위해 ANSI 스트링을 사용하며 후자를 위해 UNICODE 스트링을 사용합니다.

    BOOL CMyListCtrl::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
    {
    // ANSI 와 UNICODE 양쪽버젼의 메시지를 처리해야함
    TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
    TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
    CString strTipText;
    UINT nID = pNMHDR->idFrom;
    if( nID == 0 ) // NT 에서의 자동생성 툴팁으로부터의 통지
    return FALSE; // 그냥 빠져나간다.
    int row = ((nID-1) >> 10) & 0x3fffff ;
    int col = (nID-1) & 0x3ff;
    strTipText = GetItemText( row, col );
    #ifndef _UNICODE
    if (pNMHDR->code == TTN_NEEDTEXTA)
    lstrcpyn(pTTTA->szText, strTipText, 80);
    else
    _mbstowcsz(pTTTW->szText, strTipText, 80);
    #else
    if (pNMHDR->code == TTN_NEEDTEXTA)
    _wcstombsz(pTTTA->szText, strTipText, 80);
    else
    lstrcpyn(pTTTW->szText, strTipText, 80);
    #endif
    *pResult = 0;
    return TRUE; // 메시지가 처리되었다.
    }

    함수는 먼저 NT에서의 내장툴팁 통지인지 체크하고 맞다면 바로 리턴 합니다. 그리고id로부터 로우와 컬럼정보를 해독하고 셀안의 정보로 TOOLTIPTEXT구조체를 채웁니다

    메시지맵에 OnToolTipText()를 연결하십시오. ON_NOTIFY_EX 와 ON_NOTIFY_EX_RANGE 매크로를 사용하는 것이 좋습니다. 이것은 필요하다면 더이상의 메시지 처리를 위해 통지를 전달하는것을 가능하게 합니다.

    BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
    //{{AFX_MSG_MAP(CMyListCtrl)
    :
    // other entries
    :
    //}}AFX_MSG_MAP
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
    END_MESSAGE_MAP()
     

    우리가 단순한 ON_NOTIFY매크로를 사용하지 않는다는것에 주의하십시오.실제로 당신이 ON_NOTIFY(TTN_NEEDTEXT, 0, OnToolTipText) 같은 메시지맵 엔트리를 사용한다면 몇 개의 큰 문제점을 가지게 됩니다. 첫째로 TTN_NEEDTEXT 통지는 ANSI 빌드 버젼에선 NT 4.0 상에서는 절대로 받을 수 없는 TTN_NEEDTEXTA로 변환됩니다. 둘째로, 우리는 일반적인 경우가 아닌 ID 0 이외의 값에 관심이 있다는 것입니다.

    9.4 각 셀을 위한 타이틀팁

    타이틀은 다소 툴팁과 비슷합니다. 리스트뷰 컨트롤에 대해서, 타이틀팁은 텍스트를 다 보여줄수 있을만큼 넓지 못할때 사용됩니다.타이틀팁은 마우스가 셀의 위에 위치 하지 마자 보여지게 됩니다.

    <그림>

    우리는 타이틀팁을 위해 커스텀클래스를 정의합니다. 타이틀팁은 WM_MOUSEMOVE 핸들러에서 생성됩니다. 타이틀팁은 마우스가 아이템 밖으로 나가거나 응용프로그램이 포커스를 잃을때 자기자신을 파괴하게 됩니다. OnMouseMove() 코드는 CellRectFromPoint() 함수를 로우,컬럼인덱스와 하부아이템의 경계영역사각형을 알아내기 위해 사용합니다. 그리고 타이틀팁 객체에 사각형과 아이템 텍스트의 정보를 넘기게 됩니다. 타이틀팁객체가 화면에 보여질지를 결정하게 됩니다.

    void CMyListCtrl::OnMouseMove(UINT nFlags, CPoint point)
    {
    if( nFlags == 0 )
    {
    // 타이틀팁 객체 Enable 하기 위해서
    int row, col;
    RECT cellrect;
    row = CellRectFromPoint(point, &cellrect, &col );
    if( row != -1 )
    {
    // 컬럼 왼쪽 경계에서부터의 오프셋은 보통 5픽셀
    int offset = 5;
    // 첫번째 컬럼에 대해선 오프셋은 그림을 고려해야 합니다.
    // 아래오프셋은 자기자신의 프로그램에 맞는값을 사용하십시오
    if( col == 0 ) offset +=19;
    m_titletip.Show( cellrect, GetItemText( row, col ), offset );
    }
    }
    CListCtrl::OnMouseMove(nFlags, point);
    }
    PreSubclassWindow() 함수가 오버라이드 되어있지 않다면, 해야 합니다. 이 함수에서 타이틀팁 객체를 생성 할 것 입니다.
    void CMyListCtrl::PreSubclassWindow()
    {
    CListCtrl::PreSubclassWindow();
    // Add initialization code
    m_titletip.Create( this );
    }
    헤더파일과 구현파일이 아래 있습니다.
    #if !defined(AFX_TITLETIP_H__FB05F243_E98F_11D0_82A3_20933B000000__INCLUDED_)
    #define AFX_TITLETIP_H__FB05F243_E98F_11D0_82A3_20933B000000__INCLUDED_
    #if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000
    // TitleTip.h : header file
    //
    /////////////////////////////////////////////////////////////////////////////
    // CTitleTip window
    #define TITLETIP_CLASSNAME _T("ZTitleTip")
    class CTitleTip : public CWnd
    {
    // Construction
    public:
    CTitleTip();
    // Attributes
    public:
    // Operations
    public:
    // Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CTitleTip)
    public:
    virtual BOOL PreTranslateMessage(MSG* pMsg);
    //}}AFX_VIRTUAL
    // Implementation
    public:
    void Show( CRect rectTitle, LPCTSTR lpszTitleText, int xoffset = 0);
    virtual BOOL Create( CWnd *pParentWnd);
    virtual ~CTitleTip();
     
    protected:
    CWnd *m_pParentWnd;
    CRect m_rectTitle;
    // Generated message map functions
    protected:
    //{{AFX_MSG(CTitleTip)
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };
    /////////////////////////////////////////////////////////////////////////////
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Developer Studio will insert additional declarations immediately
    // before the previous line.
    #endif // !defined(AFX_TITLETIP_H__FB05F243_E98F_11D0_82A3_20933B000000__
    INCLUDED_)

    CTitleTip 의 생성자에서 이 프로그램의 다른 인스턴스에서 윈도우의 클래스를 등록하지 않았다면 등록하게 됩니다. 클래스에 대한 배경 브러쉬는 COLOR_INFOBK를 사용하게 되어 툴팁의 색상과 같게 됩니다.

    Create() 함수에서는 주목해서 볼것이 윈도우 스타입니다. WS_BORDER 스타일이 타이틀팁 윈도우주위에 경계선을 그리게 합니다. WS_POPUP스타일은 타이틀팁이 리스트뷰 컨트롤의 경계를 벗어날수도 있게 하기위해 필요합니다. WS_EX_TOOLWINDOW스타일은 윈도우가 태스크바에 나타나지 않도록 해줍니다. WS_EX_TOPMOST 스타일은 타이틀팁이 보이도록 해줍니다.Show() 함수는 텍스트의 크기가 셀의 크기보다 클때 타이틀팁을 보여주게 됩니다.경계 사각형은 변형되고 나중에 언제 타이틀팁이 숨겨져야 할때를 결정하기 위해 저장됩니다.

    WM_MOUSEMOVE에 대한 핸들러 OnMouseMove()는 타이틀팁이 보일 셀 영역에 마우스가 있는지를 검사합니다. 이 영역은 타이틀팁 윈도우의 클라이언트 영역 사각형보다 작습니다. 만약 마우스가 영역 밖으로 나간다면 타이틀이 숨겨지고 적절한 윈도우에WM_MOUSEMOVE 메시지가 전달됩니다.타이틀팁은 또한 사용자가 키나 마우스버튼을 눌렀을때 없어질 필요가 있습니다.우리는 이메시지들에 대해 살펴보기 위해 PreTranslateMessage()를 오버라이드 합니다. 만약 이 메시지들중에 어떤것이라도 받는다면 타이틀팁은 없어지고 리스트뷰 컨트롤에 메시지가 전달됩니다.

     

    // TitleTip.cpp : implementation file
    //
    #include "stdafx.h"
    #include "TitleTip.h"
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    /////////////////////////////////////////////////////////////////////////////
    // CTitleTip
    CTitleTip::CTitleTip()
    {
    // 만약 이미 등록되지 않았다면 윈도우 클래스를 등록한다.
    WNDCLASS wndcls;
    HINSTANCE hInst = AfxGetInstanceHandle();
    if(!(::GetClassInfo(hInst, TITLETIP_CLASSNAME, &wndcls)))
    {
    // 새로운 클래스 등록
    wndcls.style = CS_SAVEBITS ;
    wndcls.lpfnWndProc = ::DefWindowProc;
    wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
    wndcls.hInstance = hInst;
    wndcls.hIcon = NULL;
    wndcls.hCursor = LoadCursor( hInst, IDC_ARROW );
    wndcls.hbrBackground = (HBRUSH)(COLOR_INFOBK + 1);
    wndcls.lpszMenuName = NULL;
    wndcls.lpszClassName = TITLETIP_CLASSNAME;
    if (!AfxRegisterClass(&wndcls))
    AfxThrowResourceException();
    }
    }
    CTitleTip::~CTitleTip()
    {
    }
    BEGIN_MESSAGE_MAP(CTitleTip, CWnd)
    //{{AFX_MSG_MAP(CTitleTip)
    ON_WM_MOUSEMOVE()
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    /////////////////////////////////////////////////////////////////////////////
    // CTitleTip message handlers
    BOOL CTitleTip::Create(CWnd * pParentWnd)
    {
    ASSERT_VALID(pParentWnd);
    DWORD dwStyle = WS_BORDER | WS_POPUP;?
    DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
    m_pParentWnd = pParentWnd;
    return CreateEx( dwExStyle, TITLETIP_CLASSNAME, NULL, dwStyle, 0, 0, 0, 0,
    NULL, NULL, NULL );
    }
    void CTitleTip::Show(CRect rectTitle,LPCTSTR lpszTitleText,int xoffset /*=0*/)
    {
    ASSERT( ::IsWindow( m_hWnd ) );
    ASSERT( !rectTitle.IsRectEmpty() );
    if( IsWindowVisible() )
    return;
    m_rectTitle.top = -1;
    m_rectTitle.left = -xoffset;
    m_rectTitle.right = rectTitle.Width()-xoffset;
    m_rectTitle.bottom = rectTitle.Height();
    m_pParentWnd->ClientToScreen( rectTitle );
    CClientDC dc(this);
    CString strTitle(lpszTitleText);
    CFont *pFont = m_pParentWnd->GetFont();
    CFont *pFontDC = dc.SelectObject( pFont );
    CRect rectDisplay = rectTitle;
    CSize size = dc.GetTextExtent( strTitle );
    rectDisplay.left += xoffset;
    rectDisplay.right = rectDisplay.left + size.cx + 5;
    // 만약 텍스트가 공간에 맞다면 보이지 않는다.
    if( rectDisplay.right <= rectTitle.right-xoffset )
    return;
    SetWindowPos( &wndTop, rectDisplay.left, rectDisplay.top,
    rectDisplay.Width(), rectDisplay.Height(),
    SWP_SHOWWINDOW|SWP_NOACTIVATE );
    dc.SetBkMode( TRANSPARENT );
    dc.TextOut( 0, -1, strTitle );
    dc.SelectObject( pFontDC );
    SetCapture();
    }
    void CTitleTip::OnMouseMove(UINT nFlags, CPoint point)
    {
    if( !m_rectTitle.PtInRect( point ) )
    {
    ReleaseCapture();
    ShowWindow( SW_HIDE );
    // 메시지를 전달한다.
    ClientToScreen( &point );
    CWnd *pWnd = WindowFromPoint( point );
    if( pWnd == this ) pWnd = m_pParentWnd;
    pWnd->ScreenToClient( &point );
    pWnd->PostMessage(WM_MOUSEMOVE, nFlags, MAKELONG( point.x, point.y ));
    }
    }
    BOOL CTitleTip::PreTranslateMessage(MSG* pMsg)
    {
    CWnd *pWnd;
    switch( pMsg->message )
    {
    case WM_LBUTTONDOWN:
    case WM_RBUTTONDOWN:
    case WM_MBUTTONDOWN:
    POINTS pts = MAKEPOINTS( pMsg->lParam );
    POINT point;
    point.x = pts.x;
    point.y = pts.y;
    ClientToScreen( &point );
    pWnd = WindowFromPoint( point );
    if( pWnd == this ) pWnd = m_pParentWnd;
    pWnd->ScreenToClient( &point );
    pMsg->lParam = MAKELONG( point.x, point.y );
    // 그냥 밑으로 가게 합니다.
    case WM_KEYDOWN:
    case WM_SYSKEYDOWN:
    ReleaseCapture();
    ShowWindow( SW_HIDE );
    m_pParentWnd->PostMessage(pMsg->message, pMsg->wParam, pMsg->lParam);
    return TRUE;
    }
    if( GetFocus() == NULL )
    {
    ReleaseCapture();
    ShowWindow( SW_HIDE );
    return TRUE;
    }
    return CWnd::PreTranslateMessage(pMsg);
    }

    10. 드래그 와 드롭(Drag & Drop)

    10.1 컬럼 순서를 바꾸기 위해 컬럼 드래깅하기

    종종 리스트뷰 컨트롤에 제공되는 화면공간은 컨트롤의 모든 컬럼들을 보여주기에는 부족할 때가 많습니다. 또한 매우 자주 사용자는 자신이 원하는 대로 컬럼들을 재정렬 하고자 합니다. 이일을 해결하는데 주로 사용되는 방법은 컬럼을 드래깅하는 것으로 사용자가 리스트를 재정렬(컬럼순서)하도록 하는 것 입니다. 현재는 컬럼을 드래깅하는것에 대한 지원은 없으며, 다음버젼의 공통 컨트롤에서는 소개될것 같습니다. 아래는 이것을 지원하는 방법입니다.

     

    단계 1: 커스텀 헤더 클래스를 만듭니다.

    CHeaderCtrl 로 부터 파생한 커스텀 헤더 클래스를 작성하여,컬럼드래깅을 처리하고 사용자에게 비주얼한 피드백을 제공하며 마지막으로 CListCtrl 의 멤버 함수를 호출하여 리스트를 재정렬하게 합니다.

    먼저 헤더파일입니다.

    #if !defined(AFX_MYHEADERCTRL_H__CC3DDBF3_EF5E_11D0_82AD_9A0A48000000__
    INCLUDED_)
    #define AFX_MYHEADERCTRL_H__CC3DDBF3_EF5E_11D0_82AD_9A0A48000000__INCLUDED_
    #if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000
    // MyHeaderCtrl.h : header file
    //
    /////////////////////////////////////////////////////////////////////////////
    // CMyHeaderCtrl window
    class CMyHeaderCtrl : public CHeaderCtrl
    {
    // Construction
    public:
    CMyHeaderCtrl();
    CMyHeaderCtrl(CWnd* pWnd, void (CWnd::*fpDragCol)(int, int));
    // Attributes
    public:
    // Operations
    public:
    // Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CMyHeaderCtrl)
    //}}AFX_VIRTUAL
    // Implementation
    public:
    virtual ~CMyHeaderCtrl();
    void SetCallback(CWnd* pWnd, void (CWnd::*fpDragCol)(int, int));
    protected:
    BOOL m_bCheckForDrag;
    BOOL m_bDragging;
    int *m_pWidth;
    int m_nDragCol;
    int m_nDropPos;
    CRect marker_rect;
    void (CWnd::*m_fpDragCol)(int, int);
    CWnd *m_pOwnerWnd;
    // Generated message map functions
    protected:
    //{{AFX_MSG(CMyHeaderCtrl)
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };
    /////////////////////////////////////////////////////////////////////////////
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Developer Studio will insert additional declarations immediately
    // before the previous line.
    #endif // !defined(AFX_MYHEADERCTRL_H__CC3DDBF3_EF5E_11D0_82AD_9A0A48000000__
    INCLUDED_)

    CMyHeaderCtrl 은 CHeaderCtrl 로 부터 파생한 것입니다. 변경 기본 생성자가 다소 생소할 것 입니다. 이것은 CListCtrl 이나 CListView 파생클래스에 대한 포인터와 사용자가 컬럼 드래깅을 끝마쳤을시 호출할 멤버함수에 대한 포인터를 받습니다. SetCallback() 이란 멤버 함수도 정의됩니다. 이 함수는 CMyListCtrl 클래스의 기본(Default) 생성자를 사용하고 싶을때 사용합니다. Protected 멤버 변수의 사용용도에 대한 간단한 설명입니다. m_bCheckForDrag 는 사용자가 컬럼헤더에 왼쪽마우스를 클릭했을때 WM_LBUTTONDOWN 핸들러에 의해서만 TRUE 로 세트됩니다. 이것은 WM_MOUSEMOVE 핸들러에 의해 현재가 컬럼 드래그 상태인지 체크하는데 사용됩니다. 사용자가 처음에 컬럼헤더에 마우스 버튼을 눌렀을때만 컬럼을 드래깅한다는 것은 중요합니다.

    m_bDragging 클래그는 컬럼드래그가 진행중이라는 것을 나타냅니다.

    m_pWidth 변수는 컬럼넓이에 대한 배열을 가리키고 있습니다.이것은 드롭할 목적지 컬럼을 결정하는데 사용합니다.

    m_nDragCol 변수는 드래그될 컬럼의 컬럼인덱스를 가지고 있습니다.

    m_nDragPos 는 새 위채의 컬럼인덱스를 가지고 있습니다.

    marker_rect 는 사용자에게 화면상에서 보여줄 표식인 사각형을 가지고 있습니다.화면에서 표식의 위치가 바뀌었을때 이전 표식을 지우는데도 사용됩니다.

    m_fpDragCol 변수는 사용자가 드래그 작업을 끝냈을때 호출될 CListCtrl 이나 CListView 의 멤버함수에 대한 포인터를 저장합니다.

    m_fOwnerWnd 변수는 m_fpDragCol 멤버함수가 호출될 객체에 대한 포인터를 가지게 됩니다. 이것은 보통 부모 윈도우가 될것입니다.

    아래는 구현파일입니다.

    // MyHeaderCtrl.cpp : implementation file
    //
    #include "stdafx.h"
    #include "MyHeaderCtrl.h"
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    /////////////////////////////////////////////////////////////////////////////
    // CMyHeaderCtrl
    CMyHeaderCtrl::CMyHeaderCtrl()
    : marker_rect(0,0,0,0)
    {
    m_pWidth = NULL;
    m_bDragging = FALSE;
    m_bCheckForDrag = FALSE;
    m_fpDragCol = NULL;
    m_pOwnerWnd = NULL;
    }
    CMyHeaderCtrl::CMyHeaderCtrl(CWnd *pWnd, void (CWnd::*fpDragCol)(int, int))
    : marker_rect(0,0,0,0)
    {
    m_pWidth = NULL;
    m_bDragging = FALSE;
    m_bCheckForDrag = FALSE;
    m_fpDragCol = fpDragCol;
    m_pOwnerWnd = pWnd;
    }
    CMyHeaderCtrl::~CMyHeaderCtrl()
    {
    }
    BEGIN_MESSAGE_MAP(CMyHeaderCtrl, CHeaderCtrl)
    //{{AFX_MSG_MAP(CMyHeaderCtrl)
    ON_WM_MOUSEMOVE()
    ON_WM_LBUTTONUP()
    ON_WM_LBUTTONDOWN()
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    /////////////////////////////////////////////////////////////////////////////
    // CMyHeaderCtrl message handlers
    void CMyHeaderCtrl::OnMouseMove(UINT nFlags, CPoint point)
    {
    if( (MK_LBUTTON & nFlags) == 0)
    {
    // 왼쪽버튼이 눌려지지 않았다. 플래그 리셋
    m_bCheckForDrag = FALSE;
    m_bDragging = FALSE;
    }
    else if( m_bDragging )
    {
    // 마우스 아래의 컬럼넘버를 가져온다.
    int i=0, cx = 0;
    if( point.x > 0 )
    for( i = 0; i < GetItemCount(); i++ )
    {
    if( point.x > cx && point.x < cx + m_pWidth[i] )
    break;
    cx += m_pWidth[i];
    }
    if( i != m_nDropPos )
    {
    m_nDropPos = i;
    CRect rect;
    GetWindowRect( &rect );
    // 이전 표식에 의해 점유된 영역을 무효화(Invalidate) 한다.
    InvalidateRect( &marker_rect );
     
    // 새로운 표식을 그린다.
    CClientDC dc(this);
    POINT pts[3];
    pts[0].x = cx; pts[1].x = cx -3; pts[2].x = cx +3;
    pts[0].y = rect.Height(); pts[1].y = pts[2].y = rect.Height() -7;
    dc.Polygon( pts, 3 );
    // 새로운 표식의 정보를 저장한다.
    marker_rect.left = cx - 4;
    marker_rect.top = rect.Height() -8;
    marker_rect.right = cx + 4;
    marker_rect.bottom = rect.Height();
    }
    return;
    }
    else if( m_bCheckForDrag )
    {
    // 마우스 버튼이 컬럼헤더상에서 클릭되었고 마우스가 움직였으므로
    // 드래깅을 시작한다.
    m_bCheckForDrag = FALSE;
    m_bDragging = TRUE;
    SetCapture();
    // 나중 사용을 위해 정보를 저장한다.
    int iCount = GetItemCount();
    HD_ITEM hd_item;
    m_pWidth = new int[iCount];
    for( int i = 0; i < iCount; i++ )
    {
    hd_item.mask = HDI_WIDTH;
    GetItem( i, &hd_item );
    m_pWidth[i] = hd_item.cxy;
    }
    return;
    }
    CHeaderCtrl::OnMouseMove(nFlags, point);
    }
    void CMyHeaderCtrl::OnLButtonUp(UINT nFlags, CPoint point)
    {
    ASSERT( m_pOwnerWnd != NULL && m_fpDragCol != NULL );
    if( m_bDragging )
    {
    m_bDragging = FALSE;
    delete[] m_pWidth;
    ReleaseCapture();
    Invalidate();
    // 콜백함수를 가져온다.
    if( m_nDragCol != m_nDropPos && m_nDragCol != m_nDropPos -1 )
    (m_pOwnerWnd->*m_fpDragCol)( m_nDragCol, m_nDropPos );
    }
    CHeaderCtrl::OnLButtonUp(nFlags, point);
    }
    void CMyHeaderCtrl::SetCallback( CWnd* pWnd,void (CWnd::*fpDragCol)(int, int))
    {
    m_fpDragCol = fpDragCol;
    m_pOwnerWnd = pWnd;
    }
    void CMyHeaderCtrl::OnLButtonDown(UINT nFlags, CPoint point)
    {
    // 마우스가 컬럼헤더상에서 눌렸는지 검사한다.
    HD_HITTESTINFO hd_hittestinfo;
    hd_hittestinfo.pt = point;
    SendMessage(HDM_HITTEST, 0, (LPARAM)(&hd_hittestinfo));
    if( hd_hittestinfo.flags == HHT_ONHEADER )
    {
    m_nDragCol = hd_hittestinfo.iItem;
    m_bCheckForDrag = TRUE;
    }
    CHeaderCtrl::OnLButtonDown(nFlags, point);
    }

    CMyHeaderCtrl 의 구현은 매우 간단합니다. 이것은 필수적으로 WM_MOUSEMOVE,WM_LBUTTONDOWN,WM_LBUTTONUP 에 대한 핸들러를 가지고 있습니다.

    OnLButtonDown() 은 m_nDragCol 에 값을 넣고 만약 사용자가 컬럼헤더상에서 마우스 버튼을 눌렀다면 m_bCheckForDrag 를 세트한다.

    OnMouseMove() 는 사용자에게 시각적인 효과를 주는곳이다. 이것은 먼저 왼쪽마우스 버튼이 눌렸는지 체크하고 m_bCheckForDrag 와 m_bDragging 플래그를 리셋합니다.만약 드래깅중이라면 m_nDropPos 값이 세트되고 헤더상에 표식이 그려집니다.만약 처음 두개의 조건이 실패하면 드래그가 초기화되어야 하는지 체크합니다.

    OnLButtonUp() 은 드래그 작업을 종료하고 , 드래그가 진행중이었다면 콜백 함수를 드래그된 컬럼과 드롭 위치를 인자로해서 호출합니다.

    단계 2: CListCtrl 파생클래스에 CMyHeaderCtrl 멤버변수를 추가합니다.

    CListCtrl 파생클래스에 CMyHeaderCtrl 멤버변수를 추가합니다. 만약 CListView를 사용중이라면 그 클래스에 멤버변수를 추가합니다.

    CMyHeaderCtrl m_headerctrl;

    단계 3: CMyHeaderCtrl 객체를 초기화 합니다.

    CListCtrl 파생클래스의 생성자에 아래문장을 추가합니다.

    m_headerctrl.SetCallback( this, (void (CWnd::*)(int, int))DragColumn );

    DragColumn 은 다음단계에서 정의할 콜백함수입니다.

    단계 4: 컬럼 재정렬을위해 콜백함수를 정의합니다.

    CMyHeaderCtrl 객체는 사용자가 드래그 작업이 끝났을때 호출할 함수의 포인터를 필요로 합니다. 이함수는 콜백함수로 실제로 컬럼을 재정렬할 책임이 있습니다. 우리는 3에서 CMyHeaderCtrl객체를 초기화할때 DragColumn이란 것을 사용했습니다.

    void CMyListCtrl::DragColumn(int source, int dest)
    {
    TCHAR sColText[160];
    // 목적지에 컬럼을 삽입한다.
    LV_COLUMN lv_col;
    lv_col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
    lv_col.pszText = sColText;
    lv_col.cchTextMax = 159;
    GetColumn( source, &lv_col );
    lv_col.iSubItem = dest;
    InsertColumn( dest, &lv_col );
    // 새컬럼이 삽입되었기 때문에 변화된 원본 Col 번호를 조절한다.
    // because a new column was inserted
    if( source > dest )
    source++;
    // 컬럼을 0 위치로 옮기는 것은 특별한 경우이다.
    if( dest == 0 )
    for( int i = GetItemCount()-1; i > -1 ; i-- )
    SetItemText(i, 1, GetItemText( i, 0) );
    // 원본에서 목적지로 하부아이템을 복사한다.
    for( int i = GetItemCount()-1; i > -1 ; i-- )
    SetItemText(i, dest, GetItemText( i, source ) );
    // 첫컬럼이 아닌경우 원본 컬럼을 지웁니다.
    if( source != 0 )
    DeleteColumn( source );
    else
    {
    // 만약 원본 컬럼이 0이면 col#1 의 것을 col#0 으로 복사한다.
    // and then delete col# 1
    GetColumn( 1, &lv_col );
    lv_col.iSubItem = 0;
    SetColumn( 0, &lv_col );
    for( int i = GetItemCount()-1; i > -1 ; i-- )
    SetItemText(i, 0, GetItemText( i, 1) );
    DeleteColumn( 1 );
    }
    Invalidate();

    }

    이 함수에서 취한 일반적인 접근방법은 맞는 자리에 컬럼을 삽입하고, 원본의 모든 컬럼을 모든 하부아이템으로 옮기는 겁니다. 리스트뷰 컨트롤은 첫번째 컬럼에 특별한 처리를 해주지 않습니다만, 우리는 해야만 합니다. 당신이 컬럼을 추가하거나 삭제할때 알아야할 특별한 것은... 0번 위치에 컬럼을 추가하려고 할 때 이미 하나이상의 컬럼이 있다면 새 컬럼은 실제로 두번째 컬럼에 추가됩니다. 만약 첫번재 컬럼을 지운다면 결과는 컬럼헤더들이 왼쪽으로 하나씩 시프트되고 마지막컬럼이 지워진다는 것입니다. DragColumn() 함수는 이 두가지 상황을 처리합니다.

    단계 5: 헤더컨트롤을 서브클래스 합니다.

    마지막으로 헤더컨트롤을 서브클래스 합니다. 좋은 곳은 리스트뷰 컨트롤 클래스의 PreSubclassWindow() 입니다.

    void CMyListCtrl::PreSubclassWindow()
    {
    CListCtrl::PreSubclassWindow();
    // Add initialization code
    m_headerctrl.SubclassWindow( ::GetDlgItem(m_hWnd,0) );
    }
    ==============================================================================

    자.. 이것으로 리스트뷰 컨트롤이 끝났네요...비록 졸작 번역이었지만.. 하면서 저한테도 도움이 많이 되었군요..리스트뷰 컨트롤을 사용하실 일이 생기시면 아주 도움이 될거라 믿습니다.이제 트리뷰를 시작해야 겠네요..

    신고
    TRACKBACK 0 AND COMMENT 0

    ARTICLE CATEGORY

    분류 전체보기 (14)
    쥬니 이야기 (7)
    게임 프로그래밍 (7)

    RECENT TRACKBACK

    CALENDAR

    «   2017/12   »
              1 2
    3 4 5 6 7 8 9
    10 11 12 13 14 15 16
    17 18 19 20 21 22 23
    24 25 26 27 28 29 30
    31            

    ARCHIVE