Come trascinare e spostare le forms in C #

In un’applicazione C # WindoeForms, è ansible selezionare, quindi spostare o eliminare una forma tracciata con il mouse? Come il programma di pittura di Windows.

Il tracciamento della forma funziona perfettamente, tutti i punti sono memorizzati in alcuni array. Come questo esempio di disegno a tratteggio

Point Latest { get; set; } List _points = new List(); protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); // Save the mouse coordinates Latest = new Point(eX, eY); // Force to invalidate the form client area and immediately redraw itself. Refresh(); } protected override void OnPaint(PaintEventArgs e) { var g = e.Graphics; base.OnPaint(e); if (_points.Count > 0) { var pen = new Pen(Color.Navy); var pt = _points[0]; for(var i=1; _points.Count > i; i++) { var next = _points[i]; g.DrawLine(pen, pt, next); pt = next; } g.DrawLine(pen, pt, Latest); } } private void Form1_MouseClick(object sender, MouseEventArgs e) { Latest = new Point(eX, eY); _points.Add(Latest); Refresh(); } 

Posso lasciarlo calcolare la distanza più breve tra la posizione del mouse e ogni linea per l’algebra lineare di base e impostare una distanza di soglia, se è più breve della soglia, rendere questa linea selezionata e può essere trascinata o modificata con il mouse. Ma, mi chiedo, esiste un modo più gestibile per tale compito? Principalmente la parte di selezione. Ogni suggerimento sarà apprezzato, grazie!

Per colpire le forms di prova non hai bisogno dell’algebra lineare. È ansible creare GraphicsPath per le forms e quindi utilizzare il metodo GraphicsPath.IsOutlineVisible o il metodo GraphicsPath.IsOutlineVisible per eseguire hit-test.

  • Per verificare se un punto si trova nell’area del percorso, ad esempio una forma piena, utilizzare IsVisible .

  • Per IsOutlineVisible hit test per linee o curve o forms vuote, puoi utilizzare IsOutlineVisible .

Esempio

Ad esempio, è ansible creare un’interfaccia IShape base che contenga metodi per hit-testing, disegno e spostamento. Quindi nelle classi implementare questi metodi. Inoltre è ansible creare un controllo DrawingSurface grado di gestire gli hit-test, disegnare e spostare oggetti IShape .

Nell’esempio seguente, creiamo IShape interfacce IShape , Line e Circle . Inoltre creiamo un controllo DrawingSurface . Per testare l’esempio, è sufficiente inserire un controllo DrawingSurface su un Form e gestire l’evento Load del modulo e aggiungere alcune forms, quindi eseguire l’applicazione e provare a spostare le forms.

IShape

Questa interfaccia contiene alcuni metodi utili che, se una class li implementa, possono essere utilizzati per il disegno, il hit-testing e lo spostamento. Alla fine di questo esempio, puoi vedere un controllo DrawingSurface che può funzionare con IShape implementazioni di IShape semplicemente:

 public interface IShape { GraphicsPath GetPath(); bool HitTest(Point p); void Draw(Graphics g); void Move(Point d); } 

Linea

Ecco una class di linea che implementa IShape interfaccia IShape . Se esegui un hit-testing se fai clic sulla linea, HitTest restituisce true. Inoltre, per consentirti di scegliere la linea in modo più semplice, ho aggiunto 2 punti per hit-testing:

 public class Line : IShape { public Line() { LineWidth = 2; LineColor = Color.Black; } public int LineWidth { get; set; } public Color LineColor { get; set; } public Point Point1 { get; set; } public Point Point2 { get; set; } public GraphicsPath GetPath() { var path = new GraphicsPath(); path.AddLine(Point1, Point2); return path; } public bool HitTest(Point p) { var result = false; using (var path = GetPath()) using (var pen = new Pen(LineColor, LineWidth + 2)) result = path.IsOutlineVisible(p, pen); return result; } public void Draw(Graphics g) { using (var path = GetPath()) using (var pen = new Pen(LineColor, LineWidth)) g.DrawPath(pen, path); } public void Move(Point d) { Point1 = new Point(Point1.X + dX, Point1.Y + dY); Point2 = new Point(Point2.X + dX, Point2.Y + dY); } } 

Cerchio

Ecco una class circle che implementa IShape interfaccia IShape . Se esegui un hit-testing se fai clic in cerchio, HitTest restituisce true:

 public class Circle : IShape { public Circle() { FillColor = Color.Black; } public Color FillColor { get; set; } public Point Center { get; set; } public int Radious { get; set; } public GraphicsPath GetPath() { var path = new GraphicsPath(); var p = Center; p.Offset(-Radious, -Radious); path.AddEllipse(pX, pY, 2 * Radious, 2 * Radious); return path; } public bool HitTest(Point p) { var result = false; using (var path = GetPath()) result = path.IsVisible(p); return result; } public void Draw(Graphics g) { using (var path = GetPath()) using (var brush = new SolidBrush(FillColor)) g.FillPath(brush, path); } public void Move(Point d) { Center = new Point(Center.X + dX, Center.Y + dY); } } 

DrawingSurface

Il controllo, disegna un elenco di forms. Esegue anche hit-test in MouseDown e sposta la forma se la trascini. Dovresti aggiungere alcune forms come la raccolta Line o Circle a Shapes del controllo.

 public class DrawingSurface : Control { public List Shapes { get; private set; } IShape selectedShape; bool moving; Point previousPoint = Point.Empty; public DrawingSurface() { DoubleBuffered = true; Shapes = new List(); } protected override void OnMouseDown(MouseEventArgs e) { for (var i = Shapes.Count - 1; i >= 0; i--) if (Shapes[i].HitTest(e.Location)) { selectedShape = Shapes[i]; break; } if (selectedShape != null) { moving = true; previousPoint = e.Location; } base.OnMouseDown(e); } protected override void OnMouseMove(MouseEventArgs e) { if (moving) { var d = new Point(eX - previousPoint.X, eY - previousPoint.Y); selectedShape.Move(d); previousPoint = e.Location; this.Invalidate(); } base.OnMouseMove(e); } protected override void OnMouseUp(MouseEventArgs e) { if (moving) { selectedShape = null; moving = false; } base.OnMouseUp(e); } protected override void OnPaint(PaintEventArgs e) { e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; foreach (var shape in Shapes) shape.Draw(e.Graphics); } }