Kreise, Rechtecke und Linien animieren



  • Hallo zusammen,

    ich soll für eine Aufgabe ein vorhandenes Programm umbauen. In dem Programm geht es um die Grundlagen der Grafikprogrammierung. Es werden Kreise, Rechtecke und Linien dargestellt.

    Erweitern Sie die grafische Spielerei um Animationen für die Elemente ohne Füllungen. Die Kreise beziehungsweise Rechtecke sollen dabei von innen nach außen schrittweise vergrößert werden. Bei den Linien soll die Animation von der Mitte sowohl nach unten als auch nach oben laufen. Bei jedem Schritt soll das alte Element gelöscht und ein neues gezeichnet werden. Wenn der äußere Rand erreicht ist, soll sich die Animation wieder nach innen bewegen, bis ungefähr die ursprüngliche Größe beziehungsweise die ursprüngliche Position erreicht ist. Die Anzahl der Wiederholungen für die Animation und die Geschwindigkeit der Animation soll der Anwender über geeignete Steuerelemente selbst festlegen können.

    Und hier das Programm:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace Eine_Spielerei
    {
        public partial class Form1 : Form
        {
            //eine Variable um Durchläufe zu zählen
            int durchlaeufe;
            //das Feld zeichenflaeche vereinbaren
            Graphics zeichenflaeche;
            //die Linienfarbe
            Color linienfarbe;
            //die Hintergrundfarbe
            Color hintergrundfarbe;
    
            //für den Linienstil
            System.Drawing.Drawing2D.DashStyle[] linienstil =
            {
                System.Drawing.Drawing2D.DashStyle.Dash,
                System.Drawing.Drawing2D.DashStyle.DashDot,
                System.Drawing.Drawing2D.DashStyle.DashDotDot,
                System.Drawing.Drawing2D.DashStyle.Dot,
                System.Drawing.Drawing2D.DashStyle.Solid
            };
    
            //für den Hintergrund
            System.Drawing.Drawing2D.HatchStyle[] fuellstil =
            {
                System.Drawing.Drawing2D.HatchStyle.BackwardDiagonal,
                System.Drawing.Drawing2D.HatchStyle.Cross,
                System.Drawing.Drawing2D.HatchStyle.DottedGrid,
                System.Drawing.Drawing2D.HatchStyle.ForwardDiagonal,
                System.Drawing.Drawing2D.HatchStyle.Sphere,
                System.Drawing.Drawing2D.HatchStyle.Vertical,
                System.Drawing.Drawing2D.HatchStyle.Wave,
                System.Drawing.Drawing2D.HatchStyle.ZigZag
            };
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                //die Hintergrundfarbe ist zunächst schwarz
                hintergrundfarbe = Color.Black;
                //die Linienfarbe ist zunächst schwarz
                linienfarbe = Color.Black;
                //für die Lininenstile 
                foreach (System.Drawing.Drawing2D.DashStyle element in linienstil)
                    listBoxLinieStil.Items.Add("");
                //für den Hintergrund
                foreach (System.Drawing.Drawing2D.HatchStyle element in fuellstil)
                    listBoxHintergrundStil.Items.Add("");
    
                //eine Referenz auf die Zeichenfläche des Panels setzen
                //zeichenflaeche ist als Feld der Klasse Form1 vereinbart
                zeichenflaeche = panel1.CreateGraphics();
            }
    
            private void buttonBeenden_Click(object sender, EventArgs e)
            {
                Close();
            }
    
            private void buttonLoeschen_Click(object sender, EventArgs e)
            {
                zeichenflaeche.Clear(panel1.BackColor);
            }
    
            private void buttonStart_Click(object sender, EventArgs e)
            {
                //eine lokale Variable für die Größe
                int groesse = 0;
                //einen Stift erzeugen
                Pen stift = new Pen(linienfarbe);
                //einen Pinsel erzeugen
                SolidBrush pinsel = new SolidBrush(hintergrundfarbe);
                //die Dicke des Stiftes setzen
                stift.Width = Convert.ToInt32(numericUpDownLinieStaerke.Value);
                //die Groesse der Figur ermitteln
                switch(trackBar1.Value)
                {
                    case 1: groesse = 125;
                        break;
                    case 2: groesse = 100;
                        break;
                    case 3: groesse = 75;
                        break;
                }
                //den Linienstil ermitteln
                if (listBoxLinieStil.SelectedIndex >= 0)
                    stift.DashStyle = linienstil[listBoxLinieStil.SelectedIndex];
                //Figur ermitteln
                //beim Kreis und beim Rechteck auch die Füllung überprüfen
                if (radioButtonKreis.Checked == true)
                {
                    if (radioButtonHintergrundOhne.Checked == true)
                        //zeichenflaeche.DrawEllipse(stift, panel1.ClientRectangle.Left + groesse, panel1.ClientRectangle.Top + groesse, panel1.ClientRectangle.Width - (groesse * 2), panel1.ClientRectangle.Height - (groesse * 2));
    
                    if (radioButtonHintergrundFarbe.Checked == true)
                        zeichenflaeche.FillEllipse(pinsel, panel1.ClientRectangle.Left + groesse, panel1.ClientRectangle.Top + groesse, panel1.ClientRectangle.Width - (groesse * 2), panel1.ClientRectangle.Height - (groesse * 2));
                    //soll mit Muster gezeichnet werden und ist ein Muster ausgewählt?
                    if (radioButtonHintergrundMuster.Checked == true && listBoxHintergrundStil.SelectedIndex >= 0)
                    {
                        //einen neuen Pinsel für das Muster erzeugen
                        //die Vordergrundfarbe kommt vom Stift, der Hintergrund ist immer weiß
                        System.Drawing.Drawing2D.HatchBrush musterPinsel = new System.Drawing.Drawing2D.HatchBrush(fuellstil[listBoxHintergrundStil.SelectedIndex], stift.Color, Color.White);
                        zeichenflaeche.FillEllipse(musterPinsel, panel1.ClientRectangle.Left + groesse, panel1.ClientRectangle.Top + groesse, panel1.ClientRectangle.Width - (groesse * 2), panel1.ClientRectangle.Height - (groesse * 2));
                    }
                }
    
                if (radioButtonRechteck.Checked == true)
                {
                    if (radioButtonHintergrundOhne.Checked == true)
                        zeichenflaeche.DrawRectangle(stift, panel1.ClientRectangle.Left + groesse, panel1.ClientRectangle.Top + groesse, panel1.ClientRectangle.Width - (groesse * 2), panel1.ClientRectangle.Height - (groesse * 2));
                    if (radioButtonHintergrundFarbe.Checked == true)
                        zeichenflaeche.FillRectangle(pinsel, panel1.ClientRectangle.Left + groesse, panel1.ClientRectangle.Top + groesse, panel1.ClientRectangle.Width - (groesse * 2), panel1.ClientRectangle.Height - (groesse * 2));
                    //soll mit Muster gezeichnet werden und ist ein Muster ausgewählt?
                    if (radioButtonHintergrundMuster.Checked == true && listBoxHintergrundStil.SelectedIndex >= 0)
                    {
                        //einen neuen Pinsel für das Muster erzeugen
                        //die Vordergrundfarbe kommt vom Stift, der Hintergrund ist immer weiß
                        System.Drawing.Drawing2D.HatchBrush musterPinsel = new System.Drawing.Drawing2D.HatchBrush(fuellstil[listBoxHintergrundStil.SelectedIndex], stift.Color, Color.White);
                        zeichenflaeche.FillRectangle(musterPinsel, panel1.ClientRectangle.Left + groesse, panel1.ClientRectangle.Top + groesse, panel1.ClientRectangle.Width - (groesse * 2), panel1.ClientRectangle.Height - (groesse * 2));
                    }
                }
    
                if(radioButtonLinie.Checked == true)
                {
                    zeichenflaeche.DrawLine(stift, panel1.ClientRectangle.Left + groesse, panel1.ClientRectangle.Height / 2, panel1.ClientRectangle.Width - groesse, panel1.ClientRectangle.Height / 2);
                }
            }
    
            private void buttonLinieFarbe_Click(object sender, EventArgs e)
            {
                //den Dialog zur farbauswahl anzeigen
                if(colorDialog1.ShowDialog()==DialogResult.OK)
                {
                    //die Hintergrundfarbe für das Panel auf die ausgewählte Farbe setzen
                    panelLinieFarbeVorschau.BackColor = colorDialog1.Color;
                    //und die Linienfarbe
                    //Linienfarbe ist ein Feld der Klasse Form1
                    linienfarbe = colorDialog1.Color;
                }
            }
    
            private void buttonHintergrundFarbe_Click(object sender, EventArgs e)
            {
                //den Dialog zur Farbauswahl zeigen
                if(colorDialog1.ShowDialog()==DialogResult.OK)
                {
                    //die Hintergrundfarbe für das Panel auf die ausgewählte farbe setzen
                    panelHintergrundfarbe.BackColor = colorDialog1.Color;
                    //und die eigentliche Hintergrundfarbe
                    //Hintergrundfarbe ist ein Feld der Klasse Form1
                    hintergrundfarbe = colorDialog1.Color;
                    //die Auswahl Farbe aktivieren
                    radioButtonHintergrundFarbe.Checked = true;
                }
            }
    
            private void listBoxLinieStil_DrawItem(object sender, DrawItemEventArgs e)
            {
                //eine lokale Variable für die Berechnung der Mitte
                int y;
                //ein neuer lokaler Stift
                Pen boxStift = new Pen(Color.Black);
                //die Mitte berechnen
                y = (e.Bounds.Top + e.Bounds.Bottom) / 2;
                //den Hintergrund zeichnen
                e.DrawBackground();
                //und die Linie
                boxStift.DashStyle = linienstil[e.Index];
                e.Graphics.DrawLine(boxStift, e.Bounds.Left + 1, y, e.Bounds.Right - 1, y);
            }
    
            private void listBoxHintergrundStil_DrawItem(object sender, DrawItemEventArgs e)
            {
                //ein neuer lokaler Pinsel für das Muster
                System.Drawing.Drawing2D.HatchBrush boxPinsel = new System.Drawing.Drawing2D.HatchBrush(fuellstil[e.Index], Color.Black, Color.White);
                //den Hintergrund zeichnen
                e.DrawBackground();
                //und das Rechteck
                e.Graphics.FillRectangle(boxPinsel, e.Bounds.Left + 1, e.Bounds.Top + 1, e.Bounds.Width - 1, e.Bounds.Height - 1);
            }
    
            private void timer1_Tick(object sender, EventArgs e)
            {
                for(durchlaeufe = 0; durchlaeufe <= numericUpDownDurchlaufe.Value; durchlaeufe++)
                {
    
                }
            }
    
            private void panel1_Paint(object sender, PaintEventArgs e)
            {
    
            }
    
            //die eingestellte Geschwindigkeit an den Timer übergeben
            private void numericUpDownGeschwindigkeit_ValueChanged(object sender, EventArgs e)
            {
                timer1.Interval = (int)(numericUpDownGeschwindigkeit.Value * 1000);
            }
        }
    }
    

    Ich hänge dort total fest und weiß nicht weiter. Ich habe für die Anzahl der Durchläufe und die Geschwindigkeit einen numericUpDown gewählt und möchte es über dem timer steuern.

    Kann mir vielleicht jemand helfen?



  • Hallo,

    lies dir mal [Tutorial] Zeichnen in Windows-Forms-Programmen (Paint/OnPaint, PictureBox) durch.

    Du darfst nur im Paint-Ereignis zeichnen und nicht außerhalb (die Methode panel1_Paint existiert ja schon in deiner Form-Klasse).
    Und im Timer veränderst du dann nur die Variablen für die Positionen und rufst dann für das Panel Invalidate() auf.

    Die Variable "Graphics zeichenflaeche" solltest du als erstes gleich wieder entfernen.



  • Th69 schrieb:

    Die Variable "Graphics zeichenflaeche" solltest du als erstes gleich wieder entfernen.

    Das soll aber Bestandteil der Aufgabe sein. Auch wenn es mir freigestellt ist wie ich die Aufgabe löse, wäre das weglassen ein Fehler.



  • Hallo DerGerd,

    wie Th69 angesprochen hat, brauchst du die Variable "Graphics zeichenflaeche" nicht. Wenn du wie angesprochen im OnPaint zeichnest hast du Zugriff auf das Graphics-Objekt des Controls in das du zeichnest.

    Du kannst auch gut und gern mit einem Timer das Zeichnen auslösen. Dann würde der EventHandler des Ticks eben die neuen Punkte setzen und anschließend ein Control.Invalidate auf die Zeichenfläche auslösen. Durch das Invalidate wird die Zeichnung für ungültig erklärt und das Neuzeichnen ausgelöst.

    Anhand deines Codes würde sich halt statts der panel1.CreateGraphics() variante folgendes ergeben:

    private void MyPanel_Paint(Object sender, PaintEventArgs e)
    {
         var zeichenFlaeche = e.Graphics;
    
         // zeichnen auf die Zeichenfläche...
    }
    


  • Hallo ich mache gerade das gleiche. Hast Du die Lösung gefunden? Könntest Du die mir zukommen lassen?


Anmelden zum Antworten