栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

[ATL/WTL]

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

[ATL/WTL]

场景
  1. 有一次开发WTL窗口时,使用GDI的CMemoryDC来绘制中文文字显示不出来,但是文字改为英文就绘制出来的,确认字符集,字体,坐标都没问题,那是什么情况?
说明
  1. 在开发WTL程序时, 我们有时候会容易混合使用GDI和GDI+,比如使用GDI的CDC的方法RoundRect绘制圆角矩形,而GDI+没有类似的方法。同样,使用GDI+轻松绘制png图片,而GDI绘制需要繁琐的转换。但是,实际上,微软MSDN文档说明GDI和GDI+是不能混用的,上边的绘制不出来中文就是混用导致的结果之一。

  2. 微软的文档说明 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。
例子
  1. 以下例子说明如何使用GDI和GDI+混用的方式,它是微软官方说明的第三种情况,也有3种用法。
View.h
// View.h : interface of the CView class
//
/

#pragma once

#include 
#include 

class CView : public CWindowImpl
{
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 , WPARAM , LPARAM , BOOL& );
	int OnCreate(LPCREATESTRUCT lpCreateStruct);
	void PaintImage(CDC& cdc,CRect& rect);
	void OnDestroy();

private:
	Gdiplus::Font* font_;
	HFONT font_normal_;
	Gdiplus::Bitmap* bitmap_;
};

View.cpp
// 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 , WPARAM , LPARAM , BOOL& )
{
	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;
}

截图

下载地址

项目代码

参考
  1. 中文有些翻译的不正确,可以结合英文看。比如这句
如果在 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+

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/909165.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号