【问题标题】:Graphics drawing - manipulate drawn shape图形绘制 - 操纵绘制的形状
【发布时间】:2014-12-01 02:57:15
【问题描述】:

我正在使用 Graphics 对象在表单上绘制矩形或椭圆(取决于选择的内容)。有什么方法可以在绘制这些图形对象后对其进行操作?我的意思是调整大小、删除、拖动等操作。另外,值得一提的是,在同一个表单上可以绘制多个形状并且它们可以重叠。

绘图本身看起来像这样,由 ScrollableControl 的 OnPaint() 事件触发 - 只需将这些方法传递给 PaintEventArgs 的 Graphics 对象。

protected override void Fill(System.Drawing.Graphics g, Brush b)
{
    g.FillEllipse(b, m_topLeft.X, m_topLeft.Y, m_width, m_height);
}

protected override void Draw(System.Drawing.Graphics g, Pen p)
{
    g.DrawEllipse(p, m_topLeft.X, m_topLeft.Y, m_width, m_height);
}

我希望能够点击一个形状,选择如何处理它并采取相应的行动。 我在想也许我可以检查光标的位置是否在形状的范围内(m_topLeft、m_width 和 m_height 数据成员)并从那里开始。尽管它确实有效,但这并没有考虑到潜在的重叠。所选点可能属于两个(或更多)形状。

这是使用用户定义的参数绘制的两个重叠形状(一个矩形和一个椭圆)的示例:

【问题讨论】:

  • 这当然是可能的,但您必须从头开始编写所有代码。这不是一项微不足道的任务。首先开发一个类来表示形状,并为其提供一种使用拖动手柄在选定状态下绘制自身的方法。然后,您需要进行命中测试以查看光标是否在这些句柄上并采取相应措施。对于多个形状命中,您可以为用户提供一种通过按键选择下一个命中的方法?
  • 或者,您可能希望停止使用已弃用的 winform 并继续使用当前技术,请参阅 my example

标签: c# winforms graphics


【解决方案1】:

不,没有办法在屏幕上绘制对象后对其进行最小化。您需要做的是列出需要在屏幕上绘制的所有对象的列表,并且无论何时要添加、删除或操作该列表中的对象,您都需要重新绘制整个列表。您通常通过在控件上调用 Invalidate() 来执行此操作,这将调用 Draw 再次被调用,这通常会在 foreach 循环中迭代您要绘制的对象集合。

public YourControl : Control
{
    List<IDrawableObject> _itemsToDraw = new List<IDrawableObject>();

    protected override void Draw(System.Drawing.Graphics g, Pen p)
    {
        foreach(var item in _itemsToDraw)
        {
            item.Draw(g, p);
        }
    }

    protected override void OnMouseClick(MouseEventArgs e)
    {
         base.OnMouseClick(e);

         IDrawableObject clickedItem = _itemsToDraw.FirstOrDefault(x=> x.WasClicked(e.Location));

         if(clickedItem != null)
         {
             //Do something with the clicked item.
         }
    }
}

interface IDrawableObject
{
    void Draw(System.Drawing.Graphics g, Pen p);

    bool WasClicked(Point p)
}

private class Ellipse : IDrawableObject
{    
    Point m_topleft;
    int m_width;
    int m_height;

    //Snip stuff like constructors assigning the values to the private fields.

    public void Draw(System.Drawing.Graphics g, Pen p)
    {
        g.DrawEllipse(p, m_topLeft.X, m_topLeft.Y, m_width, m_height);
    }

    public bool WasClicked(Point p)
    {
         return p.X >= m_topLeft.X && p.X < m_topLeft.X + m_width 
             && p.Y >= m_topLeft.Y && p.Y < m_topLeft.Y + m_height;
    }
}

要查找单击了哪个控件,您可以创建一个类似 WasClicked 的方法,该方法在单击时获取鼠标的 XY 并返回 true 或 false。然后,您可以操作集合中从 WasClicked 函数返回 true 的对象。

【讨论】:

  • 我知道这一点,但是如何在该列表中选择一个我已经用来跟踪绘制的形状(而不是它们的图形表示)的形状?
  • 谢谢,我刚刚对我的代码做了完全相同的事情,它对矩形按预期工作,但对椭圆则不起作用,因为它们有“空白”点。我希望你明白我的意思。我能想到的唯一标准是用于绘制形状的颜色。
  • 我会问一个新问题,说明你做了什么以及得到了什么结果。
猜你喜欢
  • 2018-09-24
  • 1970-01-01
  • 1970-01-01
  • 2018-06-25
  • 2012-04-15
  • 2013-10-17
  • 2018-04-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多