C# Elemente in Liste hinzufügen und auslesen

Terminator2

Erfahrenes Mitglied
Ich habe einen Typ "Element" erstellt:
Code:
   public class Element
    {
        //Dezimalzahlen sind 4-stellig gerundet.
        //Prozentsatz der X1,Y1 Koordinate
        public Decimal Pos1_X;
        public Decimal Pos1_Y;

        //Prozentsatz der X2,Y2 Koordinate
        public Decimal Pos2_X;
        public Decimal Pos2_Y;
    }

Wenn man mit der Maus ein Fenster auf dem Bildschirm aufzieht, wird das Rechteck beim Loslassen der Maus gesichert:
Code:
        private void cameraWindow_MouseDown(object sender, MouseEventArgs e)
        {
            //Nur durchführen, wenn ein neues Fenster gezeichnet werden soll:
            if (DrawingWindow == true)
            {
                //Nur bei linker Maustaste reagieren & voriger Auswahl des Objekttypes:
                if (e.Button == MouseButtons.Left)
                {
                    MausDown = true;
                    list.Add(new Point(e.X, e.Y));
                }

                //Bei rechter Maustaste Vorgang abbrechen:
                if (e.Button == MouseButtons.Right)
                {
                    DrawingWindow = false;
                    MausDown = false;
                    list.Clear();
                    cameraWindow.Invalidate();
                    StatusInfo.Text = "";
                }
            }
        }

        private void cameraWindow_MouseMove(object sender, MouseEventArgs e)
        {
            if (MausDown == true)
            {
                if ((e.X >= 0) & (e.Y >= 0) & (e.X <= cameraWindow.Width) & (e.Y <= cameraWindow.Height))
                {
                    list.Add(new Point(e.X, e.Y));
                }
            }
        }

        private void cameraWindow_MouseUp(object sender, MouseEventArgs e)
        {
            if ((MausDown == true) & (DrawingWindow == true))             //Wenn Maustaste gedrückt war und ein Fenster gezeichnet werden soll
            {
                SaveElement();                                          //Objekt in Bibliothek übernehmen
                list.Clear();                                           //Liste mit Koordinaten leeren
                if (e.Button == MouseButtons.Left) MausDown = false;    //Maustaste losgelassen
                DrawingWindow = false;                                  //Fenster gezeichnet -> fertig
                StatusInfo.Text = "";
            }
        }

        private void SaveElement()
        {
            Element Form = new Element();                               //Ein neues Objekt wird in die Bibliothek eingefügt

            decimal POS;

            //X-WERTE:  Koordinaten nach Größe ordnen und auf 4-stelligen %-Wert runden
            if (list[0].X < list[list.Count - 1].X)
            {
                POS = list[0].X * 100 / cameraWindow.Width;
                Form.Pos1_X = Math.Round(POS, 4);

                POS = list[list.Count - 1].X * 100 / cameraWindow.Width;
                Form.Pos2_X = Math.Round(POS, 4);
            }
            else
            {
                POS = list[0].X * 100 / cameraWindow.Width;
                Form.Pos2_X = Math.Round(POS, 4);

                POS = list[list.Count - 1].X * 100 / cameraWindow.Width;
                Form.Pos1_X = Math.Round(POS, 4);
            }

            //Y-WERTE:  Koordinaten nach Größe ordnen und auf 4-stelligen %-Wert runden
            if (list[0].Y < list[list.Count - 1].Y)
            {
                POS = list[0].Y * 100 / cameraWindow.Height;
                Form.Pos1_Y = Math.Round(POS, 4);

                POS = list[list.Count - 1].Y * 100 / cameraWindow.Height;
                Form.Pos2_Y = Math.Round(POS, 4);
            }
            else
            {
                POS = list[0].Y * 100 / cameraWindow.Height;
                Form.Pos2_Y = Math.Round(POS, 4);

                POS = list[list.Count - 1].Y * 100 / cameraWindow.Height;
                Form.Pos1_Y = Math.Round(POS, 4);
            }

            AlarmWindow.Add(Form);  //Element hinzufügen zur Liste mit allen Alarm-Fenstern
        }

Ich habe absolut keinen Fehler finden können. Die Prozeduren werden außerdem alle vollständig ausgeführt.
Allerdings kann ich die Elemente mit nichts in der Welt wieder weiterverarbeiten...
Hier noch die Deklaration der Liste, die die Elemente enthält:
Code:
    public class MainForm : System.Windows.Forms.Form
    {
        public static MainForm Instance = new MainForm();

        //Variablen
        private Boolean MausDown;
        private Boolean DrawingWindow;
        private readonly List<Point> list;
        public List<Element> AlarmWindow;


Bin leider noch ganz neu in C# und komme nicht mehr weiter, ich hoffe Ihr könnt mir helfen.


Danke!
 
Hi.

1. Warum speicherst du alle Punkte die sich bei MouseMove ansammeln in einer Liste?
Statt deiner Liste "list" würden es 2 Variablen vom Typ Point auch tun. Bei MouseDown setzt du den ersten Punkt, und bei MouseMove überschreibst du den 2. Das sind ja die einzigen interessanten. Deine Liste kann ja durchaus mal etwas lang werden, und beinhaltet nur uninteressante Objekte. :)

