来自 .NET 的 CustomLineCap 构造函数的 NotImplementedException

发布于 2024-09-13 03:23:20 字数 621 浏览 10 评论 0原文

我想画一个自定义线帽 - 一个半径为 r 的等边三角形。显然我不能:

  Dim triangleSide As Single = CSng(3 * r / Math.Sqrt(3))
  Dim triangleHeight As Single = CSng(3 * r / 2)
  path = New GraphicsPath()
  Dim points() As PointF = New PointF() { _ 
      New PointF(-triangleSide / 2, 0), _ 
      New PointF(triangleSide / 2, 0), _
      New PointF(0, triangleHeight) }
  path.AddLines(points)

  ' Not Implemented Exception, Was is Das? '
  _HlpCap = New CustomLineCap(path, Nothing) 

是我做错了什么还是这只是一个框架错误?

编辑:

在 Mark Cidade 评论之后,我尝试使用 (Nothing, path) 并且它有所帮助,但我需要填充三角形,而不仅仅是将其描边......

I want to draw a custom line cap - a equilateral triangle with the radius r. Apparently I can't:

  Dim triangleSide As Single = CSng(3 * r / Math.Sqrt(3))
  Dim triangleHeight As Single = CSng(3 * r / 2)
  path = New GraphicsPath()
  Dim points() As PointF = New PointF() { _ 
      New PointF(-triangleSide / 2, 0), _ 
      New PointF(triangleSide / 2, 0), _
      New PointF(0, triangleHeight) }
  path.AddLines(points)

  ' Not Implemented Exception, Was is Das? '
  _HlpCap = New CustomLineCap(path, Nothing) 

Do I something wrong or it's just a framework bug?

EDIT:

After Mark Cidade remark, I tried using (Nothing, path) and it helped, but I need to fill in the triangle, not only to stroke it out...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

烟花肆意 2024-09-20 03:23:20

该异常来自 GDI+ 库从其 GdipCreateCustomLineCap() 函数返回 NotImplemented 状态。尝试传递笔划路径而不是 Nothing

  Dim path2 As GraphicsPath = New GraphicsPath()
  path2.AddLines(points);
  _HlpCap = New CustomLineCap(path, path2) 

The exception comes from the GDI+ library returning a NotImplemented status from its GdipCreateCustomLineCap() function. Try passing a stroke path instead of Nothing:

  Dim path2 As GraphicsPath = New GraphicsPath()
  path2.AddLines(points);
  _HlpCap = New CustomLineCap(path, path2) 
梨涡少年 2024-09-20 03:23:20

显然,路径不能穿过 x 轴。我使用此代码创建了箭头帽:

  GraphicsPath capPath = new GraphicsPath();
  float arrowSize = 2.0f;
  capPath.AddLines(new PointF[] {
    new PointF(arrowSize, -(float)Math.Sqrt(3.0) * arrowSize),
    new PointF(0.0f, -0.01f),
    new PointF(-arrowSize, -(float)Math.Sqrt(3.0) * arrowSize)
  });

  CustomLineCap arrowCap = new CustomLineCap(capPath, null, LineCap.NoAnchor, (float)Math.Sqrt(3.0) * arrowSize);

Apparently, the path cannot cross the x-axis. I used this code to create an arrow cap:

  GraphicsPath capPath = new GraphicsPath();
  float arrowSize = 2.0f;
  capPath.AddLines(new PointF[] {
    new PointF(arrowSize, -(float)Math.Sqrt(3.0) * arrowSize),
    new PointF(0.0f, -0.01f),
    new PointF(-arrowSize, -(float)Math.Sqrt(3.0) * arrowSize)
  });

  CustomLineCap arrowCap = new CustomLineCap(capPath, null, LineCap.NoAnchor, (float)Math.Sqrt(3.0) * arrowSize);
浸婚纱 2024-09-20 03:23:20

错误

下面是一个 GraphicsPath 的示例,它尝试在行尾之外绘制箭头并导致 System.NotImplementedException

GraphicsPath capPath = new GraphicsPath();
capPath.AddLine(0, 8, -5, 0);
capPath.AddLine(-5, 0, 5, 0);
arrowPen.CustomEndCap = new CustomLineCap(capPath, null); // System.NotImplementedException

此操作会失败,因为路径必须与负 Y 轴相交。但上面的路径只经过原点,实际上并没有到达负 Y 轴。

中的注释这些文档至关重要:

fillPathStrokePath 参数不能同时使用。必须向一个参数传递一个空值。如果两个参数都未传递空值,则将忽略 fillPath。如果 strokePathnull,则 fillPath 应截取负 y 轴。

