WTL
窗口时,使用GDI
的CMemoryDC
来绘制中文文字显示不出来,但是文字改为英文就绘制出来的,确认字符集,字体,坐标都没问题,那是什么情况?在开发WTL
程序时, 我们有时候会容易混合使用GDI
和GDI+
,比如使用GDI
的CDC
的方法RoundRect
绘制圆角矩形,而GDI+
没有类似的方法。同样,使用GDI+
轻松绘制png
图片,而GDI
绘制需要繁琐的转换。但是,实际上,微软MSDN
文档说明GDI
和GDI+
是不能混用的,上边的绘制不出来中文就是混用导致的结果之一。
微软的文档说明 GDI 和 GDI + 之间的互操作性 介绍了4种需要互操作性的情况,我们最常用的就是第三种情况在 GDI HDC 上使用 GDI +
. 也就是说在创建Gdiplus::Graphics(HDC)
之后如果需要使用HDC
,那么有两种方式:
2.1. 请先销毁Graphics
再使用HDC
.
2.2. 使用Graphics.GetHDC()
来创建新的HDC
,之后直到调用Graphics.ReleaseHDC()
之前不要使用Graphics
对象.
您可以通过使用采用 HDC 作为参数的图形构造函数来协助在 HDC 上使用 GDI +。 可以使用此方法在 HDC 上绘制 Graphics 类的绘图成员。 将 Graphics 对象附加到 HDC 后,不应在 HDC 上执行任何 GDI 操作,直到 Graphics 对象损坏或超出范围。 如果在 HDC 上需要 GDI 输出,请先销毁 Graphics 对象,然后再使用原始 HDC 或使用 Graphics::GetHDC() 获取新的 hdc,然后按照本文前面所述的规则进行互操作,同时对 GDI + 对象使用 gdi。
GDI
和GDI+
混用的方式,它是微软官方说明的第三种情况,也有3种用法。// View.h : interface of the CView class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
#include
#include
class CView : public CWindowImpl<CView>
{
public:
DECLARE_WND_CLASS(NULL)
BOOL PreTranslateMessage(MSG* pMsg);
BEGIN_MSG_MAP_EX(CView)
MSG_WM_CREATE(OnCreate)
MSG_WM_DESTROY(OnDestroy)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
END_MSG_MAP()
LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
int OnCreate(LPCREATESTRUCT lpCreateStruct);
void PaintImage(CDC& cdc,CRect& rect);
void OnDestroy();
private:
Gdiplus::Font* font_;
HFONT font_normal_;
Gdiplus::Bitmap* bitmap_;
};
// View.cpp : implementation of the CView class
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "resource.h"
#include
#include
#include
#include "View.h"
using namespace std;
using namespace Gdiplus;
static HFONT GetHFONT(int em,int charset = DEFAULT_CHARSET,
bool bold = false,const wchar_t* fontName = L"Arial")
{
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT)); // zero out structure
lf.lfHeight = em; // request a 8-pixel-height font
lf.lfCharSet = charset;
lstrcpy(lf.lfFaceName,fontName); // request a face name "Arial"
if(bold)
lf.lfWeight = FW_BOLD;
else
lf.lfWeight = FW_NORMAL;
HFONT font = ::CreateFontIndirect(&lf);
return font;
}
static Gdiplus::Font* GetGDIFont(HDC hdc,int em,int charset = DEFAULT_CHARSET,
bool bold = false,const wchar_t* fontName = L"Arial")
{
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT)); // zero out structure
lf.lfHeight = em; // request a 8-pixel-height font
lf.lfCharSet = charset;
lstrcpy(lf.lfFaceName,fontName); // request a face name "Arial"
if(bold)
lf.lfWeight = FW_BOLD;
else
lf.lfWeight = FW_NORMAL;
return new Gdiplus::Font(hdc,&lf);
}
int CView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
auto one = GetDC();
font_ = GetGDIFont(one,16);
ReleaseDC(one);
font_normal_= GetHFONT(16);
bitmap_ = new Bitmap(L"res\\toolbar.bmp");
return 0;
}
BOOL CView::PreTranslateMessage(MSG* pMsg)
{
pMsg;
return FALSE;
}
void CView::PaintImage(CDC& cdc,CRect& rect)
{
static std::wstring title(L"学院课程: C++17语言特性和标准库-第一部");
static std::wstring url(L"https://edu.csdn.net/course/detail/30136");
CSize size;
cdc.GetTextExtent(title.c_str(),title.size(),&size);
CRect rectText(CPoint(100,130),size);
cdc.DrawText(title.c_str(),title.size(),rectText,DT_LEFT);
// 2. 可以用大括号进行包括graphics进行绘制,当语句块结束时,graphics会销毁.
// 接着再使用原HDC.
{
Gdiplus::Graphics graphics(cdc);
graphics.DrawImage(bitmap_,100,180);
// 混淆GDI+和GDI方式3
// 如果需要使用HDC,通过GetHDC()方法来锁定graphics,之后再通过方法ReleaseHDC释放锁定graphics.
auto hdc = graphics.GetHDC();
CDCHandle dc(hdc);
rectText.MoveToY(200);
dc.DrawText(title.c_str(),title.size(),rectText,DT_LEFT);
graphics.ReleaseHDC(hdc);
graphics.DrawImage(bitmap_,100,220);
}
cdc.GetTextExtent(url.c_str(),url.size(),&size);
rectText = CRect(CPoint(100,160),size);
cdc.DrawText(url.c_str(),url.size(),rectText,DT_LEFT);
}
void CView::OnDestroy()
{
delete font_;
DeleteObject(font_normal_);
}
// 第三种情况. hdc作为Graphics的参数传入,在Graphics销毁之前不要使用hdc.
LRESULT CView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CPaintDC dc(m_hWnd);
CMemoryDC mdc(dc,dc.m_ps.rcPaint);
mdc.SelectFont(font_normal_);
CRect rect;
GetClientRect(&rect);
mdc.FillSolidRect(rect,RGB(255,255,255));
static std::wstring temp(L"https://blog.csdn.net/infoworld");
// 混淆GDI+和GDI方式1.
PaintImage(mdc,rect);
// 混淆GDI+和GDI方式2,放到最后再使用graphics绘制.
Graphics graphics(mdc);
RectF rectf_text;
rectf_text.X = 100;
rectf_text.Y = 100;
graphics.MeasureString(temp.c_str(),temp.size(),font_,rectf_text,&rectf_text);
auto sf = StringFormat::GenericDefault();
Color color;
color.SetFromCOLORREF(RGB(0,0,0));
SolidBrush sb(color);
graphics.DrawString(temp.c_str(),temp.size(),font_,rectf_text,sf,&sb);
return 0;
}
项目代码
如果在 HDC 上需要 GDI 输出,请先销毁 Graphics 对象,然后再使用原始 HDC 或使用 Graphics::GetHDC() 获取新的 hdc...
原英文是:
If GDI output is required on the HDC, either destroy the Graphics object before using the original HDC or use Graphics::GetHDC() to get a new HDC...
应该是:
如果在 HDC 上需要 GDI 输出,请先销毁 Graphics 对象,然后再使用原始 HDC; 或者使用 Graphics::GetHDC() 获取新的 hdc...
GDI 和 GDI + 之间的互操作性
Interoperability between GDI and GDI+