2. Was meinst du mit Allerdings kann ich die Elemente mit nichts in der Welt wieder weiterverarbeiten...?

Deine erstellten Element-Objekte liegen in der Liste AlarmWindow, und wenn du damit etwas machen möchtest, musst ja nur auf diese über eben jene Liste zugreifen.

lg, Alex
 
Also zu 1.
Das stimmt natürlich ;) Der Grund für die Liste war der, dass man das Rechteck während des Aufziehens mit der Maus auch sehen sollte. Allerdings braucht man da auch keine Liste für. Ich werde das bei nächster Gelegenheit ändern :)

Und zu 2.
Ich greife in einer anderen Klasse auf diese globalen Variablen zu. Da habe ich den Code vergessen, stelle ich gerade fest. Also hier der Code, mit dem ich gerne auf die Variablen zugreifen würde und dann in meine PictureBox zeichnen will:
Code:
           //Elemente zeichnen               
            for (int i = 0; i <= MainForm.Instance.AlarmWindow.Count - 1; i++)
            {
                //Da die Koordinaten sortiert vorliegen, kann die Breite einfach errechnet werden
                int X1 = (int)MainForm.Instance.AlarmWindow[i].Pos1_X / 100 * MainForm.Instance.cameraWindow.Width;
                int Y1 = (int)MainForm.Instance.AlarmWindow[i].Pos1_Y / 100 * MainForm.Instance.cameraWindow.Height;
                int X2 = (int)MainForm.Instance.AlarmWindow[i].Pos2_X / 100 * MainForm.Instance.cameraWindow.Width;
                int Y2 = (int)MainForm.Instance.AlarmWindow[i].Pos2_Y / 100 * MainForm.Instance.cameraWindow.Height;

                int W = X2 - X1;
                int H = Y2 - Y1;

                Graphics g = pe.Graphics;
                Pen pen = new Pen(rectColor, 1);

                g.DrawRectangle(pen, X1, Y1, W, H);
           }
            g.DrawRectangle(pen, 5, 5, 50, 50);

In dem Code sollen alle Elemente aus der Liste gezeichnet werden. Es erscheint jedoch nichts.
Zur Kontrolle ist der letzte Befehl: Dieses Rechteck wird gezeichnet.
Ich vermute, dass etwas mit der For-Schleife nicht stimmt oder ich falsch auf meine globale Variable zugreife. Fehlermeldungen bekomme ich keine und Haltepunkte kann ich auch nicht setzen.

PS: Wie kann ich Integer Werte bei C# mal eben mit einer MsgBox ausgeben? Bei VB mache ich das öfters wenn ich Probleme habe, hier habe ich jedoch nichts richtiges gefunden, da C# auch ziehmlich oft meckert wenn man Integer nicht zu String konvertiert. Diesen Befehl habe ich auch nicht auffinden können :)

Ich hoffe, dass Ihr mit den Infos etwas mehr anfangen könnt ;)


Gruß David
 
Hi.

Mhm auf den ersten Blick fällt mir jetzt nichts auf, worans scheitern könnte.
Nur ein paar kosmetische Sachen:

1. Bei deiner Schleife kannst du statt "<=" und ".Count -1" auch einfach
C#:
for (int i = 0; i < MainForm.Instance.AlarmWindow.Count ; i++)
schreiben.

2. In deiner Schleife hast du
C#:
Graphics g = pe.Graphics;
Pen pen = new Pen(rectColor, 1);

Das kann vor die Schleife! (Also bevor dem "for") Du musst das, vorallem den Stift, nicht jedes mal neu erstellen. (bzw zuweisen beim Graphics Objekt)

3. Bei Pen sollte Dispose aufgerufen werden, wenns nicht mehr benutzt wird.

PS: Wie kann ich Integer Werte bei C# mal eben mit einer MsgBox ausgeben?

Unter anderem so:
C#:
int i = 5;
MessageBox.Show(i.ToString());

lg,.. :)
 
hey,

Habe alles soweit geändert.
Das mit der MessageBox würde es normalerweise tun, aber die Meldung wird gar nicht gesendet. Das wundert mich wirklich sehr...
Hier erstmal mein aktueller Code:
Code:
			Graphics	g = pe.Graphics;
			Pen			pen = new Pen( rectColor, 1 );

            for (int i = 0; i < MainForm.Instance.AlarmWindow.Count; i++)
            {
                //Da die Koordinaten sortiert vorliegen, kann die Breite einfach errechnet werden
                int X1 = (int)MainForm.Instance.AlarmWindow[i].Pos1_X / 100 * MainForm.Instance.cameraWindow.Width;
                int Y1 = (int)MainForm.Instance.AlarmWindow[i].Pos1_Y / 100 * MainForm.Instance.cameraWindow.Height;
                int X2 = (int)MainForm.Instance.AlarmWindow[i].Pos2_X / 100 * MainForm.Instance.cameraWindow.Width;
                int Y2 = (int)MainForm.Instance.AlarmWindow[i].Pos2_Y / 100 * MainForm.Instance.cameraWindow.Height;

                int W = X2 - X1;
                int H = Y2 - Y1;

                MessageBox.Show(X1.ToString());
                
                g.DrawRectangle(pen, X1, Y1, W, H);
           }
            g.DrawRectangle(pen, 5, 5, 50, 50);
            
			pen.Dispose( );

