Laden...

Mehrere in sich abgeknickte Linien zeichnen, die aber mit den anderen Linien nicht verbunden sind

Erstellt von Tornado47 vor 12 Jahren Letzter Beitrag vor 12 Jahren 5.745 Views
T
Tornado47 Themenstarter:in
38 Beiträge seit 2011
vor 12 Jahren
Mehrere in sich abgeknickte Linien zeichnen, die aber mit den anderen Linien nicht verbunden sind

Hy, leider bin ich scheinbar nicht in der Lage, ein vermeintlich einfaches Problem wie ein Notizbuch mittels Touchscreen zu realisieren (Sprich: zeichnen)

Der Code schaut so aus:

    public partial class Form1 : Form
{
    List<Point> Points = new List<Point>();
    ArrayList total = new ArrayList();
    Pen skyBluePen = new Pen(Color.FromArgb(50, Color.DeepSkyBlue));

    public Form1()
    {
        InitializeComponent();
        skyBluePen.Width = 8.0F;
        skyBluePen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;

    }
         
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);


        foreach (List<Point> element in total)
        { 
            if (element.Count > 1)
            {

                e.Graphics.DrawLines(this.skyBluePen, element.ToArray());
            }
        }
    }

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

       
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        
        if(e.Button == MouseButtons.Left)
            Points.Add(e.Location);

        this.Invalidate();
    }
    protected override void OnMouseUp(MouseEventArgs e)
    {
        base.OnMouseUp(e);

        total.Add(Points);
        
        //Points.Clear();
    }

So funktioniert alles, allerdings kann ich dann nur eine Linie zeichnen, da er Elemente, die ich eigentlich alleinestehend zeichnen wollte, verbindet.

Entferne ich das Kommentar vor der letzten Zeile "Points.Clear()", sehe ich meine aktuelle Zeichnung und dann verschwindet sie wieder.

Mein Ansatz war, die einzelnen "Point Lists" in eine ArrayList zu speichern und dann jeweils einzeln zu zeichnen. Scheinbar habe ich da etwas falsch verstanden, oder?

Hinweis von herbivore vor 12 Jahren

ArrayList gehört in die Mottenkiste und sollte wie alle untypisierten Collections aus System.Collections nicht mehr benutzt werden. Verwende stattdessen List<T> und alle anderen typisierten Collections aus System.Collections.Generic; im konkreten Fall eine List<List<Point>>.

2.298 Beiträge seit 2010
vor 12 Jahren

Da du nur Linien zeichnen willst würde es sich eher anbieten eine Klasse zu definieren, mit Start- und Endpunkt der Linie also Quasi:


class Line
{
    private Point _startPoint;
    public Point StartPoint
    {
        get { return _startPoint; }
        set { _startPoint = value; }
    }

    private Point _endPoint;
    public Point EndPoint
    {
        get { return _endPoint; }
        set { _endPoint = value; }
    }  
}

Von der Klasse kannst du dann x-Objekte in einer List<Line> speichern und anschließend zeichnen lassen.

PS: Lass die finger von der ArrayList. 😃 - Näheres dazu findet sich mit der Suchfunktion.

// Edit:
Du fügst aktuell x-Punkte zur Liste hinzu. Mit DrawLines zeichnet er zwischen den einzelnen Punkten dann auch die Linien. Daher hast du keine einzel-Linien. - Besser wäre hier: im Mousedown Startpunkt festlegen, im MouseUp Endpunkt festlegen und zur Liste hinzufügen (natürlich die von mir vorgeschlagene Liste).

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

T
Tornado47 Themenstarter:in
38 Beiträge seit 2011
vor 12 Jahren

Aber dann kann ich doch nur gerade Linien zeichnen oder?

2.298 Beiträge seit 2010
vor 12 Jahren

Naja, wenn du Linien mit Knick zeichnen willst wirds komplizierter. 😃

Vorgehensweise:

Du nimmst eine List<List<Point>>, erstellst im MouseDown eine neue List<Point> fügst diese der List<List<Point>> hinzu.

Während des Mousemove fügst du nun der letzten List<Point> in der Auflistung die einzelnen Punkte hinzu.

Anschließend brauchst du dann nur noch zeichnen.

Aktuell hast du genau eine List<Point>, was zu deinem Effekt führt.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

