본문 바로가기

Language/MFC

프로퍼티 시트 탭 글꼴/색상/변경

탭 컨트롤을 많이 사용해보지 않아서 만들때도 많이 해맸는데 프로퍼티 시트를 이용한 탭 컨트롤 제어는 오죽했겠는가....


일단 프로퍼티 시트와 탭 컨트롤의 차이점은 VC++6.0 완전정복 SE 에 기제되어 있듯이 탭에 다른 화면을 출력하기 위해서는 프로퍼티 시트를 사용하는 것이 좋다고 한다.


사실 차이는 그닥...ㄱ- 머 그렇다고 그냥 탭 컨트롤은 않되나? 그것도 아님..ㅡㅡ;


어째든 책 보고 하다 보니;; 프로퍼티 시트를 이용하여 탭 컨트롤을 구현하게 되었고 색상을 변경하려고 하니...이건머...탭 컨트롤에 대한 내용만 있군...


일단 이리저리 서칭해본 결과 Tip Soft 등에서 찾아본 결과 프로퍼티 시트 클래스는 내부적으로 탭 클래스를 생성하도록 되어있다. 


때문에 프로퍼티 시트 클래스를 상속받은( 프로퍼티 시트를 만들때 매인이 되는 클래스) 클래스 멤버 함수중 GetTabControl() 함수로 탭 클래스의 포인트를 받아올 수 있다. 


때문에 제대로된 탭 클래스를 컨트롤 하려면 탭 클래스를 상속받은 클래스(빈 Tab class를 상속받은 MFC클래스를 만들어서) 에 이를 연결해주면 된다. 


이를 서브클래싱이라 한다. 


ㅡㅡ 머 이리저리 자료를 뒤저보니 간단한거 같으면서도 좀 어려운듯 하다. 


1. 일단 프로퍼티 시트를 탭 형식으로 만들고


2. new class 를 이용하여 MFC Class 를 선택, Base class를 Tab class로 지정하고 하나 만든다. 


3. 프로퍼티 시트를 상속받은 프로퍼티 시트 컨트롤 매인 클래스에 2번으로 만든 클래스 객체를 만든다. (멤버로 만들어 준다.)


3. 프로퍼티 시트를 상속받은 프로퍼티 시트 의 매인 클래스 OnInitDialog() 함수에 서브클래싱을 해준다.

3-1. 탭 클래스의 멤버 함수중 SubclassDlgItem() 함수를 호출하는데 이 함수는 컨트롤 ID와 포인터를 필요로 한다.

BOOL CWnd::SubclassDlgItem(UINT nID, CWnd* pParent);

3-2. 서브클래싱을 해줄때 사실 탭 컨트롤의 아이디를 알 수 가 없다. 다음 지식 답변에는 윈도우 아이디를 모두 알 수 있는 음...프로그램 생각이 않난다.ㅡ.ㅡ;; 여튼 그걸 이용하는데 사실 아이디는 할당이 언제든 변경될 수 있으니 직접 때리는 것은 좋지않다고 판단! 그래서 좀 머리를 써봤다. 다음과 같이 ID를 받아온다.

this->GetTabControl()->GetDlgCtrID() 

그리고 CWnd의 핸들은 this만 넣어주면 된다. 만일 탭 클래스를 m_MyTab이라고 만들었다면, 


m_MyTab.SubClassDlgItem(this->GetTabControl()->GetDlgCtrID(), this);


를 호출한다. 이로써 일단 탭 컨트롤를 클래스로 연결은 됐다. 그렇기 때문에 m_MyTab이 탭컨트롤의 클래스라고 봐도 된다.


3-3. 컨트롤의 색을 변경하기 위해서는 DrawItem(LPDRAWITEMSTRUC lpDrawItemStruct) 를 제정의 하여 내부에서 DC를 이용하여 색이나 폰트를 변경 할 수 있다. 

하지만 이 DrawItem을 호출하기 위해서는 OwnerDraw를 호출해줘야 하므로 


m_MyTab.ModifyStyle(0, TCS_OWNERDRSWFIXED); 


를 호출해준다. 이 루틴을 디버그 해보면 모디피스타일 함수가 콜 되면 DrawItem이 호출이 된다. 


그리고 DrawItem 함수에 


CDC* pDC = GetSystemMetrics(SM_SYEDGE); 로 DC의 객체를 받아온 후 일반적인 DrawItem에서 색상을 변경하 듯이 루틴을 만들면 된다. 


3-4 만일 탭컨트롤 캡션의 글자 색을 변경하려고자 한다면 pDC->SetTextColor(RGB(R,G,B));를 호출하면되고, (물론 pDC->SetBkMode(TRANSPARENT);를 호출하여 글자 배경을 투명하게 만드는 것도 잊지 말자)


배경색을 변경하려면 pDC->FillSolidRect();를 호출하면 된다. 이때 Rect인자는 DrawItem 매개변수인 lpDrawItemStruct구조체의 멤버의 rcItem을 받아와서 넣으면 된다. 


3-5 이런식으로 탭 캡션의 색상이나 글자체 (물론 CFont를 이용하면 된다.) 를 변경 할 수있다. 하지만 이런식으로 해보면 100% 먼가 이상하다는 것을 알 수 있다. 캡션의 Text가 않보인다.ㄱ- ;;. 이유는 이 기법은 이미 Tab컨트롤이 생성되고 난 후에 색을 입히는 방식이기 때문에 모든 글자들이 덥혀버린다. 


그래서 DrawItem 에서 다시 글을 써줘야 한다. 


방법은 lpDrawItemStruct구조체의 멤버중 itemID 를 이용하여 각 탭의 캡션을 넣어주면 된다.

DrawItem 함수는 탭의 갯수 만큼 호출이 된다. (물론 더 많이 되긴 하다.ㅋㅋㅋ) 그렇기 때문에 캡션을 넣는 루틴을 넣어주면 된다. 

char tab_text[50];


switch(lpDrawItemStruct->itemID)

{

case 0 : strcpy(tab_text, "탭1번");

break;

case 1 : strcpy(tab_text, "탭2번");

break;

}


pDC->DrawText(tab_text, rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);


이러면 글자들이 모두 변경 된다. 


4. 일단 나는 폰트를 변경하고 싶다는 취지가 강했기 때문에 이를 해봤는데 같은 회사의 과장님 께서 더 단순하게 하는 방법이 있을 거라며 고민하시다 해결책을 내준 방법이다.


아 물론 서브클래싱을 사용 않하는건 아니지만 글을 다시 써줘야 하는등 하지 않아도 된다. 


4-1. 3-2 까지의 루틴은 동일하다. 서브클래싱으로 포인트를 넘겨 받은 후 

CFont font;

//폰트를 이리저리 세팅

::SendMessage(m_MyTab,.m_hWnd, WM_SETFONT,(WPARAM)Font.GetSafeHandle(), 1);


이 방법을 이용하면 단순하게 폰트가 변경 된다. 

 


일단 시간이 없다는 핑계로 테스트를 해보지는 않았지만 4번으로 색상도 변경이 가능할 것 이다. 


음...나머지 함수에 대해서는 구글링 해보시고~ 나중에 따로 포스팅 할 예정이다.