티스토리 뷰
기존의 윈도우나 컨트롤의 형태 또는 동작을 변경할 수 있도록 한다.
윈도우(정확하게는 윈도우 프로시저)로 가는 메시지를 중간에서 붙잡아 처리하는 기법이다.
메시지 종류에 따라 처리한 후 원래의 윈도우 프로시저에게 전달해주거나 전달하지 않을 수도 있다. 이렇게 함으로써 원래의 윈도우 동작이 바뀌는 것이며, 이 기업은 일반적인 윈도우는 물론이고 컨트롤에도 적용할 수 있다.
MFC 에서는 일반 윈도우나 컨트롤을 모두 클래스(객체) 수준에서 다루며 메시지 매핑 기법을 사용하여 메시지를 처리하므로 서브 클래싱을 쉽게 구현할 수 있다.
<서브 클래실 구현 순서>
1. 기존의 클래스를 기반으로 새로운 윈도우나 컨트롤를 생성한다.
2. 메시지 핸들러를 재정의 하거나 새로운 메시지 핸들러를 추가하여 사용한다.
3. CWnd::SubclassWindow() 또는 CWnd::SubclassDlgitem() 을 호출한다.
1,2 단계 후 객체를 선언하고 윈도우나 컨트롤을 생성하는 것으로도 서브 클래싱의 효과를 얻을 수 있으며, 이 경우를 정적 서브 클래싱(Static Subclassing) 이라 부른다.
그러나 이미 생성된 윈도우나 컨트롤의 동작을 실행 중에 변경하려면 3단계를 실행해야 한다. 예를 들어 대화상자를 디자인할 때 배치하는 컨트롤은 모두 표준 컨트롤이다. 이 컨트롤들을 대화상자와 더블어 같이 생성되는데, 이들의 동작을 바꾸려면 실행 중에 서브 클래싱을 해야 한다. 이와 같이 이미 생성된 윈도우 또는 컨트롤의 동작을 실행 중에 변경하는 기법을 동적 서브 클래싱(Synamic Subclassing) 이라 부른다.
대화상자에 존재하는 컨트롤은 CWnd::SubclassWindow() 또는 CWnd::SubclassDlgItem() 을 직접 사용하지 않고도 동적 서브 클래싱을 할 수 있는 좀 더 편리한 방법이 있다. 클래스 마법사를 이용하여 컨트롤 변수를 생성하면 DDX_Control() 을 호출하는 코드가 추가되는데, 이 코드 내부에서 CWnd::SubclassWindow()를 호출하여 자동으로 서브 클래싱을 하게 된다.
<방법1>
1. CEdit 상속받는 CMyEdit 클래스를 추가한다.
2. 클래스 마법사를 이용해서 컨트롤 변수를 추가한다.
3. 상속 받은 CEdit는 키보드에서 모든 문자가 입력 가능한데, 이를 숫자와 -, Backspace 키만으로 제한 시킨다.
1
2
3
4
5 |
void CMyEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if(nChar >= '0' && nChar <= '9' || nChar == '-' || nChar == VK_BACK)
CEdit::OnChar(nChar, nRepCnt, nFlags);
} |
cs |
<방법2>
방법1에서 마법사를 통해 자동으로 서브클래싱이 되었으나 여기서는 수동으로 서브 클래싱을 한다.
방법1에서 만든 CMyEdit 클래스 객체(변수) 추가하고 SubclassDlgItem() 호출하는 코드를 수동으로 추가하면 된다.
1
2
3
4
5
6
7
8
9
10
11 |
class CMFCApplication5View : public CFormView
{
...
CMyEdit m_edit2;
};
void CMFCApplication5View::OnInitialUpdate()
{
...
m_edit2.SubclassDlgItem(IDC_EDIT2, this);
} |
cs |
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
32
33
34
35
36
37
38
39 |
class CMyEdit : public CEdit
{
DECLARE_DYNAMIC(CMyEdit)
public:
CMyEdit();
virtual ~CMyEdit();
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
};
void CMyEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if(nChar >= '0' && nChar <= '9' || nChar == '-' || nChar == VK_BACK)
CEdit::OnChar(nChar, nRepCnt, nFlags);
}
class CMFCApplication5View : public CFormView
{
...
CMyEdit m_edit1;
CMyEdit m_edit2;
};
void CMFCApplication5View::DoDataExchange(CDataExchange* pDX)
{
CFormView::DoDataExchange(pDX);
DDX_Control(pDX, IDC_EDIT1, m_edit1);
}
void CMFCApplication5View::OnInitialUpdate()
{
...
m_edit2.SubclassDlgItem(IDC_EDIT2, this);
} |
cs |
2개의 편집 컨트롤 둘 다 숫자와 -, Backspace 키만 입력 받도록 CEdit를 서브 클래싱 한것이다.
방법1, 2 중 편한 방법으로 구현하면 된다.
수퍼 클래싱
'새로운' 윈도우 클래스 등록 (추가 개념)
윈도우 클래스를 새로 등록하여 기존 윈도우 클래스 대신 사용하는 것
::SetWindowLong()
서브 클래싱
'기존' 윈도우 클래스 사용, 대신 프로시저 변경 또는 대체 (대체 개념)
기존 윈도우 클래스에서 프로시저만 변경하는 것
::SetClassLong()
수퍼/서브 클래싱 둘 다 자신의 프로시저 함수에서 ::CallWindowProc() 를 사용하여 기존의 프로시저 함수를 호출할 수 있다.