这是措辞不佳的情况之一。文档说“应该拦截”,但我认为它“必须拦截”,否则你会得到一个System.NotImplementedException.此拦截问题仅适用于 fillPath,而不适用于 strokePath。 (文档也可能使用一些图片。)

这是一个 GraphicsPath 的示例,它在线的末尾绘制一个箭头并且工作正常。无论如何,这可能是大多数人想要绘制的箭头。

输入图片此处描述

GraphicsPath capPath = new GraphicsPath();
capPath.AddLine(0, 0, -5, -8);
capPath.AddLine(-5, -8, 5, -8);
arrowPen.CustomEndCap = new CustomLineCap(capPath, null); // OK

修复您的示例

修复方法是从 y 中减去 triangleHeight。这会将箭头的尖端放置在 0,0(这是线末端的坐标),这可能正是您想要的,并将三角形的底边放置在 -triangleHeight 处。

float radius = 5.0f;
float triangleSide = 3.0f * radius / (float)Math.Sqrt(3.0f);
float triangleHeight = 3.0f * radius / 2.0f;
GraphicsPath capPath = new GraphicsPath();
capPath.AddLines(new PointF[] {
    new PointF(-triangleSide / 2.0f, -triangleHeight),
    new PointF(triangleSide / 2.0f, -triangleHeight),
    new PointF(0, 0) }
);
arrowPen.CustomEndCap = new CustomLineCap(capPath, null);

为您提供的确切修复(在 Visual Basic 中):

  Dim points() As PointF = New PointF() { _ 
      New PointF(-triangleSide / 2, -triangleHeight), _ 
      New PointF(triangleSide / 2, -triangleHeight), _
      New PointF(0, 0) }
  path.AddLines(points)

Bad

Here's an example of a GraphicsPath that tries to draw an arrow head beyond the end of the line and causes a System.NotImplementedException.

GraphicsPath capPath = new GraphicsPath();
capPath.AddLine(0, 8, -5, 0);
capPath.AddLine(-5, 0, 5, 0);
arrowPen.CustomEndCap = new CustomLineCap(capPath, null); // System.NotImplementedException

This fails because the path must intercept the negative Y-axis. But the path above only passes through the origin and doesn't actually hit the negative Y-axis.

The remarks in the docs are crucially important:

The fillPath and strokePath parameters cannot be used at the same time. One parameter must be passed a null value. If neither parameter is passed a null value, fillPath will be ignored. If strokePath is null, fillPath should intercept the negative y-axis.

This is one of those cases where the wording is poor. The docs say "should intercept" but I think it's the case that it "must intercept" or else you're going to get a System.NotImplementedException. This intercept issue applies only to a fillPath, and not a strokePath. (The documentation could probably use some pictures too.)

Good

Here's an example of a GraphicsPath that draws an arrow head at the end of the line and works correctly. And it's likely the kind of arrow head that most people want to draw anyway.

enter image description here

GraphicsPath capPath = new GraphicsPath();
capPath.AddLine(0, 0, -5, -8);
capPath.AddLine(-5, -8, 5, -8);
arrowPen.CustomEndCap = new CustomLineCap(capPath, null); // OK

Fixing Your Example

A fix is to just subtract the triangleHeight from y. This places the tip of the arrow at 0,0 (which are the coordinates of the end of the line) which is likely what you intended anyway, and puts the base of the triangle at -triangleHeight.

float radius = 5.0f;
float triangleSide = 3.0f * radius / (float)Math.Sqrt(3.0f);
float triangleHeight = 3.0f * radius / 2.0f;
GraphicsPath capPath = new GraphicsPath();
capPath.AddLines(new PointF[] {
    new PointF(-triangleSide / 2.0f, -triangleHeight),
    new PointF(triangleSide / 2.0f, -triangleHeight),
    new PointF(0, 0) }
);
arrowPen.CustomEndCap = new CustomLineCap(capPath, null);

The exact fix for you (in Visual Basic):

  Dim points() As PointF = New PointF() { _ 
      New PointF(-triangleSide / 2, -triangleHeight), _ 
      New PointF(triangleSide / 2, -triangleHeight), _
      New PointF(0, 0) }
  path.AddLines(points)
倾城月光淡如水﹏ 2024-09-20 03:23:20

就我而言,我根据容器的宽度设置了盖子各段的长度。每当我将表单缩小到超过一定限制时,我的程序总是会因异常而停止。
然后我发现当任何段的长度达到1时就会抛出异常。
因此,请确保 cap 路径中的所有段的长度都大于 1。

In my case, I had made the lenght of the cap's segments dependant on the conteiner's width. My program always stopped with an exception whenever I shrinked the form past a certain limit.
Then I discovered that the exception was thrown when any segment's length reached 1.
So, make sure that all the segments in your cap path have a length greater than 1.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文