본문 바로가기
Windows/Windows API (설명&함수 사용 실수..)

CWnd::Invalidate 함수 & static 에 글씨가 겹쳐서 보일 때

by 미티치 2021. 8. 20.

Static에 글씨가 겹쳐서 보일 때 조치법

CStatic 을 상속받은 재정의 클래스를 선언하고, OnPaint 함수에서 배경을 투명화하고 DrawText 하도록 해주었다.

그랬더니 Invalidate 함수를 호출할때마다 글자가 한겹씩 점점 더 진해지는게 아닌가!

 

이런 경우는 아래 URL 을 참고하여 해결하는 방법이 있다.

필자는 우선 이런 방식으로 해결은 하였다만, 또 다른 방법도 있어 소개하려고 한다.

 

1. 글씨를 출력하는 SetWindowsText 호출 전에 Invalidate(FALSE)를 호출하는 방법

https://itbrain.tistory.com/entry/MFCStatic-Control-%EB%B0%B0%EA%B2%BD-%ED%88%AC%EB%AA%85%ED%99%94-%EB%B0%8F-%EA%B8%80%EC%9E%90-%EA%B2%B9%EC%B9%A8-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95

 

2. CStatic을 상속받은 재정의 클래스를 선언한 경우

- BOOL 형식의 m_bDrawText 를 선언, 이 멤버변수를 이용해 text 가 변경되지 않는 이상 DrawText를 재호출하지 않는다.

class ColorStatic : public CStatic
{
...
public :
	BOOL	m_bDrawText;
    CString	m_strText;
...
}

OnPaint 에서 DrawText 를 호출하면 멤버 변수인 m_bDrawText 를 TRUE 로 셋팅

void ColorStatic::OnPaint()
{
	CPaintDC	dc(this);
    ...
    SetBkMode(TRANSPARENT);
    ...
    if(FALSE == m_bDrawText)
    {
    	if( 0!=DrawText(m_strText, m_strText.size(), ...))
        	m_bDrawText = TRUE;
    }
    
}
...
void ColorStatic::SetText(CString strText)
{
	m_strText = strText;
    if(NULL != m_pWnd->hwnd)	// 변수명 정확하지 않음
    {
    	Invalidate(FALSE);
    }
}

 

 

 

 

Invalidate 함수

MSDN Invalidte함수

윈도우 화면을 갱신할때는 두가지의 메시지를 이용할수 있습니다.

 

WM_PAINT와 WM_ERASEBKGND 메시지입니다.

이 메시지를 발생하기 위해 사용하는게 바로 Invalidate 함수입니다. 인자만 다르게 설정하면 되는데요.

WM_PAINT 메시지만 발생하고 싶으시다면 Invalidate(FALSE); WM_PAINT와 WM_ERASEBKGND 메시지 둘다 발생하고 싶다면 Invalidate(); 또는 Invalidate(TRUE); 라고 호출하면 됩니다.

 

Invalidate(FALSE) : WM_PAINT

Invalidate(TRUE)  : WM_PAINT -> WM_ERASEBKGND

 

즉, FALSE 인자는 백그라운드(현재 그려저 있는 거 포함)를 지우지 않고 그냥 그리고 TRUE는 백그라운드를 다 지우고 그린다는 의미인데, 여기서 백그라운드는 단순히 배경 색만 의미하는게 아니라 이미 영역 내에 그려진 것을 포함합니다.

 

 

 

Invalidate(TRUE); 로 화면을 갱신할때는 WM_PAINT 메시지가 일단 발생하고 WM_PAINT 메시지 핸들러에서 아래와 같이 DC 변수를 할당할때, WM_ERASEBKGND 메시지가 발생합니다.

CPaintDC dc(this);

 

호출 순서를 살펴보면 다음과 같습니다.

void CMyWnd::OnPaint()
{
    m_event_list.InsertString(-1, "Paint1");
    CPaintDC dc(this); // device context for painting
    m_event_list.InsertString(-1, "Paint2");
}
BOOL CMyWnd::OnEraseBkgnd(CDC* pDC)
{
    m_event_list.InsertString(-1, "Bk");
    return CWnd::OnEraseBkgnd(pDC);
}

 

위와 같이 코드를 구성하고 Invalidate(TRUE); 라고 호출하면 출력되는 순서가 아래와 같습니다.

        Paint1 -> Bk -> Paint2

따라서 호출순서를 잘 생각하시고 프로그램하시는것이 좋습니다.

 

예외적으로, 윈도우가 처음 생성될때는 위 호출이 아래와 같습니다.

        Bk -> Paint1 -> Paint2

즉, OnInitDialog 호출 시에는 OnEraseBkgnd() -> OnPaint 호출되고 OnPaint 중간에 CPaintDC dc(this); 호출부가 있어도 다시 OnEraseBkgnd( ) 가 호출되지 않는다는 말입니다.

 

 

[Reference]

1. https://taessing.tistory.com/86 [Taessing]

2. http://www.tipssoft.com/bulletin/board.php?bo_table=FAQ&wr_id=48