Gerade flackert und kann nur eine Linie verschieben

sailer86

Grünschnabel
Hi,

ich habe folgendes Problem. Ich zeichne per Click auf einen Button eine Linie auf einem Panel. Diese Linie kann ich verschieben und in der Größe ändern. -> Was auch funktioniert. Doch leider flackert die Linie ziemlich stark, wenn ich die Maus bewege. Das Problem ist, wenn ich die Events nach dem zeichenvorgang wieder deaktiviere kann ich sie nicht mehr verschieben. Zudem habe ich das Problem, wenn ich eine Linie erstelle kann ich diese verschieben und in der größe ändern, wenn ich jedoch noch eine Linie erstelle kann ich die alte linie nicht mehr verschieben/größe ändern sondern nur noch die neue.


Code:
 public partial class Probe: Form
    {
        Line line;
        List <Line> list = new List<Line> ();
       
        public StartForm()
        {
            InitializeComponent();
        }

 private void zeichnen_Click(object sender, EventArgs e)
        {
            line= new Line(); 
            line.pStart = new Point(10, 10);
            line.pEnd = new Point(100, 100);
            this.panel.MouseDown += new System.Windows.Forms.MouseEventHandler(this.probe_MouseDown);
            this.panel.MouseMove += new System.Windows.Forms.MouseEventHandler(this.probe_MouseMove);
            this.panel.MouseUp += new System.Windows.Forms.MouseEventHandler(this.probe_MouseUp);
            this.panel.Paint += new PaintEventHandler(panel_Paint);   
        }

        void panel_Paint(object sender, PaintEventArgs e)
        {            
            base.OnPaint(e);
            list.Add(line);
            foreach (Line linie in list)
            {
                linie.Paint(e.Graphics);
            }
        }

        void probe_MouseUp(object sender, MouseEventArgs e)
        {
            list.Add(line);
            line.MouseUp(e);
            
        }

        void probe_MouseMove(object sender, MouseEventArgs e)
        {
            line.MouseMove(e);
            panel.Invalidate();
        }

        void probe_MouseDown(object sender, MouseEventArgs e)
        {
            line.MouseDown(e);            
        }

Meine Line Klasse sieht folgendermaßen aus:
Code:
 class Line
    {
        protected bool mouseDown;
        protected bool mouseDownStart;
        protected bool mouseDownEnd;
        protected bool mouseDownLine;

        protected float grabSize = 1.0f;
        protected float tolerance = 2;

        protected Point start;
        protected Point end;
        protected Point lastMousePosition;

        RectangleF grabPointStart = new RectangleF();
        RectangleF grabPointEnd = new RectangleF();
     
        protected Color lineColor = Color.Black;
        private Pen linePen;      

        public Line()
        {
            linePen = new Pen(lineColor, 2);                
        } 

        public virtual double Distance(PointF p)
        {
            double rReturnValue = 0;
            double rSx = 0;
            double rSy = 0;
            double rM1 = 0;
            double rM2 = 0;

            if (start.X == end.X)
            {
                rReturnValue = Math.Abs(start.X - p.X);
                return rReturnValue;
            }
            if (start.Y == end.Y)
            {
                rReturnValue = Math.Abs(start.Y - p.Y);
                return rReturnValue;
            }

            float rX = start.X - end.X;
            float rY = start.Y - end.Y;

            p.X = p.X - start.X;
            p.Y = p.Y - start.Y;

            rM1 = (double)rY / (double)rX;
            rM2 = 1 / rM1;

            rSx = (rM2 * p.X + p.Y) / (rM1 + rM2);
            rSy = (-rM2) * (rSx - p.X) + p.Y;

            return Math.Sqrt(((p.X - rSx) * (p.X - rSx)) + ((p.Y - rSy) * (p.Y - rSy)));
        }

        public virtual bool IsPointOnLine(Point p, float rTolerance)
        {
            if (p.X >= Math.Min(start.X, end.X) - rTolerance &&
                p.X <= Math.Max(start.X, end.X) + rTolerance &&
                p.Y >= Math.Min(start.Y, end.Y) - rTolerance &&
                p.Y <= Math.Max(start.Y, end.Y) + rTolerance)
            {
                if (Distance(p) <= rTolerance)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
 
        public virtual void MouseDown(MouseEventArgs e)
        {
            mouseDown = true;

            if (grabPointStart.Contains(e.Location))
            {
                mouseDownStart = true;
            }
            if (grabPointEnd.Contains(e.Location))
            {
                mouseDownEnd = true;
            }
            if (IsPointOnLine(e.Location, tolerance))
            {
                mouseDownLine = true;
            }
        }

        public virtual void MouseMove(MouseEventArgs e)
        {
                int deltaX = e.Location.X - lastMousePosition.X;
                int deltaY = e.Location.Y - lastMousePosition.Y;

                if (mouseDownLine && !mouseDownEnd && !mouseDownStart)
                {
                    // Move the whole line
                    Move(deltaX, deltaY);
                }
                if (mouseDownStart)
                {
                    // Move the start
                    start.X += deltaX;
                    start.Y += deltaY;
                }
                if (mouseDownEnd)
                {
                    // Move the end
                    end.X += deltaX;
                    end.Y += deltaY;
                }

                lastMousePosition = e.Location;           
        }
    
        public virtual void MouseUp(MouseEventArgs e)
        {
            mouseDown = false;
            mouseDownStart = false;
            mouseDownEnd = false;
            mouseDownLine = false;
        }
      
        public void Move(int iX, int iY)
        {
            start.X += iX;
            start.Y += iY;

            end.X += iX;
            end.Y += iY;
        }
    
        public virtual void Paint(Graphics graphic)
        {
            // Draw the line
            graphic.DrawLine(linePen, start, end);

            // Draw the grab points
            grabPointStart.X = start.X - grabSize;
            grabPointStart.Width = grabSize * 2;
            grabPointStart.Y = start.Y - grabSize;
            grabPointStart.Height = grabSize * 2;

            grabPointEnd.X = end.X - grabSize;
            grabPointEnd.Width = grabSize * 2;
            grabPointEnd.Y = end.Y - grabSize;
            grabPointEnd.Height = grabSize * 2;

            graphic.FillRectangle(Brushes.Black, grabPointStart);
            graphic.FillRectangle(Brushes.Black, grabPointEnd);
        }
              
        public Point pStart
        {
            get
            {
                return start;
            }
            set
            {
                start = value;
            }
        }

        public Point pEnd
        {
            get
            {
                return end;
            }
            set
            {
                end = value;
            }
        }


        public Color pLineColor
        {
            get
            {
                return lineColor;
            }
            set
            {
                lineColor = value;
                if (linePen != null)
                    linePen.Dispose();
                linePen = new Pen(lineColor);
            }
        }
    }

Kann mir jemand sagen, was ich tun muss damit dieses geflackere aufhört? Ich hatte es schon mit "this.DoubleBuffered = true;" versucht aber das funkt nicht. Kann mir jemand auch noch einen Tip geben was ich tun muss das ich alle Linien verschieben kann.

LG
sailer
 
Wendest du das this.DoubleBuffered = true; denn auf das Panel oder auf die Form an? Soweit ich weiß, muss man das direkt bei der Form machen, dann muss das Geflackere aber weg sein...

Dass du immer nur die letzte Linie verschieben kannst, wundert mich nicht. Du benutzt im Code immer "line", das immer nur die letzte erzeugte Linie darstellt. Du müsstest alle Elemente in dieser List<Line> durchgehen, und schauen, welche verschoben werden soll...
 
Zuletzt bearbeitet:
Ich würde das MouseMove Ereignis erst feuern wenn wirklich eine Linien verschoben werden soll.
Glaube zur Zeit zeichnest du immer neu wenn sich die Maus über einer Linie bewegt.

Ich weiß nicht wieviele Linien du zeichnest.
Aber vielleicht solltest du direkt fest auf ein Image Objekt zeichnen.
Bis auf die zu ziehende Linie und diese im Paint Ereignis zeichnen.
Wenn die Linie nicht mehr gezogen wird diese wieder fest aufs Image zeichnen.

Das Graphics Objekt hat auch eine Eigenschaft VisibleRectangle (oder so).
Damit könntest du auch prüfen ob es überhaupt sinnvoll ist diese Linie jetzt zu zeichnen.
(Könnte ja auch sein das sie sich nicht im sichtbaren Bereich befindet)

Und ev. die Linie über Graphics Path einmal zeichnen lassen. Dort kannst du ja als Enum mit angegeben was ist Start und Endpunkt meienr Linie. Übergibst ein Array deiner Linien positionen. Und .Net zeichnet alles in einem Rutsch.
Nach meinen bisherigen Erfahrungen wäre das auch die performateste Lösung.

Nachtrag:
Vielleicht hilft dir das bissel weiter
http://www.tutorials.de/forum/net-g...-c-picturebox-malen-hnlich-wie-bei-paint.html
 
Zuletzt bearbeitet:
Zurück