[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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章