Правильно ли использовать GC.Collect (); GC.WaitForPendingFinalizers () ;?

Вот подходящий класс Line:

class Line
{
    public Color LineColor { get; set; }
    public float Linewidth { get; set; }
    public bool Selected { get; set; }
    public Point Start { get; set; }
    public Point End { get; set; }

    public Line(Color c, float w, Point s, Point e)
    { LineColor = c; Linewidth = w; Start = s; End = e;    }

    public void Draw(Graphics G)
    { using (Pen pen = new Pen(LineColor, Linewidth)) G.DrawLine(pen, Start, End); }

    public bool HitTest(Point Pt)
    {
        // test if we fall outside of the bounding box:
        if ((Pt.X < Start.X && Pt.X < End.X) || (Pt.X > Start.X && Pt.X > End.X) ||
            (Pt.Y < Start.Y && Pt.Y < End.Y) || (Pt.Y > Start.Y && Pt.Y > End.Y)) 
            return false;
        // now we calculate the distance:
        float dy = End.Y - Start.Y;
        float dx = End.X - Start.X;
        float Z = dy * Pt.X - dx * Pt.Y + Start.Y * End.X - Start.X * End.Y;
        float N = dy * dy + dx * dx;
        float dist = (float)( Math.Abs(Z) / Math.Sqrt(N));
        // done:
        return dist < Linewidth / 2f;
    }

}

Определите список строк, возможно, на уровне класса:

    List lines = new List();

Вот как вы можете инициализировать это несколько строк:

for (int i = 0; i < 20; i++) lines.Add(new Line(Color.Black, 4f, 
    new Point(R.Next(panel1.Width), R.Next(panel1.Height)), 
    new Point(R.Next(panel1.Width), R.Next(panel1.Height))));

Вот результат нажатия на переход:

Всякий раз, когда вы добавляете , измените или удалите строку, необходимую для того, чтобы Panel отразили новости, вызвав событие Paint:

panel1.Invalidate();

. Здесь Paint событие Panel:

private void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    foreach (Line L in lines) L.Draw(e.Graphics);
}

В событии MouseClick вы выполните тест:

private void panel1_MouseClick(object sender, MouseEventArgs e)
{
    foreach(Line L in lines) 
            L.LineColor = L.HitTest(e.Location) ?  Color.Red : Color.Black;
    panel1.Invalidate();
}

Чтобы избежать мерцания, не используйте базовый класс Panel, поскольку он не doublebuffered , Вместо этого используйте либо подкласс PictureBox, либо doublebuffered Panel:

class DrawPanel : Panel 
{     public DrawPanel ()   { DoubleBuffered = true; }   }

Примечания:

  • В WinForms нет такой вещи, как «Линия», только пикселей различных цветов. Поэтому, чтобы выбрать строку, вам нужно сохранить координаты двух конечных точек, а затем выяснить, попали ли вы при нажатии.
  • В приведенном выше примере показано, как это сделать в математике.
  • Вместо этого можно проверить каждую строку, нарисуя ее на растровое изображение и протестировать пиксель, щелкнув мышью. Но рисование этих растровых изображений должно было бы выполнять математику за кулисами, а также выделять пространство для растровых изображений, поэтому математика будет более эффективной ..
  • Да, класс Line выглядит немного длиннее для таких простая вещь asa line, но посмотрите, насколько короткими все коды событий теперь! Это потому, что ответственность - это место, где они принадлежат!
  • Также обратите внимание, что первое правило делать любой рисунок в WinForms: Никогда не кэшируйте или не храните объект Grahics. Фактически, вы никогда не должны использовать CreateGraphics в первую очередь, так как объект Graphics никогда не останется в области видимости, и создаваемая графика не будет сохраняться (т. Е. Выдержать последовательность с минимальным увеличением).
  • Также обратите внимание, как я передаю e.Graphics объект параметров события Paint в экземпляры Line, чтобы они могли нарисовать себя с помощью текущего объекта Graphics!
  • Чтобы выбрать более тонкий линии, это может помочь немного изменить проверку расстояния ..
  • Математика была взята непосредственно из Wikipedia .

30
задан TamaMcGlinn 23 April 2019 в 07:09
поделиться