場景
- 在
WTL
開發時,我們開發自定義的窗口類,繼承自CWindowImpl
,而這個類自帶有SetFont
和GetFont
方法. 問題是調用了這個SetFont
方法,之後在調用GetFont
方法返回的HFONT
是NULL
, 怎麼回事?
說明
-
在
CWindowImpl
類裏,SetFont
方法實際上就是發送了WM_SETFONT消息. 而WM_SETFONT的API
並沒有說明提示設置字體不生效的情況。事實上,查閱網上的資料,對於自定義的控件(即內部是自定義WNDCLASS),不是系統自帶的默認控件,系統不會處理WM_SETFONT
和WM_GETFONT
消息,需要自己處理這兩個消息,也就是說並沒有一個句柄HFONT
變量存儲設置的值。 -
在自定義的控件裏,我們可以在消息映射裏處理這兩個消息, 還需要添加一個
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;
}
例子
-
my_container.h 只是用來測試自定義窗口默認的
SetFont
無效的窗口類. -
CView.h 是增加了處理
WM_SETFONT
和WM_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;
}