我使用Embarcadero RAD Studio XE7创建了一个C ++图形应用程序,我试图使用GDI +和一些破折号模式属性来设置循环进度动画。
这个想法非常简单:通过配置一个模式,其中短划线足够长以填充圆的圆周,并且空白部分足够长以防止两个破折号在圆上一起可见,这是可能的显示循环进度,其中破折号偏移属性可用于显示当前进度位置。
但是,我无法通过GDI +实现目标,因为可以看到几个图形工件,而且我无法找到解决方案。我非常确定我使用的值是正确的,因为Direct2D处理的完全相同的绘图工作正常。
以下是显示问题的示例代码。一个圆圈用GDI +绘制,另一个圆圈用Direct2D绘制。对于2个圆圈,绘图配置完全相同。
// fill the background
TRect rect(0, 0, ClientWidth, ClientHeight);
Canvas->Brush->Color = clWhite;
Canvas->Brush->Style = bsSolid;
Canvas->FillRect(rect);
const float startY = 100.0f;
const float penWidth = 32.0f;
const float dashOffset = -559.0f + (float(tb1->Position) * 559.0f * 0.01f);
std::vector<float> dashPattern;
dashPattern.push_back(559.0f / penWidth);
dashPattern.push_back(559.0f / penWidth);
// --------------------------------- USING GDI+ --------------------------------------
// create a GDI+ path showing a circle
Gdiplus::GraphicsPath path;
path.StartFigure();
path.AddBezier(Gdiplus::PointF(99.99999, 11.05255 + startY),
Gdiplus::PointF(51.31296, 11.05255 + startY),
Gdiplus::PointF(11.05254, 51.31297 + startY),
Gdiplus::PointF(11.05254, 100 + startY));
path.AddBezier(Gdiplus::PointF(11.05254, 100 + startY),
Gdiplus::PointF(11.05254, 148.6871 + startY),
Gdiplus::PointF(51.31297, 188.9475 + startY),
Gdiplus::PointF(99.99999, 188.9475 + startY));
path.AddBezier(Gdiplus::PointF(99.99999, 188.9475 + startY),
Gdiplus::PointF(148.687, 188.9475 + startY),
Gdiplus::PointF(188.9474, 149.1552 + startY),
Gdiplus::PointF(188.9474, 100 + startY));
path.AddBezier(Gdiplus::PointF(188.9474, 100 + startY),
Gdiplus::PointF(188.9474, 50.84483 + startY),
Gdiplus::PointF(149.1552, 11.05255 + startY),
Gdiplus::PointF(99.99998, 11.05255 + startY));
path.CloseFigure();
// configure the GDI+ pen
Gdiplus::Pen pen(Gdiplus::Color(255, 0, 0, 0));
pen.SetWidth(penWidth);
pen.SetDashOffset(dashOffset / penWidth);
const Gdiplus::LineCap lineCapStart = Gdiplus::LineCapFlat;
const Gdiplus::LineCap lineCapEnd = Gdiplus::LineCapFlat;
const Gdiplus::DashCap dashCap = Gdiplus::DashCapFlat;
pen.SetLineCap(lineCapStart, lineCapEnd, dashCap);
const Gdiplus::LineJoin lineJoin = Gdiplus::LineJoinMiter;
pen.SetLineJoin(lineJoin);
pen.SetMiterLimit(4.0f);
// configure dash style to custom (meaning that dash pattern should be used)
pen.SetDashStyle(Gdiplus::DashStyleCustom);
// configure dash pattern
pen.SetDashPattern(&dashPattern[0], dashPattern.size());
// draw the path using GDI+
Gdiplus::Graphics graphics(Canvas->Handle);
graphics.DrawPath(&pen, &path);
// ------------------------------- USING DIRECT2D ------------------------------------
const float startX = 300.0f;
// get a Direct2D canvas
TRect canvasRect(0, 0, ClientWidth, ClientHeight);
TDirect2DCanvas* pCanvas = new TDirect2DCanvas(Canvas->Handle, canvasRect);
// begin draw
pCanvas->BeginDraw();
ID2D1Factory* pD2DFactory;
// get factory associated with canvas
pCanvas->RenderTarget->GetFactory(&pD2DFactory);
// create a Direct2D path showing a circle
ID2D1PathGeometry* pGeometry;
pD2DFactory->CreatePathGeometry(&pGeometry);
ID2D1GeometrySink* pSink;
pGeometry->Open(&pSink);
pSink->BeginFigure(D2D1::Point2F(99.99999 + startX, 11.05255 + startY), D2D1_FIGURE_BEGIN_FILLED);
pSink->AddBezier(D2D1::BezierSegment(D2D1::Point2F(51.31296 + startX, 11.05255 + startY),
D2D1::Point2F(11.05254 + startX, 51.31297 + startY),
D2D1::Point2F(11.05254 + startX, 100 + startY)));
pSink->AddBezier(D2D1::BezierSegment(D2D1::Point2F(11.05254 + startX, 148.6871 + startY),
D2D1::Point2F(51.31297 + startX, 188.9475 + startY),
D2D1::Point2F(99.99999 + startX, 188.9475 + startY)));
pSink->AddBezier(D2D1::BezierSegment(D2D1::Point2F(148.687 + startX, 188.9475 + startY),
D2D1::Point2F(188.9474 + startX, 149.1552 + startY),
D2D1::Point2F(188.9474 + startX, 100 + startY)));
pSink->AddBezier(D2D1::BezierSegment(D2D1::Point2F(188.9474 + startX, 50.84483 + startY),
D2D1::Point2F(149.1552 + startX, 11.05255 + startY),
D2D1::Point2F(99.99998 + startX, 11.05255 + startY)));
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
pSink->Close();
pSink->Release();
// configure the Direct2D stroke properties
::D2D1_STROKE_STYLE_PROPERTIES strokeProps;
strokeProps.startCap = D2D1_CAP_STYLE_FLAT;
strokeProps.endCap = D2D1_CAP_STYLE_FLAT;
strokeProps.dashCap = D2D1_CAP_STYLE_FLAT;
strokeProps.lineJoin = D2D1_LINE_JOIN_MITER;
strokeProps.miterLimit = 4.0f;
strokeProps.dashStyle = D2D1_DASH_STYLE_CUSTOM;
strokeProps.dashOffset = dashOffset / penWidth;
// get the stroke style to apply
ID2D1StrokeStyle* pStrokeStyle;
pD2DFactory->CreateStrokeStyle(strokeProps,
&dashPattern[0],
dashPattern.size(),
&pStrokeStyle);
::ID2D1SolidColorBrush* pSolidBrush;
::D2D1_COLOR_F color;
color.r = 0.0f;
color.g = 0.0f;
color.b = 0.0f;
color.a = 1.0f;
// create a solid color brush
pCanvas->RenderTarget->CreateSolidColorBrush(color, &pSolidBrush);
// draw the geometry
pCanvas->RenderTarget->DrawGeometry(pGeometry, pSolidBrush, penWidth, pStrokeStyle);
pCanvas->EndDraw();
delete pCanvas;
tb1-&gt; Position属性只是一个可在0到100之间移动的轨迹栏控制光标。
使用上面的代码,我注意到2绘图之间存在一些差异:
当tb1-> Position = 0时,GDI +圆圈是完全可见的,而Direct2D圆圈是不可见的(这是我想达到的正确效果)。
不幸的是,使用像Direct2D这样的其他库而不是GDI +对我来说不是一个选择。我的问题是:为什么当我用GDI +绘制虚线圆圈时会发生上述差异?我做错了什么,还是GDI +错误?
重要编辑:在上面的图像中,在Direct2D绘图上启用了抗锯齿功能,而在GDI +绘图中禁用了抗锯齿功能。 这不是问题。上面提到的问题是关于图形工件,例如段结尾的方向,它们在GDI +和Direct2D之间明显不同,或者在圆形满时出现的空白工件。 无论是否使用抗锯齿都会发生这些问题。