Das merkwürdige ist ja, dass dieses Rechteck nach der For-Schleife gezeichnet wird und die Befehle in der For-Schleife scheinbar gar nicht beachtet werden... Woran kann das denn liegen? Vielleicht ist die Liste immer leer oÄ.

@Alex,
Soll ich dir das Projekt vielleicht mal zusenden?
 
Hm..

Dann mach mal folgendes

C#:
MessageBox.Show(MainForm.Instance.AlarmWindow.Count.ToString());

for (int i = 0; i < MainForm.Instance.AlarmWindow.Count; i++)
{

Scheinbar bekommst du da nichts rein... dürfte also 0 sein. Vielleicht hilft dir das beim Debuggen.

Und nein, bitte nicht zuschicken. Wenn könntest es an einen Beitrag anhängen,.. aber ich hab grad nicht wirklich Zeit da ganz drüber zu sehen..

Probier da mal rum, und versuch rauszufinden, warum da nichts in deine Liste reinkommt. (Auch mal mit Haltepunkten in deinen Eventhandlern wo die Objekte erstellt werden zum Beispiel)

lg,..
 
Habe nochmal was weiterprobiert.
Ich vermute, das hat mit der globelen Deklaration der Variablen zu tun. ich habe das neue Element einmal einfach zu "AlarmWindow" hinzugefügt und ein anderes Mal zu "MainForm.Instance.AlarmWindow". Die beiden Variablen müssten identisch sein, sind sie aber nicht...

Hier nochmal der Deklarationsbefehl:
Code:
    public class MainForm : System.Windows.Forms.Form
    {
        public static MainForm Instance = new MainForm();

        //Variablen
        private Boolean MausDown;
        private Boolean DrawingWindow;
        private List<Point> list = new List<Point>();
        public List<Element> AlarmWindow=new List<Element>();

Ich habe das nur im Internet gefunden, bin aber etwas verwirrt, warum das hier so schwierig ist... Dieses new MainForm erzeugt doch alles ein zweites Mal oder?


Gruß David
 
Argh! :)

Ja, das passt nicht. Du schreibst dort Instance = new MainForm();. Damit erzeugst du eine neue Instanz von deinem Fenster. Du siehst das nur nicht, weil Show nicht augerufen wird, deswegen ist das Fenster nicht sichtbar.

Mach das eher so:

C#:
public static MainForm Instance;

// und im Konstruktor:
public MainForm()
{
  MainForm.Instance = this;
  //.. rest
}

Klappt dann eher.. ;)

Übrigens.. du machst vieles mit öffentlichen Membern in deinen Klassen. Schau dir mal Properties an.
 
Die Sache mit den Properties werde ich mir mal genau anschauen ;)

Hab die Sachen jetzt geändert, die du gepostet hast. Damit klappt es schon um einiges besser. Jetzt greife ich immer auf das richtige Element zu.
Die Anzahl der Elemente wird auch größer wenn ich neue Fenster aufziehe, so wie gewollt.
Jetzt habe ich noch weitergetestet und soeben festgestellt, dass meine Umrechnung von Prozentwerten in Koordinaten nicht funktioniert:
Code:
decimal W_korrektur = 1 / 100 * MainForm.Instance.cameraWindow.Width; //Ergibt immer 0, Breite des Fensters jedoch 321

Vielleicht habe ich da etwas falsch umgewandelt?!


Gruß David und schon einmal ein großes Lob an deine Hilfe, wäre nie auf die Fehler gekommen :)

EDIT:

Habe den Fehler nun selbst gefunden und behoben. Konvertieren war das Stichwort. Man muss tatsächlich selbst die Zahl 1 in Decimal konvertieren, um damit rechnen zu können... Das war ich von Visual Basic wirklich nicht gewohnt. Hier nun der Befehl von oben korrigiert:
Code:
decimal W_korrektur = (decimal)1 / (decimal)100 * (decimal)MainForm.Instance.cameraWindow.Width;

Edit 2:

Habe noch eine Fehlermeldung beim Öffnen des Designers:

Das Steuerelement motion.CameraWindow hat eine unbehandelte Ausnahme im Designer ausgelöst und wurde deaktiviert.
Ausnahme:
Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
Stapelüberwachung:
bei motion.CameraWindow.OnPaint(PaintEventArgs pe)

Der Fehler war anfangs nicht da. Ich glaube dass er erst kam, als ich diese globalen Variablen gesetzt habe...
Hier noch die Funktion OnPaint ohne ihren Inhalt:

Code:
protected override void OnPaint(PaintEventArgs pe)
        {
        }
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück