none
Event-Handling in GDI+ RRS feed

  • Frage

  • Hallo 
    Also ich hab für die Matura ein kleines Programm geschrieben um zu üben und zwar fährt ein Zug(rechteckiger Block) von links nach rechts und soll bei einem bestimmten Punkt ein Event auslösen und in diesen Fall die Schranken zu schließen. Das funktioniert bei mir leider nicht und bin deshalb schon ein bisschen am verzweifeln 
    Falls ihr mehr Code von meinen Programm braucht sagt bitte bescheid
    Danke für eure Hilfe 

    //Form 1
    public partial class Form1 : Form
        {
            public delegate void GateEvent(Graphics g, int high, int width);
            public event GateEvent gatev;
            Street street;
            RailTracks rt;
            Graphics g;
            Gates gat;
            EventPoints ep;
            Diesellok lok;
            ELok elok;
            int a;
            Random rand;
            int index;
            int trainnumber;
            public Form1()
            {
                InitializeComponent();
                street = new Street();
                rt = new RailTracks();
                gat = new Gates(this);
                ep = new EventPoints();
                lok = new Diesellok();
                elok = new ELok();
                a = 0;
                rand = new Random();
                index = rand.Next(1, 3);
                trainnumber = rand.Next(100, 201);
            }
            private void timer1_Tick(object sender, EventArgs e)
            {       
                a = a + 1;
                this.pictureBox1.Invalidate();
                if ((this.a+120) == (this.pictureBox1.Width / 2-100))
                {
                    this.StartEvent(g);
                    this.pictureBox1.Invalidate();
                }
                if (a > this.pictureBox1.Width)
                {
                    
                    index = rand.Next(1, 3);
                    a = 0;
                    trainnumber = rand.Next(100, 201);
                    this.pictureBox1.Invalidate();
                }
    
            }
            public void StartEvent(Graphics g)
            {
                g = this.CreateGraphics();
               gatev(g, this.pictureBox1.Height, this.pictureBox1.Width);          
            }
            private void pictureBox1_Paint(object sender, PaintEventArgs e)
            {
                Font f = new Font("Arial", 15);
                g = e.Graphics;
                street.Draw(g, this.pictureBox1.Height, this.pictureBox1.Width);
                rt.Draw(g, this.pictureBox1.Height, this.pictureBox1.Width);
                gat.Draw(g, this.pictureBox1.Height, this.pictureBox1.Width);
                ep.Draw(g, this.pictureBox1.Height, this.pictureBox1.Width);
    
                if (index == 1)
                {
                    lok.Draw(g, this.pictureBox1.Height, this.pictureBox1.Width, this.a);         
                    g.DrawString("Diesel", f, Brushes.Black, this.a + 10, this.pictureBox1.Height / 2 - 30);
                    g.DrawString(trainnumber.ToString(), f, Brushes.Black, this.a + 70, this.pictureBox1.Height / 2 - 30);
                    g.DrawString("1990", f, Brushes.Black, this.a + 30, this.pictureBox1.Height / 2 - 10);
                    g.DrawString("500l", f, Brushes.Black, this.a + 30, this.pictureBox1.Height / 2 + 10);
                }
                else
                {
                    elok.Draw(g, this.pictureBox1.Height, this.pictureBox1.Width, this.a);
                    g.DrawString("ELok", f, Brushes.Black, this.a + 10, this.pictureBox1.Height / 2 - 30);
                    g.DrawString(trainnumber.ToString(), f, Brushes.Black, this.a + 70, this.pictureBox1.Height / 2 - 30);
                    g.DrawString("1990", f, Brushes.Black, this.a + 30, this.pictureBox1.Height / 2 - 10);
                    g.DrawString("2000V", f, Brushes.Black, this.a + 30, this.pictureBox1.Height / 2 + 10);
                }
    
            }
            private void Form1_Resize(object sender, EventArgs e)
            {
                this.pictureBox1.Invalidate();
            }
    //Klasse Gates
     class Gates : DrawingObject
        {
           
            public void Draw(Graphics g, int high, int width)
            {
                g.FillRectangle(new SolidBrush(Color.Olive), width / 2 - 60, high / 2 - 45, 10, 10);
                g.FillRectangle(new SolidBrush(Color.Olive), width / 2 - 60, high / 2 + 45, 10, 10);
    
            }
            public Gates(Form1 f1)
            {
                f1.gatev += new Form1.GateEvent(f1_gatev);
            }
    
            public void f1_gatev(Graphics g, int high, int width)
            {
                g.FillRectangle(new SolidBrush(Color.Green), width / 2 - 60, high / 2 - 45, 125, 10);
                g.FillRectangle(new SolidBrush(Color.Green), width / 2 - 60, high / 2 + 45, 125, 10);
    
            }

    Montag, 15. April 2013 17:20

Alle Antworten

  • Hallo,

    da die Zeichen-Elemente fehlen muss man ein bisschen raten.  Wenn ich aus den (nicht ganz verständlichen) Namen eine Art Karte ableite, so gibt es keinen Grund hier ein Ereignis einzusetzen.

    Einfacher wäre ein Flag zu verwenden, womit das "Gates" seinen Zustand von zu auf offen - oder was auch immer es anzeigen soll - wechselt:

        class Gates // : DrawingObject // auskommentiert da fehlend
        {
            public bool Open { get; set; }
    
            public void Draw(Graphics g, int high, int width)
            {
                System.Diagnostics.Debug.WriteLine("Draw Gate:" + this.Open);
                Color gateColor = (this.Open) ? Color.Green : Color.Olive;
                using (Brush brush = new SolidBrush(gateColor))
                {
                    g.FillRectangle(brush, width / 2 - 60, high / 2 - 45, 125, 10);
                    g.FillRectangle(brush, width / 2 - 60, high / 2 + 45, 125, 10);
                }
            }
        }
    

    Im Timer Code würde der Zustand dann gewechselt:

            private void timer1_Tick(object sender, EventArgs e)
            {
                a = a + 1;
                System.Diagnostics.Debug.WriteLine("A: {0} / Gate: {1}", a + 120, this.pictureBox1.Width / 2 - 100);
                if ((this.a + 120) >= (this.pictureBox1.Width / 2 - 100))
                {
                    // Zustand wechseln
                    this.gat.Open = true;
                }
    
                // ... gestrichen...
    
                // Neuzeichnen veranlassen 
                this.pictureBox1.Invalidate();
            }
    

    Wobei ich offen gelassen haben, wann der Zustand wieder auf geschlossen geht - ggf. kann man  die Eigenschaft aber bei jedem Durchlauf setzen. Und natürlich müsste der Timer ticken.

    Weitere Hinweise:

    Wie man rausfinden kann, ob und was passiert habe, ich über Debug Klasse angedeutet, die Ausgaben erscheinen im Ausgabefenster.

    Im übrigen sollte man Zeichenobjekte wie SolidBrush nach Gebrauch entsorgen, was am einfachsten über using geht.

    Da für die Matura: Tue Dir und Deinem Lehrer einen Gefallen und bezeichne Deine Variablen - z. b. a muss nicht sein - etwas klarer. Trotz des sehr kleinen Programms ist das Lesen relativ anstrengend (und ich habe ziemlich viel Übung ;).

    Gruß Elmar

    Montag, 15. April 2013 19:06
    Beantworter
  • Hallo

    Danke für deine Hilfe :)
    Ich werde das für die Matura dann natürlich berücksichtigen und eigentlich muss ich eh mein ganzes Programm kommentieren, was ich in diesen Fall leider noch nicht gemacht habe aber jetzt noch machen werden.

    lg

    Xandl

    Montag, 15. April 2013 19:16


  • Übung: TrainEventSimulation

    Erstellen Sie ein C#-Programm (GDI+) welches einen „Bahnübergang“ simuliert mit folgenden Funktionen:

    1.        Darstellung

    Die Straße verläuft von Norden nach Süden; die Bahnlinie von Westen nach Osten; die Kreuzung der Straße mit der Bahn muss immer im Zentrum des Forms liegen, sodass bei einem Resize-Vorgang alles weiterhin zentral angezeigt wird!

    -          Die Maße (Straßenbreite,..) können beliebig angenommen werden

    -          Die Farben können beliebig angenommen werden

    -          Die Properties der Lokomotiven muss im Rechteck angezeigt werden

    1.        Ablauf: Eine Lokomotive fährt von Westen nach Osten; sobald der erste Signalgeber (oranges rundes Symbol) erreicht wird werden die Schranken geschlossen(mittels Event!); sobald das Ende der Lokomotive den zweiten Signalgeber passiert hat werden die Schranken wieder geöffnet (Darstellung des Balkens als kleines grünes Rechteck am linken Anfang des Schrankens). Es existieren zwei Arten von Lokomotiven, die zufallsgesteuert erscheinen – Diesellokomotive (Properties: string id, int baujahr, int tank)und E-Lok (string id, int baujahr, int spannung). Die Nummern der Lokomotiven müssen zufällig zwischen 100 und 200 gewählt werden. Die DieselLok ist „blau“  und die ELok ist „rot“.
    2.        Programmierung: Verwenden Sie möglichst unterschiedliche Klassen bzw. Interfaces. Alle Objekte, die gezeichnet werden sollen, sollen für das Zeichnen eine Methode verwenden, die für alle den gleichen Namen besitzt (zB „drawObject“). 

    Aja und das mit den Event war nicht meine Idee sonder stand in der Angabe ;)

    Montag, 15. April 2013 19:18
  • Hallo,

    ein Ereignis gäbe zwar durchaus Sinn, aber nur bei einer anderen Strukturierung des Ablaufs.

    Auslösen sollte ein Ereignis die Lokomotive(n) - und zwar wenn sie die Signalgeber-Position erreicht haben. Wobei auch dabei die Schranken den Zustand (bei mir Open, hieße wohl besser Closed / Geschlossen) wechseln und solange beibehalten würden, bis ein weiteres Signal - auch hier wieder durch die Lokomotive ausgelöst das Öffnen anzeigt.

    Sollte der Fall eintreten können, dass zwei Lokomotiven direkt hinter einander kommen, so reicht für den Zustand kein boolean mehr, sondern Du müsstest den Zustand auf / zu hochzählen, sonst öffnet die Schranke u. U zu früh (und es passiert ein Unglück ;)

    Will man es  "richtig machen", sollten die Signalgeber ein eigenes Objekt sen. Und die Lokomotiven nur ihre Position mitteilen (auch ein Ereignis) auf das der Signalgeber wiederum selbst ein Ereignis auslöst - was hier das Öffnen und schlissen der Schranken auslöst.

    Damit der Code das Ganze besser abbildet (verständlicher wird), solltest Du das Malen von dem Zustandsänderungen (Bewegung der Loks, Signalgeber an/aus, Schranke auf/zu) trennen.

    Die Draw-Methoden sollten wiederum nur periodisch den aktuellen Zustand (farblich) anzeigen. Das im Ursprungscode vorkommende CreateGraphics sollte überhaupt nicht erscheinen => Ereignis hat nichts mit Malen zu tun und umgekehrt.

    Was das Kommentieren angeht:
    Mit sprechenden Klassen, Variablen und Methodennamen braucht man kaum Kommentare. - wenn sollten sie nur für komplexere Zusammenhänge verwendet werden (Meine Kommentare waren keine guten Beispiele, lagen aber an der Ausgangslage). Beispiel: Anstatt gates verwende [Level]Crossing oder Bahnübergang - wobei man entweder immer englisch oder immer deutsch verwenden sollte.

    Da sich Nummern / Farben der Lokomotiven (Locomotive) während der Existenz nicht ändern, speichere die Informationen in der Klasse selbst und lasse sie sich selbst zeichnen. Das Paint-Ereignis der PictureBox sollte nur noch die Draw-Methoden der Instanzen aufrufen.

    Gruß Elmar


    Montag, 15. April 2013 20:00
    Beantworter
  • Mittwoch, 17. April 2013 13:04