1. 程式人生 > >[ATL/WTL]_[Gdiplus]_[關於使用Gdiplus來繪製反鋸齒的圓角矩形]

[ATL/WTL]_[Gdiplus]_[關於使用Gdiplus來繪製反鋸齒的圓角矩形]

場景

  1. 在使用WTL或MFC開發自定義按鈕時, 往往美工設計的按鈕都時圓角矩形的. 用GDI的函式RoundRect函式可以簡便的繪製圓角矩形, 但是如果橢圓(ellipse)的寬高比較大的時候, 按鈕比較大. 這時候按鈕的圓角矩形看起來就是有鋸齒的(aliasing).

  2. GDI的函式裡, 沒有比較好的函式來實現抗鋸齒(antialias), 如果不想自己去解決鋸齒效果, 只能使用Gdiplus來解決.

說明

  1. Gdiplus沒有自己的RoundRect函式, 所以需要自己實現一個. 其實圓角就是直角座標系以橢圓形的圓心為原點分割4部分, 在4個角分別繪製橢圓的4個部分, 之後再由上下左右4條直線組成.

  2. 關鍵的函式還是graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);, 沒有這個, 繪製出來的圓角矩形和RoundRect是一樣的, 有鋸齒.

例子

圖示
在這裡插入圖片描述


// Create round rect path.
void CreateRoundRect(Gdiplus::GraphicsPath& m_pPath,
	Gdiplus::Rect rect, int cornerRadius)
{
	// https://docs.microsoft.com/en-us/windows/desktop/api/gdipluspath/nf-gdipluspath-graphicspath-addarc%28inreal_inreal_inreal_inreal_inreal_inreal%29
	m_pPath.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
	m_pPath.AddLine(rect.X + cornerRadius, rect.Y, rect.GetRight() - cornerRadius * 2, rect.Y);
	m_pPath.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
	m_pPath.AddLine(rect.GetRight(), rect.Y + cornerRadius * 2, rect.GetRight(), rect.Y + rect.Height - cornerRadius * 2);
	m_pPath.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
	m_pPath.AddLine(rect.GetRight() - cornerRadius * 2, rect.GetBottom(), rect.X + cornerRadius * 2, rect.GetBottom());
	m_pPath.AddArc(rect.X, rect.GetBottom() - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
	m_pPath.AddLine(rect.X, rect.GetBottom() - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2);
	m_pPath.CloseFigure();
}

void DrawRectangle(CDC& dc,Gdiplus::Graphics& graphics)
{
	// Gdi
	// https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-roundrect
	CRect rect(300,500,300+128,500+50);
	CPen pen_gdi;
	pen_gdi.CreatePen(PS_SOLID,2,RGB(255,0,0));
	dc.SelectPen(pen_gdi);
	CBrush brush_gdi;
	brush_gdi.CreateSolidBrush(RGB(0,0,0));
	dc.SelectBrush(brush_gdi);
	dc.RoundRect(rect,CPoint(8*2,8*2));

	// Gdiplus
	// https://docs.microsoft.com/en-us/windows/desktop/api/gdipluspath/nf-gdipluspath-graphicspath-addarc%28inreal_inreal_inreal_inreal_inreal_inreal%29
	Gdiplus::Rect rcShadow(300,400,128, 50);
	Gdiplus::GraphicsPath m_pPath;
	Gdiplus::Pen pen(Gdiplus::Color(255,0,0),2);
	CreateRoundRect(m_pPath,rcShadow, 8);
	Gdiplus::SolidBrush brShadow(Gdiplus::Color(0,0,0));

	graphics.FillPath(&brShadow,&m_pPath);
	auto status = graphics.DrawPath(&pen,&m_pPath);
}

LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	CPaintDC dc(m_hWnd);
	Gdiplus::Graphics graphics(dc);
	// 注意, 得新增這句實現繪製圖形時有反鋸齒效果. 不然用Gdiplus和Gdi都有鋸齒.
	graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
	DrawRectangle(dc,graphics);

	return 0;
}

參考

GraphicsPath::AddArc method
RoundRect function