gpt4 book ai didi

c# - WPF 可选曲线

转载 作者:行者123 更新时间:2023-11-30 18:21:28 27 4
gpt4 key购买 nike

我目前正在开发类似图形的编辑器应用程序。到目前为止,我得到了节点和连接显示,我可以移动它们等。我希望能够选择将一个节点连接到另一个节点(橙色节点)的曲线。

enter image description here

选择曲线本身并不是真正的问题,它只是有点棘手,因为它是一个相当薄的对象(原始笔画粗细为 2)。我不得不增加描边以使其更容易选择。我想保持笔触较小,因为我认为它看起来更好。我的想法是绘制两条曲线,其中一条具有高描边粗细但透明,最重要的是实际的彩色曲线。这将使我基本上可以容忍我需要点击实际曲线多近才能选择它。

现在曲线 (Connection) 是一个继承自 Shape 的类,为了拥有其中的两个,我将它们包装在一个自定义控件中。它成功了,我不喜欢它的事实是我必须将所有属性包装在可能的自定义形状上以便将数据传播到我的两个连接,例如我必须包装开始和结束点属性。我或许也可以通过绑定(bind)实现该目标,但这基本上是将问题从代码隐藏转移到 XAML。

是否有更好的方法来实现我想要做的事情?我不是 WPF 的专家,所以我可能忽略了一些简单的解决方案。对于此事的任何反馈将不胜感激。

M.

最佳答案

好吧,首先我认为你的方法是最简单的。但是你让我感兴趣,我已经探索了另一种选择元素的方法。当然,它可能需要大量工作来调整它,但也许会让您走上另一种方式。

我的想法是基于VisualTreeHelper.HitTest。它在您指定的点执行 HitTest 并返回在该点找到的依赖对象。所以我所做的是监听 MouseRightButtonDown 事件(在我的窗口示例中),并且从按下鼠标右键的点开始,我计算形成圆形网格的点网格。然后我对这些点中的每一个点进行 HitTest,如果我找到一个已知的命名路径,我就可以安全地选择它。

在这个(太长的)解释之后,这里有一个示例代码:

List<DependencyObject> hitResultsList = new List<DependencyObject>();
private void WrapPanel_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
Window wp = sender as Window;
// Retrieve the coordinate of the mouse position.
Point pt = e.GetPosition((UIElement)sender);

bool elementFound = false;
foreach (Point point in GetPointsInCircle(pt, 8, pt, new Point(2, 2)))
{
// Clear the contents of the list used for hit test results.
Debug.Print(point.ToString());
hitResultsList.Clear();
// Set up a callback to receive the hit test result enumeration.
VisualTreeHelper.HitTest(wp, null,
new HitTestResultCallback(MyHitTestResult),
new PointHitTestParameters(point));

// Perform actions on the hit test results list.
foreach (DependencyObject d in hitResultsList)
{
if (d is Path)
{
Path p = d as Path;
if (p.Name == "link1")
{
elementFound = true; //Here we found the Path with name link1, we could then select it
break;
}
}
}
if (elementFound) break;
}

}

我的 HitTest 结果:

// Return the result of the hit test to the callback.
public HitTestResultBehavior MyHitTestResult(HitTestResult result)
{
// Add the hit test result to the list that will be processed after the enumeration.
hitResultsList.Add(result.VisualHit);

// Set the behavior to return visuals at all z-order levels.
return HitTestResultBehavior.Continue;
}

GetPointsInCircle(获取点的圆形网格):

private static IEnumerable<Point> GetPointsInCircle(Point circleCenter, float radius, Point gridCenter, Point gridStep)
{
if (radius <= 0)
{
throw new ArgumentOutOfRangeException("radius", "Argument must be positive.");
}
if (gridStep.X <= 0 || gridStep.Y <= 0)
{
throw new ArgumentOutOfRangeException("gridStep", "Argument must contain positive components only.");
}

// Loop bounds for X dimension:
int i1 = (int)Math.Ceiling((circleCenter.X - gridCenter.X - radius) / gridStep.X);
int i2 = (int)Math.Floor((circleCenter.X - gridCenter.X + radius) / gridStep.X);

// Constant square of the radius:
float radius2 = radius * radius;

for (int i = i1; i <= i2; i++)
{
// X-coordinate for the points of the i-th circle segment:
double x = gridCenter.X + i * gridStep.X;

// Local radius of the circle segment (half-length of chord) calulated in 3 steps.
// Step 1. Offset of the (x, *) from the (circleCenter.x, *):
double localRadius = circleCenter.X - x;
// Step 2. Square of it:
localRadius *= localRadius;
// Step 3. Local radius of the circle segment:
localRadius = (float)Math.Sqrt(radius2 - localRadius);

// Loop bounds for Y dimension:
int j1 = (int)Math.Ceiling((circleCenter.Y - gridCenter.Y - localRadius) / gridStep.Y);
int j2 = (int)Math.Floor((circleCenter.Y - gridCenter.Y + localRadius) / gridStep.Y);

for (int j = j1; j <= j2; j++)
{
yield return new Point(x, gridCenter.Y + j * gridStep.Y);
}
}
}

引用资料:

HitTest on MSDN
Get all points on a uniform discrete grid inside a circle's radius (Adapted)

关于c# - WPF 可选曲线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35456987/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com