T
Tornado47 Themenstarter:in
38 Beiträge seit 2011
vor 12 Jahren

Ich versuch es dann mal, danke für deine Hilfe!!!

G
47 Beiträge seit 2011
vor 12 Jahren

Hi Tornado,

ergaänze einfach ein


Points = new List<Point>();

im OnMouseDown Ereignis.

total spiechert nur einen Verweis auf das jeweilige Points-Object, das ihm übergeben wird. deshalb musst du für Points immer eine neue Liste erstellen, wenn du eine neue Linie zeichnen möchtest.

Gruß Gwinn

T
Tornado47 Themenstarter:in
38 Beiträge seit 2011
vor 12 Jahren

Das war jetzt ausschlaggebend! Danke! Mein Versuch war das "Points.Clear", aber dass hier nur der Verweis gespeichert wird war mir nicht klar! Danke 😄

T
Tornado47 Themenstarter:in
38 Beiträge seit 2011
vor 12 Jahren

Hy, nachdem ich das ganze jetzt in C# geschafft habe, bin ich draufgekommen, dass das gar nicht so einfach in WPF zu konvertieren ist-.-
Ich finde leider kein Objekt, dass eine komplexe Linie darstellen kann... Entweder ist es eine gerade Linie oder eine Kombination aus mehreren Formen.
Was kann ich hier verwenden?

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo Tornado47,

in Shapes and Basic Drawing in WPF Overview ist nichts dabei?

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

T
Tornado47 Themenstarter:in
38 Beiträge seit 2011
vor 12 Jahren

Da ist zwar eine Linie dabei, die meinen Anforderungen entsprechen könnte, allerdings nur in XAML angegeben. Aber ich werde einfach mal versuchen, damit zu arbeiten... Die Seite hatte ich auch schon durchgelesen, aber ich bin nicht wirklich weitergekommen. Ich werde es dennoch noch mal versuchen =) danke

T
Tornado47 Themenstarter:in
38 Beiträge seit 2011
vor 12 Jahren

Ich habe es jetzt ansatzweise zufriedenstellen hinbekommen, allerdings habe ich das Problem, dass ich den Content der Page ja mit dem Canvas überschreibe.
Das heißt ich kann keine Buttons machen.
Gibt es dafür auch eine Lösung?

Hier der Code:

 public partial class notebook : Page
    {
        
        public static List<Line> savelist = new List<Line>();
        public notebook()
        {
            InitializeComponent();
            MyCanvas myc = new MyCanvas();
            myc.Background = System.Windows.Media.Brushes.Transparent;
            this.Content = myc;
            
        }
        public class MyCanvas : Canvas
        {
            bool lineStarted = false;
            System.Windows.Point mousePoint1;
            protected override void OnMouseDown(MouseButtonEventArgs e)
            {
                base.OnMouseDown(e);
                if (!lineStarted)
                {
                    lineStarted = true;
                    mousePoint1 = e.GetPosition(this);
                }
                this.InvalidateVisual();
            }
            protected override void OnMouseUp(MouseButtonEventArgs e)
            {
                base.OnMouseUp(e);
                this.lineStarted = false;
                this.InvalidateVisual();
            }
            protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
            {
                base.OnMouseMove(e);
                if (lineStarted)
                {
                    System.Windows.Point mousePoint2 = e.GetPosition(this);
                    Line newLine = new Line { X1 = mousePoint1.X, Y1 = mousePoint1.Y, X2 = mousePoint2.X, Y2 = mousePoint2.Y };
                    newLine.Stroke = System.Windows.Media.Brushes.Black;
                    newLine.StrokeThickness = 5;
                    this.Children.Add(newLine);
                    savelist.Add(newLine);
                    mousePoint1 = e.GetPosition(this);
                }
            }
            protected override void OnRender(DrawingContext dc)
            {
                base.OnRender(dc);
                if(lineStarted)
                dc.DrawLine(new System.Windows.Media.Pen(System.Windows.Media.Brushes.Black, 5), this.mousePoint1, Mouse.GetPosition(this));
            }
        }

        private void save1_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.MessageBox.Show(tostring());
        }

        private string tostring()
        {
            string drawing = "";
            for (int i = 0; i < savelist.Count(); i++)
            {
                drawing += savelist[i].X1 + "," + savelist[i].X2 + "," + savelist[i].Y1 + "," + savelist[i].Y2;
                if (i < savelist.Count() - 2)
                {
                    drawing += "|";
                }
            }
            return drawing;
        }

    }

}
6.911 Beiträge seit 2009
vor 12 Jahren

