[ATL/WTL]_[初級]_[自定義的窗口爲什麼調用SetFont後無效-GetFont爲NULL]

場景

  1. WTL開發時,我們開發自定義的窗口類,繼承自CWindowImpl,而這個類自帶有SetFontGetFont方法. 問題是調用了這個SetFont方法,之後在調用GetFont方法返回的HFONTNULL, 怎麼回事?

說明

  1. CWindowImpl類裏,SetFont方法實際上就是發送了WM_SETFONT消息. 而WM_SETFONTAPI並沒有說明提示設置字體不生效的情況。事實上,查閱網上的資料,對於自定義的控件(即內部是自定義WNDCLASS),不是系統自帶的默認控件,系統不會處理WM_SETFONTWM_GETFONT消息,需要自己處理這兩個消息,也就是說並沒有一個句柄HFONT變量存儲設置的值。

  2. 在自定義的控件裏,我們可以在消息映射裏處理這兩個消息, 還需要添加一個HFONT的實例變量來存儲WM_SETFONT消息設置的值.

MSG_WM_SETFONT(OnSetFont)
MSG_WM_GETFONT(OnGetFont);

CFont font_normal_;

HFONT CView::OnGetFont()
{
	return font_normal_;
}

void CView::OnSetFont(CFontHandle font, BOOL bRedraw)
{
	font_normal_ = font;
}

例子

  1. my_container.h 只是用來測試自定義窗口默認的SetFont無效的窗口類.

  2. CView.h 是增加了處理WM_SETFONTWM_GETFONT消息的自定義窗口類.

my_container.h

// MyContainer.h : interface of the MyContainer class
//
/////////////////////////////////////////////////////////////////////////////

#pragma once

#include <utility>
#include <string>
#include <functional>
#include <atlmisc.h>
#include <atlctrls.h>
#include <GdiPlus.h>

class MyContainer : public CWindowImpl<MyContainer>
{
public:
	DECLARE_WND_CLASS(NULL)

	BOOL PreTranslateMessage(MSG* pMsg);

	BEGIN_MSG_MAP_EX(MyContainer)
		MSG_WM_CREATE(OnCreate)
		MESSAGE_HANDLER(WM_PAINT, OnPaint)
		REFLECT_NOTIFICATIONS()
	END_MSG_MAP()

	int OnCreate(LPCREATESTRUCT lpCreateStruct);
	LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
	
private:
	std::wstring GetControlText(HWND hwnd,wchar_t* buf = NULL);

	CFont font_normal_;

	CBrushHandle brush_white_;
	CBrushHandle brush_hollow_;
	CBrush brush_red_;

public:
};

my_container.cpp

// my_container.cpp : implementation of the MyContainer class
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h"
#include <utility>
#include <assert.h>

#include "my_container.h"
#include <CommCtrl.h>
#include <string>
#include <regex>


BOOL MyContainer::PreTranslateMessage(MSG* pMsg)
{
	return FALSE;
}

LRESULT MyContainer::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	CPaintDC dc(m_hWnd);
	CMemoryDC mdc(dc,dc.m_ps.rcPaint);

	CRect rect_client;
	GetClientRect(&rect_client);
	mdc.FillSolidRect(rect_client,RGB(255,0,0));
	mdc.SetBkColor(RGB(255,0,0));
	auto font = GetFont();
	static const wchar_t* text = L"GetFont result is NULL";
	if(font == NULL)
		mdc.DrawText(text,wcslen(text),rect_client,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
	
	return 0;
}

int MyContainer::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	brush_hollow_ = AtlGetStockBrush(HOLLOW_BRUSH);
	brush_white_ = AtlGetStockBrush(WHITE_BRUSH);
	brush_red_.CreateSolidBrush(RGB(255,0,0));

	return 0;
}

CView.h

// View.h : interface of the CView class
//
/////////////////////////////////////////////////////////////////////////////

#pragma once

#include <utility>
#include <string>
#include <functional>
#include <atlmisc.h>
#include <atlctrls.h>
#include <GdiPlus.h>
#include "my_container.h"

class CView : public CWindowImpl<CView>
{
public:
	DECLARE_WND_CLASS(NULL)

	BOOL PreTranslateMessage(MSG* pMsg);

	BEGIN_MSG_MAP_EX(CView)
		MSG_WM_CREATE(OnCreate)
		MESSAGE_HANDLER(WM_PAINT, OnPaint)
		MSG_WM_SETFONT(OnSetFont)
		MSG_WM_GETFONT(OnGetFont);
		REFLECT_NOTIFICATIONS()
	END_MSG_MAP()

	int OnCreate(LPCREATESTRUCT lpCreateStruct);
	LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
	
private:
	std::wstring GetControlText(HWND hwnd,wchar_t* buf = NULL);
	void OnSetFont(CFontHandle font, BOOL bRedraw);
	HFONT OnGetFont();

	MyContainer container_;
	CFont font_normal_;

	CBrushHandle brush_white_;
	CBrushHandle brush_hollow_;
	CBrush brush_red_;

public:
};

CView.cpp

// View.cpp : implementation of the CView class
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h"
#include <utility>
#include <assert.h>

#include "View.h"
#include <CommCtrl.h>
#include <string>
#include <regex>


BOOL CView::PreTranslateMessage(MSG* pMsg)
{
	return FALSE;
}

LRESULT CView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	CPaintDC dc(m_hWnd);
	CMemoryDC mdc(dc,dc.m_ps.rcPaint);

	CRect rect_client;
	GetClientRect(&rect_client);
	mdc.FillSolidRect(rect_client,RGB(255,255,255));
	
	auto font = GetFont();
	static const wchar_t* text = L"SetFont is not NULL";
	if(font){
		mdc.SelectFont(font);
		mdc.DrawText(text,wcslen(text),rect_client,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
	}
	return 0;
}

static HFONT GetFont(int pixel,bool bold,const wchar_t* font_name)
{
	LOGFONT lf; 
	memset(&lf, 0, sizeof(LOGFONT)); // zero out structure 
	lf.lfHeight = pixel; // request a 8-pixel-height font
	if(bold)
	{
		lf.lfWeight = FW_BOLD;  
	}
	lstrcpy(lf.lfFaceName, font_name); // request a face name "Arial"
	
	HFONT font = ::CreateFontIndirect(&lf);
	return font;
}


static std::wstring GetProductBinDir()
{
	static wchar_t szbuf[MAX_PATH];  
	GetModuleFileName(NULL,szbuf,MAX_PATH);  
    PathRemoveFileSpec(szbuf);
	int length = lstrlen(szbuf);
	szbuf[length] = L'\\';
	szbuf[length+1] = 0;
	return std::wstring(szbuf);
}

HFONT CView::OnGetFont()
{
	return font_normal_;
}

void CView::OnSetFont(CFontHandle font, BOOL bRedraw)
{
	font_normal_ = font;
}

int CView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	auto font = ::GetFont(20,false,L"Arial");
	SetFont(font);

	container_.Create(m_hWnd,CRect(CPoint(100,100),CSize(200,100)),L"MyContainer");
	container_.SetFont(font);

	brush_hollow_ = AtlGetStockBrush(HOLLOW_BRUSH);
	brush_white_ = AtlGetStockBrush(WHITE_BRUSH);
	brush_red_.CreateSolidBrush(RGB(255,0,0));

	return 0;
}

圖示

在這裏插入圖片描述

參考

  1. GetFont returns NULL after SetFont
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章