Malprogramm



  • Das ist mein kleines Malprogramm. Wenn ich male, drücke ich die Maustaste und solange ich sie nicht wiederloslasse ensteht eine durchgezogene Linie.
    Wenn ich die maus an anderer Stelle wieder drücke wird komischweise eine Linie zum vorherlosgelassenen Punkt gezeichnet. Versteh das nicht.

    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
    
            List<int> mylist = new List<int>(); 
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Paint(object sender, PaintEventArgs e)
            {
                Graphics mygraf = e.Graphics;
                Pen mypen=new Pen(Color.Black);
    
                for(int i=3;i<this.mylist.Count;i+=2)
                {
    
                  mygraf.DrawLine(mypen, mylist[i-3], mylist[i -2], mylist[i -1], mylist[i ]);
    
                }
                mygraf.Dispose();
    
            }
    
            private void Form1_MouseDown(object sender, MouseEventArgs e)
            {
                this.mylist.Add(e.Location.X);
                this.mylist.Add(e.Location.Y);
    
            }
    
            private void Form1_MouseMove(object sender, MouseEventArgs e)
            {
    
                if (MouseButtons.Left == e.Button)
                {
    
                    this.mylist.Add(e.Location.X);
                    this.mylist.Add(e.Location.Y);
    
                    this.Refresh();
    
                }
    
            }
    
        }
    }
    


  • Du solltest auch irgendwie kennzeichnen, wo innerhalb von mylist die einzelnen Pinselstriche zu Ende sind. (und ich würde dir sowieso eine klarere Struktur für die Linien empfehlen)

    PS: Ich kenne mich mit der .NET Grafik nicht so gut aus, aber ist das mygraf.Dispose() wirklich notwendig?



  • CStoll schrieb:

    PS: Ich kenne mich mit der .NET Grafik nicht so gut aus, aber ist das mygraf.Dispose() wirklich notwendig?

    Nein es ist an der Stelle sogar falsch. Die Basisklasse kümmert sich darum.



  • Na gut blurry ich bin mal nicht so.

    namespace MalenNachZahlen
    {
        public partial class Form1 : Form
        {
            List<List<Point>> points;
    
            public Form1()
            {
                InitializeComponent();
                DoubleBuffered = true;
    
                points = new List<List<Point>>();
            }
    
            private void Form1_MouseDown(object sender, MouseEventArgs e)
            {
                points.Add(new List<Point>());
            }
    
            private void Form1_MouseMove(object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left)
                {
                    points.Last().Add(e.Location);
                    Invalidate();
                }
            }
    
            private void Form1_Paint(object sender, PaintEventArgs e)
            {
                foreach (var list in points.Where( l => l.Count > 1))
                        e.Graphics.DrawLines(Pens.Black, list.ToArray());
            }
        }
    }
    


  • mü dein Code klappt wunderbar.

    Leider hab ich große Probleme deinen überirdischen code zu verstehen.

    Kann mir mal einer sagen was ich noch ändern muss damit bei mir auch alles funktioniert ?



  • Der Trick ist, er verwendet keine einzelne Liste für alle zu zeichnenden Punkte, sondern für jeden "Pinselstrich" eine eigene Liste. Damit ist dann auch klar, wo eine Linie aufhört und die nächste anfängt.

    µ schrieb:

    CStoll schrieb:

    PS: Ich kenne mich mit der .NET Grafik nicht so gut aus, aber ist das mygraf.Dispose() wirklich notwendig?

    Nein es ist an der Stelle sogar falsch. Die Basisklasse kümmert sich darum.

    Da hat mich mein Gefühl also nicht im Stich gelassen 🕶



  • blurry333 Dein Code ist wesentlich schwerer zu verstehen, da Du sehr viel mehr Information in die Listenindizes kodierst als notwendig ist.

    CStoll hat Dir den entscheidenden Hinweis gegeben: "Du solltest auch irgendwie kennzeichnen, wo innerhalb von mylist die einzelnen Pinselstriche zu Ende sind".
    Dein Code lässt sich an der Stelle aber nur durch noch mehr Gefrickel reparieren. Zum Beispiel durch einführen einer zweiten Liste, in der die Anfangs- und Endindizes der einzelnen Striche gespeichert werden. Das wird immer unübersichtlicher und komplexer und ich bin eigentlich nicht bereit Dir in der Richtung zu helfen.

    Versuch lieber zu verstehen wie der andere Code funktioniert. Hier ein paar Hinweise.

    Wir haben Punkte, also WertPAARE, für die Liniensegmente eines Striches. .NET kommt von Haus aus mit einer Point-Struktur, also verwendet man die auch. Somit bist Du direkt die fehleranfällige, alternierende Speicherung von x- und y-Koordinaten los. Also, EIN einzelner Strich wird als List<Point> gespeichert.

    So zeichnest Du einen Strich:

    public partial class Form1 : Form
    {
            List<Point> meinStrich = new List<Point>();
    
            public Form1()
            {
                meinStrich.Add(new Point(100, 100));
                meinStrich.Add(new Point(200, 150));
                meinStrich.Add(new Point(150, 300));
    
                InitializeComponent();
                DoubleBuffered = true;
            }
    
            private void Form1_Paint(object sender, PaintEventArgs e)
            {
                //DrawLines wirft eine Exception wenn die Anzahl der Punkte <= 1 ist.
                 if(meinStrich.Count > 1)
                       e.Graphics.DrawLines(Pens.Black, meinStrich.ToArray());
            }
    }
    

    Jetzt willst Du mehrere Striche:

    List<Point> meinStrich1 = new List<Point>();
    List<Point> meinStrich2 = new List<Point>();
    List<Point> meinStrich3 = new List<Point>();
    

    Ziemlich dumm, oder? Lieber eine Liste von Strichen anlegen, dann begrenzen wir uns nicht auf drei:

    List<List<Point>> points;
    

    Was nun? Bei jedem Mouse_Down wird ein neuer Strich gestartet und unserer Liste (am Ende!) hinzugefügt:

    private void Form1_MouseDown(object sender, MouseEventArgs e) 
    {
         List<Point> meinNeuerStrich = new List<Point>(); 
         points.Add(meinNeuerStrich); 
    }
    

    Bei MouseMove (und gedrückter Maustaste) werden die Koordinaten der Maus dem aktuellen Strich hinzugefügt.
    Der aktuelle Strich ist der letzte in der Liste:

    Point mousePosition = e.Location;
    List<Point> aktuellerStrich = points[points.Count-1];
    aktuellerStrich.Add(mousePosition);
    

    oder kurz:

    points.Last().Add(e.Location);
    

    Und jetzt noch alle Striche zeichnen:

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
    
    	    //Jeden Strich einzeln zeichnen
                for (int i = 0; i < points.Count; ++i)
                {
                    List<Point> StrichPunkte = points[i];
    
                    if (StrichPunkte.Count > 1)
                        e.Graphics.DrawLines(Pens.Black, StrichPunkte.ToArray());
                }          
    }
    

    Oder eben kürzer und eleganter wie oben:

    foreach (var list in points.Where(l => l.Count > 1))
                   e.Graphics.DrawLines(Pens.Black, list.ToArray());
    


  • 🙂

    mir ist es aber ein absolutes Rätsel warum bei mir wenn ich eine neue Linie zeichne diese mit der vorherigen verbunden wird.
    Ich füge der Liste im mouse_down event einen neuen Punkt hinzu dann gehts ins Mouse_move event. Dort füge ich wieder einen Punkt hinzu .
    Dort rufe ich dann mit Refresh das paint Event auf.
    Der Endpunkt der alten Linie taucht hier gar nicht mehr auf.



  • Was zeichnet denn deiner Meinung nach den Endpunkt der alten Linie aus?

    Du verbindest paarweise alle Punkte die in der Liste aufeinanderfolgen. Es gibt keine Abgrenzung zwischen altem und neuem Strich und der Punkt, den Du in MouseDown in die Liste schiebst, unterscheidet sich nicht auf magische Weise von den Punkten des MouseMove events.

    Sagen wir du hast bereits einen Strich aus 4 Punkten gezeichnet: mylist = {P1,P2,P3,P4}

    Jetzt drückst Du wieder die Taste. MouseDown fügt einen Punkt hinzu: mylist = {P1,P2,P3,P4,P5}
    Und MouseMove noch weiter: {P1,P2,P3,P4,P5,P6,P7}

    Wo ist da jetzt noch ein Endpunkt markiert? Warum sollte P4 und P5 nicht verbunden sein?
    Deine Schleife verbindet sie alle! Was ist daran nicht zu verstehen?



  • stimmt. Danke für deine Erklärung.



  • so meine Lösung .

    Leider flackert es noch stark. Was könnte ich verbessern ?

    doublebuffered=true;
    

    funktioniert bei mir irgendwie nicht.

    namespace Malen
    {
        public partial class Form1 : Form
        {
    
            List<List<Point>> mylist = new List<List<Point>>();
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Paint(object sender, PaintEventArgs e)
            {
                Graphics mygraf = e.Graphics;
                Pen mypen = new Pen(Color.Black);
    
                for (int j = 0; j < mylist.Count; j++)
                {
    
                    for (int i = 1; i < this.mylist[j].Count; i++)
                    {
    
                        mygraf.DrawLine(mypen, mylist[j][i - 1].X, mylist[j][i-1].Y, mylist[j][i].X, mylist[j][i].Y);
    
                    }
    
                }
                mygraf.Dispose(); 
    
            }
    
            private void Form1_MouseDown(object sender, MouseEventArgs e)
            {
                this.mylist.Add(new List<Point>());
    
            }
    
            private void Form1_MouseMove(object sender, MouseEventArgs e)
            {
    
                if (MouseButtons.Left == e.Button)
                {
    
                    this.mylist[mylist.Count - 1].Add(e.Location);
    
                    this.Refresh();
    
                }
    
            }
    
        }
    


  • Mach das weg:
    mygraf.Dispose();

    Invalidate() statt Refresh()

    DoubleBuffered = true rein.

    Flackert mein Programm bei Dir?



  • ob invalidate oder refresh ist egal.
    ( was ist eigentlich noch mal genau der Unterschied )

    Was raus muss ist das dispose .

    am wichtigsten ist doublebuffered.

    Also dein Programm hat nicht geflackert.





  • kann mir mal einer diese Schleife erklären. Ist mir echt zu hoch

    µ schrieb:

    Na gut blurry ich bin mal nicht so.

    private void Form1_Paint(object sender, PaintEventArgs e)
            {
                foreach (var list in points.Where( l => l.Count > 1)) // l 
                                                                      // list var ?
                        e.Graphics.DrawLines(Pens.Black, list.ToArray()); //toarray ?
            }
       
    }
    

    welcher typ ist denn var ? was ist l=> ?
    toarray() ersetzt mein mylist[j][i - 1].X, mylist[j][i-1].Y, mylist[j][i].X, mylist[j][i].Y



  • blurry333 schrieb:

    welcher typ ist denn var ?

    var typisiert Bezeichner implizit zur Compilezeit.

    blurry333 schrieb:

    was ist l=> ?

    Ein Lambda-Ausdruck der mit LINQ Einzug in C# gehalten hat. Davor musste man auf anonyme Methoden/Delegaten zurück greifen.

    Zeit für ein Buch blurry.


  • Administrator

    µ schrieb:

    Zeit für ein Buch blurry.

    Weisst du eigentlich, wie oft wir ihm das schon gesagt haben? Aber es findet sich immer eine naive und freundliche Person, welche dem Blurry die Denkarbeit abnimmt 😉

    Grüssli



  • Klar weiß ich das. Ich wollte Blurry sperren lassen.

    Aber er hat das List-Generic entdeckt und endlich aufgehört außerhalb des Paint-Eventhandlers zeichnen zu wollen. Wenn das kein belohnenswerter Fortschritt ist

    A New Hope 😉


  • Administrator

    µ schrieb:

    Ich wollte Blurry sperren lassen.

    Das ist mir durchaus bewusst 😉

    Grüssli



  • Willst Du mir sagen, dass ich einfach mal die Fresse halten und Blurry nicht mehr helfen soll? 😃


Anmelden zum Antworten