Hallo Tornado47,

mir kommt das sehr durch die Luft gewirbelt vor was du da machen willst.

Mach es lieber "wie üblich" in WPF mit XAML und per Styles, etc. dann bekommst du alles sauber getrennt hin. Für den Button kannst du das ControlTemplate überschreiben und in der :rtfm: gibts dafür sogar mehrere Beispiele.
Das Zeichnen von eigenen Linien erfolgt jedoch weiterhin in der Code-Behind, analog zu dem bereits oben erwähnten, nur halt die entsprechenden WPF-Klassen verwenden.

Beschreib, wenn dir das nicht hilft, was genau du vorhast.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

T
Tornado47 Themenstarter:in
38 Beiträge seit 2011
vor 12 Jahren

Im Grunde genommen will ich, dass der User etwas zeichnen kann und das dann mittels den Koordinaten der einzelnen Linien als Text gespeichert werden kann.

Habe ich nicht die für WPF üblichen Klassen verwendet? Ich habe versucht mich an diversen WPF Guides zu orientieren. So wie ich Dich verstehe, ist das, was ich bereits gemacht habe jetzt nicht richtig bzw konform, oder?

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo Tornado47,

doch die üblichen Klassen hast du verwendet, aber alles eher wild zusammengeworfen. Von der Canvas kannst du ableiten und dort die Zeichenlogik unterbringen - keine Problem und das passt auch. Aber mach die von Canvas abgeleite Klasse separat und nicht als nested class von der Page. Somit kannst du auch in XAML die MyCanvas erstellen und entsprechend positionieren, so dass die Buttons angezeigt werden können (also schauen dass die Canvas oben liegt od. mittels z-Index).

Benenne auch keine Methode mit "tostring", denn das ist sehr an ToString angelehnt und diese Methode gehört einfach zu jedem Objekt. Um das sauber zu implementieren könntest du z.B. eine eigene Klasse erstellen welche die List<Line> kapselt und dort entweder ToList überschreiben od. noch besser eine richtig benannte Methode wie GetCoordinatesAsString implementieren. Somit hast du das auch sauber getrennt, denn diese Aufgabe gehört nicht in die Page.

Ich hoffe du verstehst was ich meine.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

T
Tornado47 Themenstarter:in
38 Beiträge seit 2011
vor 12 Jahren

Ich denke ich habe soweit verstanden was Du meinst und habe das jetzt folgendermaßen umgesetzt:
Ich habe die Klasse ganz weg gelassen und alles in die Notebook Klasse umgeschrieben, da es ja an sich egal ist, ob alles da drinnen steht oder in einer eigenen Klasse. MyCanvas ist jetzt in der .xaml definiert.

Eine Frage habe ich noch:
Ist der Name "LineToString()" in Ordnung?
Ich habe bewusst die Nähe zu "toString()" gewählt, da es ja die Linie in einen String umwandelt. Aber ich mag natürlich alles richtig machen, also ist der neue Name in Ordnung oder auch noch zu nahe am "toString()"?

Danke auf jeden Fall für Deine Hilfe!

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo Tornado47,

"LineToString" beschreibt nur dass eine Line zu einem String wird, mehr nicht, daher gehts auch noch sprechender. Oben habe ich "GetCoordinatesAsString" vorgeschlagen, das beschreibt schon mal dass die Coordinates als String zurückgegeben werden, aber auch nocht nicht welche Coordinates. Somit wäre dann wohl "LineCoordinatesToString" od. "GetStringRepresentationFromLineCoordinates" passender. Jedenfalls so, dass aus dem Methodennamen sofort ersichtlich ist was passiert, ohne dass dazu extra ein Kommentar notwendig ist.

Dass wir aber nicht ganz vom Thema abschweifen der Hinweis zu: [Hinweis] Wie poste ich richtig? Punk 1.2.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

T
Tornado47 Themenstarter:in
38 Beiträge seit 2011
vor 12 Jahren

OK sorry für das Abschweifen und danke für Deine Hilfe!
Habe es jetzt nach deinem Vorschlag umbenannt 🙂