[ATL/WTL]_[Gdiplus]_[關於使用Graphics::DrawString替換DrawText的說明]
阿新 • • 發佈:2018-12-01
場景
-
在開發
WTL
或MFC
程式時, 繪製文字往往會使用標準的CDC::DrawText
函式, 其實也就是呼叫了GDI
的DrawText
函式, 但是這個函式繪製出來的文字顯示出來的效果會比記事本顯示的效果差?什麼原因呢. -
GDI
在繪製文字, 線條時總是感覺比較粗糙, 邊緣總是有鋸齒, 不夠平滑.
說明
-
因為
GDI
繪製圖形時並沒有消除鋸齒的效果, 繪製出來的文字線條邊緣是不平滑的, 這種情況如果在解析度不高時沒問題, 但是如果螢幕解析度高了, 就很明顯看出來一個字元各個部分粗細不一. 自從Gdiplus
出來之後, 為了介面顯示更美觀, 直接切換使用Gdiplus
Graphics
來繪製是最好的, 不止線條還有圖形. -
Graphics
設定文字質量等級的方法SetTextRenderingHint
, 用來設定是否具備AntiAlias
(抗鋸齒). 注意Hinting
意思是微調, 指示Gdiplus
會根據繪製區域和繪製文字的大小, 位置進行微調, 比如字型的寬度, 字元間距等.
使用這種效果可能會導致字型變形.TextRenderingHintClearTypeGridFit
對於大部分LCD
顯示器提供最好的顯示質量, 但是它只適用在小字號的字型上. 如果使用大字號並不合適.TextRenderingHintAntiAlias
對於旋轉字型提供最好的質量, 無關大小號字型. 當然這個屬性也會耗費最多的效能.TextRenderingHintSystemDefault
TextRenderingHintAntiAlias
是一樣的效果.
enum TextRenderingHint { TextRenderingHintSystemDefault = 0, // Glyph with system default rendering hint TextRenderingHintSingleBitPerPixelGridFit, // Glyph bitmap with hinting TextRenderingHintSingleBitPerPixel, // Glyph bitmap without hinting TextRenderingHintAntiAliasGridFit, // Glyph anti-alias bitmap with hinting TextRenderingHintAntiAlias, // Glyph anti-alias bitmap without hinting TextRenderingHintClearTypeGridFit // Glyph CT bitmap with hinting };
例子
- 以下例子說明了
DrawText
使用的兩種情形, 使用Graphics::DrawString
都可以替換, 而且繪製質量更高.
圖示
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;
}
LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CPaintDC dc(m_hWnd);
//auto font = GetFont(16,true,L"Arial");
//dc.SelectFont(font);
// Gdi
std::wstring str_connect_via_usb_(L"Connect via USB");
CSize size;
dc.GetTextExtent(str_connect_via_usb_.c_str(),str_connect_via_usb_.size(),&size);
CRect rect_str;
rect_str.left = 0;
rect_str.right = size.cx;
rect_str.top = 0;
rect_str.bottom = size.cy;
dc.DrawText(str_connect_via_usb_.c_str(),str_connect_via_usb_.size(),&rect_str, DT_LEFT);
// Gdiplus
Gdiplus::Graphics graphics(dc);
Gdiplus::FontFamily fontFamily(L"Arial");
Gdiplus::Font font_normal_bold_(&fontFamily,16,Gdiplus::FontStyleBold,Gdiplus::UnitPixel);
Gdiplus::RectF rect_connect_via_usb_;
graphics.MeasureString(str_connect_via_usb_.c_str(),str_connect_via_usb_.size(),&font_normal_bold_,
Gdiplus::PointF(0,0),&rect_connect_via_usb_);
rect_connect_via_usb_.Y = rect_str.bottom+10;
Gdiplus::StringFormat stringFormat;
stringFormat.SetAlignment(Gdiplus::StringAlignmentNear);
// https://docs.microsoft.com/en-us/windows/desktop/api/gdiplusstringformat/nf-gdiplusstringformat-stringformat-generictypographic
const Gdiplus::StringFormat* pStringFormat = Gdiplus::StringFormat::GenericTypographic();
graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintSystemDefault);
graphics.DrawString(str_connect_via_usb_.c_str(),str_connect_via_usb_.size(),
&font_normal_bold_,rect_connect_via_usb_,pStringFormat,
&Gdiplus::SolidBrush(Gdiplus::Color(0,0,0)));
// Gdi
std::wstring str_desc(L"Language ID is set to neutral language, which means that the current language associated with the calling thread is used.");
CRect rect_desc;
rect_desc.top = rect_connect_via_usb_.Y+rect_connect_via_usb_.Height+10;
rect_desc.right = 300;
int height = dc.DrawText(str_desc.c_str(),str_desc.size(), &rect_desc,
DT_TOP| DT_WORDBREAK|DT_EDITCONTROL | DT_LEFT | DT_NOPREFIX|DT_CALCRECT);
dc.DrawText(str_desc.c_str(),str_desc.size(), &rect_desc,
DT_TOP| DT_WORDBREAK|DT_EDITCONTROL | DT_LEFT | DT_NOPREFIX);
// Gdiplus
Gdiplus::RectF rectf_desc;
Gdiplus::RectF rectf_desc_temp;
rectf_desc_temp.Width = 300;
graphics.MeasureString(str_desc.c_str(),str_desc.size(),&font_normal_bold_,
rectf_desc_temp,&rectf_desc);
rectf_desc.Y = rect_desc.bottom+10;
graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
graphics.DrawString(str_desc.c_str(),str_desc.size(),
&font_normal_bold_,rectf_desc,pStringFormat,
&Gdiplus::SolidBrush(Gdiplus::Color(0,0,0)));
auto desktopDc = ::GetDC(NULL);
auto horizontalDPI = GetDeviceCaps(desktopDc,LOGPIXELSX);
auto verticalDPI = GetDeviceCaps(desktopDc,LOGPIXELSY);
return 0;
}