如何在WPF中绘制数字信号?

8
我需要在WPF中绘制数字信号,并能够移动线的每个部分。如下图所示,箭头指示了线的哪个部分可以移动。单击并拖动“可点击区域”将向左或向右移动整个正方形。
我想到了几种方法: 1. Polyline对象。但我无法控制线的每个部分。 2. 线条(Line)对象。每次更改时,所有线都应调整其位置。难以控制“可点击区域”。可能也很复杂。 3. Border对象。每个部分实际上都是一个边框,将显示/隐藏适当的边框侧面。我不确定如何轻松地移动边框的边缘。 4. 其他选项...
我的问题是,最正确的开始做的方式是什么?

1
我想我会从矩形开始,收集一组点来绘制GraphicsPath。这是我建议开始的地方。以前没有做过这样的事情。 - IAbstract
1
如果我是你,我会编辑你的问题,使其更加客观实用,除非你希望它因为“主要基于个人意见”而被关闭。 - Sheridan
@Sheridan,你有什么建议?"如何绘制数字化..."更好吗? - theateist
1
您可以创建一个混合对象,该对象由线条和一个可点击的矩形区域组成。 - yushulx
其实我正在考虑整个事情的一条路径——每个脉冲都将成为PathGeometry中的一个线段。(我不知道这有多可行,因为我的公司会阻止图片,所以我看不到你发布的图像。) - McGarnagle
显示剩余6条评论
2个回答

0

如果您愿意,我可以编写这个代码,但是以下是我的做法...

维护一个 pair< x_position, height > 的列表,并按 X 排序。在自定义控件中完成此操作。

使用 for 循环绘制它。通过查找列表来确定点击事件。处理一些鼠标拖动事件,更新屏幕。

for 循环将查看 mylist[i] 和 mylist[i+1]。使用该信息绘制矩形。

我通常不使用 WPF 进行编码,但如果您愿意,我可以在半小时内弄清楚它。

以下是一些代码............. 将代码添加到命名空间,构建,然后将组件添加到表单中:

 public class Pair
{
    public Pair()
    {
    }

    public Pair(float first, float second)
    {
        this.First = first;
        this.Second = second;
    }

    public float First { get; set; }
    public float Second { get; set; }
};

public class ImageButton :  FrameworkElement
{
    List<Pair> items;
    Boolean dragDown = false;
    bool dragVert = false;
    int dragSeg = -1;


    public ImageButton()  {
        items = new List<Pair>();
        items.Add(new Pair(0, 0));
        items.Add(new Pair(40, 40));
        items.Add(new Pair(60, 0));
        items.Add(new Pair(100, 20));
        items.Add(new Pair(115, 0));
        items.Add(new Pair(185, 20));
        items.Add(new Pair(215, 0));
        items.Add(new Pair(300, 0));

    }

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        int seg;
        bool vert;

        if (getSegment(e.GetPosition(this).X, e.GetPosition(this).Y, out seg, out vert))
        {
            dragDown = true;
            dragSeg = seg;
            dragVert = vert;
            //We are dragging now
        }

        base.OnMouseDown(e);
    }
    protected override void OnMouseUp(MouseButtonEventArgs e)
    {
        dragDown = false;
        base.OnMouseUp(e);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        double basey = RenderSize.Height - 10;

        int seg;
        bool vert;
        if (!dragDown)
        {

            if (getSegment(e.GetPosition(this).X, e.GetPosition(this).Y, out seg, out vert))
            {
                if (vert)
                {
                    Cursor = Cursors.SizeWE;
                }
                else
                {
                    Cursor = Cursors.SizeNS;
                };

            }
            else
            {
                Cursor = Cursors.No;
            }
        }
        else
        {
            //Must be dragging.
            if (dragVert)
            {
                //This will change the X position of the segment...........
                items[dragSeg].First = (int) e.GetPosition(this).X;
                InvalidateVisual();
            }
            else
            {
                items[dragSeg].Second = (int)(basey - ((int)e.GetPosition(this).Y));
                //Change vertical
                InvalidateVisual();
            }
        }
        base.OnMouseMove(e);
    }

    protected override void OnRender(DrawingContext dc)
    {
        Brush b = new SolidColorBrush(Color.FromRgb(40,40,40));
        dc.DrawRectangle(b, new Pen(b, 2), new Rect(0, 0, this.RenderSize.Width, RenderSize.Height));
        Pen p = new Pen(new SolidColorBrush(Color.FromRgb(240, 240, 240)), 2);
        double basey = RenderSize.Height - 10;
        for (int i = 0; i < items.Count-1; i++)
        {
            Brush br = new SolidColorBrush(Color.FromRgb(240, 40, 40));
            Rect t = new Rect(items[i].First,basey-items[i].Second, items[i+1].First-items[i].First,items[i].Second);
            dc.DrawRectangle(br, p, t);
        }
    }
    /// <summary>
    /// Returns if over a segment, and how.  
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    bool getSegment(double x, double y, out int index, out bool vert)
    {
        double basey = RenderSize.Height - 10;
        index = 0;
        vert = false;

        for (int i = 0; i < items.Count - 1; i++)
        {
            //Check for vertical section going up
            if ((x >= (items[i].First - 3)) && ( x <= (items[i].First + 3))) {
                // x is hovering close to segment, check Y
                if ((y < (basey)) && (y>=(basey-items[i].Second))) {
                    index = i;
                    vert = true;
                    return true;
                }
            }

            //Check vertical going down.
            if ((x >= (items[i + 1].First - 3)) && (x <= (items[i + 1].First + 3)))
            {
                if ((y < (basey)) && (y >= (basey - items[i].Second)))
                {
                    index = i+1;
                    vert = true;
                    return true;
                }
            }

            //In the middle section
            if ((x >= (items[i].First) && (x <= (items[i+1].First)))) {
                //Check for close to line seg.
                if ((y < (basey - items[i].Second + 3)) && (y > (basey - items[i].Second - 3)))
                {
                    index = i;
                    vert = false;
                    return true;
                }
            }

        }
        return false;
    }
}

当拖动片段时,请勿重叠它们 - 我没有为此编码。但这允许查看信号并移动信号。

Sample of provided component

通过鼠标调整大小后:

enter image description here

PS:我没有尝试优化或制作任何生产代码,只是为了您而匆忙完成。


0

需要考虑的几个事项...

  • Thumb 是一个很好的控件,可以从它开始拖动你的物品,因为它已经提供了适当的事件,你可以处理它们来移动它。通过模板化,你可以赋予它任何形状。

  • 通过巧妙地使用 Grid 和适当放置的网格分隔符,你可以免费获得可拖动的线条。如果这不起作用,那么 4 个矩形可能效果很好。将它们放在一个 DockingPanel 中,放置在顶部、左侧、右侧和最后一个填充位置,你就有足够的基本元素来响应所有所需的事件。


“Thumb” 真的很有用。谢谢! - theateist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接