stargazer
Goto Top

CSharp Objekte !zufällig! sichtbar machen

Hallo zusammen!

Ich habe mal wieder ein kleines Problemchen. Ich möchte diesmal mit C# eine Tix-Clock programmiren. Dazu habe ich insgesamt vier "Spalten" mit verschiedener Anzahl Blöcken erstellt (1x3, 3x3, 2x3, 3x3).
In jedem Block befindet sich eine Grafik, die bei Programmstart unsichtbar ist. Sobald das Programm gestartet wird wird ein Timer ausgelöst, der im Sekundentakt die Uhrzeit ausliest und dann die Uhrzeit ausgeben soll.
So weit so gut, aber leider klappt das alles noch nicht so ganz. Bei der Tix-Clock wird jede Sekunde auch ein neues, zufälliges "Muster" in jedem Block ausgegeben, welches natürlich auf der aktuellen Uhrzeit basiert.
Ich hab also zuerst versucht mittels Bedingungssätzen jedes mal ein neues Muster zu erzeugen, doch da habe ich schon nach kürzester Zeit den überblick verloren.
Meine Frage also: kann ich mehrere zufällige Objekte sichtbar machen, ohne eine gigantische if-Struktur aufzubauen?

Auslesen der Uhrzeit:


DateTime currentDate = DateTime.Now;
int dtHour = currentDate.Hour;
int dtMinute = currentDate.Minute;
int dtSecond = currentDate.Second;

Da ich noch keine zufälligen Strings generieren kann hab ich zuerst angefangen random Zahlen auszugeben.

private int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}

Ich habe den Grafiken jeweils eindeutige Namen zugeteilt (daher die 4. Grafik in der 2. Spalte heißt z.B. Image2x4). Jetzt hatte ich mir erhofft über die zufällige Zahl direkt den Namen generieren zu können (was aber nicht klappte - hier nochmal der code).

String ch1 = new String;
int num0 = RandomNumber(1, 9);
ch1 = "Image2x" + num0;
if (dtHour == 15) {
if (num0 == 1) {
ch1.Visibility = Vilibility.Visible; }}


So einfach war es nunmal leider nicht. Aber ich denke irgendwas derartiges muss es doch geben, oder irgendeine Alternative?
Falls ihr eine Idee habt, lasst mich es bitte wissen!

Schöne Grüße

stargazer

Content-ID: 169867

Url: https://administrator.de/contentid/169867

Ausgedruckt am: 25.11.2024 um 16:11 Uhr

dog
dog 16.07.2011 um 20:41:35 Uhr
Goto Top
ch1 = "Image2x" + num0;

In einer statischen Programmiersprache wie C# wird das niemals gehen.

Schau dir mal mehrdimensionale Arrays an.
stargazer
stargazer 16.07.2011 um 21:04:51 Uhr
Goto Top
Alles klar, ich schau mal^^
Ach ja, würde es evtl mehr Sinn machen, die Position der Einzelnen Images zu Randomisieren?

Stargazer
dog
dog 16.07.2011 um 21:28:51 Uhr
Goto Top
Ach ja, würde es evtl mehr Sinn machen, die Position der Einzelnen Images zu Randomisieren?

Wenn du es dir absichtlich kompliziert machen willst, ja.
Jenna86
Jenna86 17.07.2011 um 11:14:56 Uhr
Goto Top
Hi stargazer,

Also ich bin mir nicht sicher, ob ich dich richtig verstanden habe.

Aber so ein "zufälliges" ändern der Sichtbarkeit von verschiedenen Objekten würde ich schon über ein Array machen, in dem sich die Objekte befinden.
Der Index ist dann zufällig und dadurch kommst du immer wieder an eins deiner Objekte ran.
Dann würde ich halt die Sichtbarkeit des Objektes auf true setzen und vor dem jeweiligen setzen auf true jede Sekunde hingehen und vorher komplett alles auf "false" setzen um den Ausgangszustand zurückzubekommen.

Also nochmal kurzfassung:

Jeder Spalte ein Array aus Blöcken zuweisen.
Alle Blöcke invisible setzen
Arrayindex per Zufall auswählen lassen und auf visible setzen ( du kannst natürlich auch zufällig viele Blöcke sichtbar machen über eine zweite Zufallszahl. Also eine Zufallszahl jeweils für den Index und eine Zufallszahl für die Anzahl der Durchgänge, in denen du einen zufälligen Block sichtbar machst )
Und das machst du einfach durchgehend, solltest aber vor jedem neuen Sichtbarmachen eben vorher alles "resetten".

Ich hoffe ich habe das Problem so halbwegs verstanden.

Wie hast du den Timer hingebogen? Du kannst die interne Klasse Timer benutzen, die dann in einem festgelegten Intervall ein Event "Tick" auslöst. So kannst du z.B. den Intervall auf 1000ms setzen und dann jedesmal deine Logik ausführen lassen.

Grüße
Jens
stargazer
stargazer 17.07.2011 um 15:15:11 Uhr
Goto Top
Das mit dem Timer ist bereits eingerichtet:

private void TimerTicker(Object ReadoutTimer, EventArgs myEventArgs)
{
DateTime currentDate = DateTime.Now;
int dtHour = currentDate.Hour;
int dtMinute = currentDate.Minute;
int dtSecond = currentDate.Second;
Image1x1.Visibility = Visibility.Hidden;
Image1x2.Visibility = Visibility.Hidden;
Image1x3.Visibility = Visibility.Hidden;
Image2x1.Visibility = Visibility.Hidden;
Image2x2.Visibility = Visibility.Hidden;
...

und

private void Window_Loaded(object sender, RoutedEventArgs e)
{
var ReadoutTimer = new Timer();
ReadoutTimer.Interval = 1000;
ReadoutTimer.Enabled = true;
ReadoutTimer.Tick += new EventHandler(TimerTicker);
}

Ich gucke zur Zeit nach den arreys, aber hab deren Funktionsweise noch nicht so ganz verstanden. Ich werds einfach mal versuchen, wenn Fragen aufkommen meld ich mich nochmal :D


Vielen Dank für die Hilfe!


stargazer
Jenna86
Jenna86 17.07.2011 um 17:34:45 Uhr
Goto Top
Okay, alles klar. Ich glaube ich habe grad etwas Langeweile und hab mal nach der Uhr gegooglet.

Ich glaub ich probier das auchmal fix zu implementieren, aber ich werds denke ich statt mit irgendwelchen Buttons oder ähnlichen Dingen direkt mit nem Panel machen, in welches ich zeichne. Falls ich da heute Abend noch was mache und zu was komme, lass ich dich wissen, wie ichs gelöst habe.

Grüße

EDIT (ein paar Denkanstöße):

Anstelle von blanken int-Werten benutze ich lieber Enums.
        enum Pos
        {
            HourFirst,
            HourLast,
            MinuteFirst,
            MinuteLast
        }

Hiermit bekomme ich die Anzahl an Punkten, die im jeweiligen Feld dargestellt werden soll.
        private int getPointsToDraw(int charOfTime)
        {
            int pointsToDraw = 0;

            switch (charOfTime)
            {
                case (int)Pos.HourFirst:
                        pointsToDraw = DateTime.Now.Hour / 10;
                    break;
                case (int)Pos.HourLast:
                        pointsToDraw = DateTime.Now.Hour % 10;
                    break;
                case (int)Pos.MinuteFirst:
                    pointsToDraw = DateTime.Now.Minute / 10;
                    break;
                case (int)Pos.MinuteLast:
                    pointsToDraw = DateTime.Now.Minute % 10;
                    break;
            }
            return pointsToDraw;
        }

Die Methode liefert mir eine ArrayListe, welche die Position für das jeweilige Rechteck liefert
        private ArrayList randomizePositions(int numberofpositions, int numberofshownrecs)
        {
            Random rand = new Random(DateTime.Now.Millisecond);
            ArrayList positions = new ArrayList();
            int tmp = 0;

            //get random position(s) for this field
            for (int i = 0; i < numberofshownrecs; i++)
            {
                while (true)
                {
                    tmp = rand.Next(0, numberofpositions);
                    if (!positions.Contains(tmp))
                    {
                        positions.Add(tmp);
                        break;
                    }
                }
            }

            return positions;
        }

Und schlussendlich die Zeichenmethode. Über das bisschen Mathe um den Index fürs Zeichnen zu berechnen könntest du statt nen Index für die Zeichenmethode auch nen Index für nen Array benutzen.
        private void draw()
        {
            ArrayList positions = new ArrayList();

            //fields for first char of hours ( 1*3 field )
            positions = randomizePositions(3, getPointsToDraw((int)Pos.HourFirst));
            for (int i = 0; i < positions.Count; i++)
            {
                g.FillRectangle(Brushes.Red, new Rectangle(_HOURSPOS_X,
                    (int)positions[i] *(_HEIGHT+_PLACEBETWEENITEMS)+_HOURSPOS_Y, 
                    _WIDTH, 
                    _HEIGHT));
            }

            //fields for the second char ( 3*3 field )
            positions = randomizePositions(9, getPointsToDraw((int)Pos.HourLast));
            for (int i = 0; i < positions.Count; i++)
            {
                g.FillRectangle(Brushes.Orange, 
                    new Rectangle(_HOURSPOS_X + (_WIDTH + _PLACEBETWEENITEMS) + ((int)positions[i] / 3 * (_WIDTH + _PLACEBETWEENITEMS)),
                    (int)positions[i] % 3 * (_HEIGHT + _PLACEBETWEENITEMS) + _HOURSPOS_Y, 
                    _WIDTH, 
                    _HEIGHT
                    ));
            }

            //fields for the third char ( 2*3 field )
            positions = randomizePositions(6, getPointsToDraw((int)Pos.MinuteFirst));
            for (int i = 0; i < positions.Count; i++)
            {
                g.FillRectangle(Brushes.Black,
                    new Rectangle(_HOURSPOS_X + 4 * (_WIDTH + _PLACEBETWEENITEMS) + ((int)positions[i] / 3 * (_WIDTH + _PLACEBETWEENITEMS)),
                    (int)positions[i] % 3 * (_HEIGHT + _PLACEBETWEENITEMS) + _HOURSPOS_Y,
                    _WIDTH,
                    _HEIGHT
                    ));
            }

            //fields for the forth char ( 3*3 field )
            positions = randomizePositions(9, getPointsToDraw((int)Pos.MinuteLast));
            for (int i = 0; i < positions.Count; i++)
            {
                g.FillRectangle(Brushes.Blue,
                    new Rectangle(_HOURSPOS_X + 6 * (_WIDTH + _PLACEBETWEENITEMS) + ((int)positions[i] / 3 * (_WIDTH + _PLACEBETWEENITEMS)),
                    (int)positions[i] % 3 * (_HEIGHT + _PLACEBETWEENITEMS) + _HOURSPOS_Y,
                    _WIDTH,
                    _HEIGHT
                    ));
            }   
        }

Ich denke, dass dir das schonmal deutlich weiterhelfen sollte.
Falls du noch Rückfragen hast, dann lass michs wissen.

Grüße
Jens
Jenna86
Jenna86 17.07.2011 um 20:24:51 Uhr
Goto Top
Ich habe hier mal mein Beispiel fix als *.exe hochgeladen, damit du dir visuell vorstellen kannst, was da passiert:

http://www.file-upload.net/download-3592987/TixClock.exe.html

Grüße
Jenna86
Jenna86 17.07.2011 um 22:52:37 Uhr
Goto Top
Zitat von @stargazer:
Ich gucke zur Zeit nach den arreys, aber hab deren Funktionsweise noch nicht so ganz verstanden. Ich werds einfach mal versuchen,
wenn Fragen aufkommen meld ich mich nochmal :D


Vielen Dank für die Hilfe!


stargazer

Heyho, also schon wieder ich.
Das hat mir jetzt keine Ruhe gelassen xD
Ich zeig dir nochmal eine Möglichkeit, wie man das mit z.B. PictureBoxen machen könnte.

- Zu allererst erstellst du dir ( am Besten automatisiert ) ein Array mit neuen PictureBoxen.
Da dich das aber eventuell überfordert hab ich mir tatsächlich mal die Arbeit gemacht das alles zu tippen
- anschließend werden die Positionen wie schon bekannt per Zufall gesetzt ( wie im "alten" Beispiel )
- die draw() Methode oder wie ich sie nannte musst du nun etwas anpassen. Dazu zeige ich dir fix noch ein paar Codefetzen.

Die im Designer erstellten PictureBox(en) in die arrays füllen ( ein Array pro Box )
        private void initPictureBoxArrays()
        {
            hour1 = new PictureBox[3];
            hour1 = pictureBox1;
            hour1[1] = pictureBox2;
            hour1[2] = pictureBox3;

            hour2 = new PictureBox[9];
            hour2 = pictureBox4;
            hour2[1] = pictureBox5;
            hour2[2] = pictureBox6;
            hour2[3] = pictureBox7;
            hour2[4] = pictureBox8;
            hour2[5] = pictureBox9;
            hour2[6] = pictureBox10;
            hour2[7] = pictureBox11;
            hour2[8] = pictureBox12;

            min1 = new PictureBox[6];
            min1 = pictureBox13;
            min1[1] = pictureBox14;
            min1[2] = pictureBox15;
            min1[3] = pictureBox16;
            min1[4] = pictureBox17;
            min1[5] = pictureBox18;

            min2 = new PictureBox[9];
            min2 = pictureBox19;
            min2[1] = pictureBox20;
            min2[2] = pictureBox21;
            min2[3] = pictureBox22;
            min2[4] = pictureBox23;
            min2[5] = pictureBox24;
            min2[6] = pictureBox25;
            min2[7] = pictureBox26;
            min2[8] = pictureBox27;
        }

Die resetView() Methode, die dir vor jedem neuen Schritt die default-Ansicht wieder herstellt
Er nimmt sich einfach alle PictureBox-Objekte, die in der Form existieren. Das erspart einiges an Arbeit im Vergleich zum manellen Setzen

        private void resetView()
        {
            foreach (PictureBox pictb in this.Controls.OfType<PictureBox>())
            {
                pictb.Image = imageDefault;
            }
        }

Und nun die neue updateView()-Methode ( vorher draw-Methode ). Hier werden nun die Zufallszahlen nichtmehr zur Positionsberechnung ( wie oben ) verwendet, sondern sie geben den Index der PictureBox an, die verändert werden soll
        private void updateView()
        {
            resetView();
            ArrayList positions = new ArrayList();
            //box1
            positions = randomizePositions(3,getPointsToDraw((int)Pos.HourFirst));
            for (int i = 0; i < positions.Count; i++)
            {
                hour1[(int)positions[i]].Image = imageSet;
            }
            //box2
            positions = randomizePositions(9, getPointsToDraw((int)Pos.HourLast));
            for (int i = 0; i < positions.Count; i++)
            {
                hour2[(int)positions[i]].Image = imageSet;
            }
            //box3
            positions = randomizePositions(6, getPointsToDraw((int)Pos.MinuteFirst));
            for (int i = 0; i < positions.Count; i++)
            {
                min1[(int)positions[i]].Image = imageSet;
            }
            //box4
            positions = randomizePositions(9, getPointsToDraw((int)Pos.MinuteLast));
            for (int i = 0; i < positions.Count; i++)
            {
                min2[(int)positions[i]].Image = imageSet;
            } 
        }

Was für dich in dem Zusammenhang vielleicht noch interessant ist wäre wie man ne Bitmap benutzt um sie hier zu benutzen.
Ich habe dazu das Bild ( bmp ) als Ressource eingebunden ( Dann wird sie, wenn gewünscht in die *.exe gepackt und du hast nur eine Datei ).
-> Rechtsklick auf das Projekt -> Eigenschaften -> Ressourcen -> Hinzufügen -> Aus Datei oder so

Anschließend kannst du diese Ressourcen im Code nutzen über "Resources.XXX". Dafür ist es sinnvoll über die using-Direktive die Properties einzubinden. "using PROJEKTNAME.Properties;"

Jetzt kannst du ein Image zum Beispiel so initialisieren:

        Image imageSet;
        Image imageDefault;

        public TixWithImages()
        {
            InitializeComponent();
            imageSet = Resources.set;                            <<<<<<--------
            imageDefault = Resources._default;            <<<<<<--------
            initPictureBoxArrays();
            resetView();
            timer.Start();
        }

Sohoo, ###e, wenn das Wetter so schlecht ist, dass man mit SAT keinen Empfang hat und dann nach "Beschäftigung" sucht :D

Sorry, falls das schon zu ausführlich war, letzten Endes hast du ja jetzt ein komplett lauffähiges Programm.

Bitteschön,
"Jenna"

EDIT:

Du kannst natürlich statt da nen Image jedesmal zu setzen auch hingehen und die Sichtbarkeit ändern. Also du könntest auch generell überall nur ein Bild anzeigen lassen und dann statt die Bilder zu ändern das Element eben unsichtbar und sichtbar machen. Das wäre ja dann g enau das, was du eigentlich wolltest denke ich mal.
stargazer
stargazer 17.07.2011 um 23:23:31 Uhr
Goto Top
Hi Jenna!

Wow. Erstmal vielen Dank für diesen Code, werds gleich mal ausprobieren und versuchen zu verstehen :D

- Zu allererst erstellst du dir ( am Besten automatisiert ) ein Array mit neuen PictureBoxen.
Da dich das aber eventuell überfordert hab ich mir tatsächlich mal die Arbeit gemacht das alles zu tippen ^^

Leider wahr. Fange demnächst mit meiner MATSE-Ausbildung an und hoffe, dass ich spätestens dann in der Lage bin sowas zu schreiben ;)


Ich lese mich mal durch!


Schöne Grüße

stargazer
Jenna86
Jenna86 17.07.2011 um 23:34:14 Uhr
Goto Top
Zitat von @stargazer:
Hi Jenna!

Wow. Erstmal vielen Dank für diesen Code, werds gleich mal ausprobieren und versuchen zu verstehen :D

> - Zu allererst erstellst du dir ( am Besten automatisiert ) ein Array mit neuen PictureBoxen.
> Da dich das aber eventuell überfordert hab ich mir tatsächlich mal die Arbeit gemacht das alles zu tippen ^^

Leider wahr. Fange demnächst mit meiner MATSE-Ausbildung an und hoffe, dass ich spätestens dann in der Lage bin sowas zu
schreiben ;)


Ich lese mich mal durch!


Schöne Grüße

stargazer

Na dann viel Spaß beim Durchlesen <:
Falls Rückfragen bleiben sollten, dann frag einfach.

Eine kurze Rückmeldung über einen Erfolg würde mich auch freuen ( damit man sieht, dass sich die "Arbeit" auch gelohnt hat ) ;)

Auf jeden Fall gern geschehen. Mich würde dennoch interessieren, ob die Lösung mit zweidimensionalen Arrays wirklich leichter und unkomplizierter sein sollte als nen verschieben der Boxen. Die komplette Logik, die man dafür braucht ist imho die gleiche Logik wie bei meinem Vorschlag des Zeichnens im Panel.
Also ein "kleiner" Denkanstoß von "dog" wäre nett, damit ich auch die Trivialität des Vorschlags mit den mehrdimensionalen Arrays verstehe (da ich sie aktuell nicht sehe, da in meinen Augen auch einfache Arrays, wie jetzt hier im zweiten Vorschlag genutzt wesentlich simpler erscheinen )
stargazer
stargazer 18.07.2011 um 01:15:33 Uhr
Goto Top
Nochmals Hallo,

ich hab mir den Code mal durchgelesen und versucht in meiner Anwendung nachzubauen, aber leider ohne Erfolg. Ich muss allerdings gestehen, dass ich den Code auch nicht wirklich verstehe (hab ja quasi noch nie mit sowas gearbetet ._.), vielleicht liegt das aber auch einfach daran, dass es langsam spät wird und ich sowieso nicht mehr so ganz durchblicke.

Desweiteren gibt es ein Problem mit dem erstellen Randomer Zahlen, denn wenn ich mehrere Zahlen zugleich generieren lasse (die den selben bereich z.B. 1-10 haben) kommt bei allen die selbe Zahl raus.
Ich hab auch schon überlegt anstelle von zufälligen Kombinationen selbige über if-Ketten festzulegen, aber dafür müsste ich mind. 1440 if-Sätze erstellen und für jeden eine Kombination ausdenken, was die Sache auch nicht wirklich einfacher macht.

Ich werde mich morgen nochmal dransetzen, vielleicht bekomme ich dann ja was Gescheites hin.

Außerdem hab ich hier ( http://www.mediafire.com/?ggwj6cpqga53sg2 ) mal das komplette Projekt hochgeladen, falls Interesse besteht.

Schönen Abend noch / Gute Nacht!


stargazer
Jenna86
Jenna86 18.07.2011 um 15:14:33 Uhr
Goto Top
Das mit den anfangs immer gleichen Zufallszahlen liegt daran, dass es keine "echten" Zufallszahlen sind, sondern eine Zufallszahlensequenz ist, welche mit einem Startwert initialisiert wird. Dazu gibt es aber einiges auf Google glaube ich.
Stichwort "bessere Zufallszahlen C#" oder so. Ich habe leider gerade keine Zeit um mal drüberzugucken, hab doch grad gut was zu tun.
Wenn Beispielsweise der Zufallszahlengenerator mit einer Zeit initialisiert wird und du ohne, dass sich die Zeit ändert mehrfach eine Zufallszahl möchtest, so wird diese immer gleich sein ( wenn ich mich recht erinnere ).

Dass das "Nachbauen" nicht immer hinhaut kann dran liegen, dass deine Variablen anders deklariert sind oder du nur Variablennamen übernimmst, die du vorher nirgends benannt hast.

Wenn du also z.B.:

variable1 = "bla"; schreibst, aber nirgends

String variable1; deklariert hast, dann wirst du einen Fehler bekommen, dass die Variable unbekannt ist oder ähnliches.


Falls ich heute Abend noch Lust haben sollte versuche ich mir deine bisherige Leistung nochmal anzuschauen, ich kann aber nichts versprechen, da ich wie gesagt grad ziemlich was zu tun habe.

Grüße
"Jenna"
stargazer
stargazer 18.07.2011 um 15:34:47 Uhr
Goto Top
Hi Jenna,

nochmal vielen Dank, dass du dich da so reinhängst! Hoffe nur, dass all deine Mühe am Ende nicht vergebens ist.
Ich hab in der Zwischenzeit mal angefangen die Uhrzeit auseinander zu pflücken - natürlich wieder mittels Bedingungssätzen. Immerhin habe ich jetzt folgende Werte aufgestellt:

hour1: Gibt den Wert der ersten Ziffer der Stunde aus
hour2: Gibt jeweils den Wert der zweiten Ziffer der Stunde aus
min1: das selbe wie hour1 nur für minuten aus
min2: hour2 für minuten

Ob das so Sinnvoller ist als vorher weiß ich allerdings nicht, aber jetzt muss ich das schonmal nicht jedes mal Manuell machen.

Das mit den Zufallszahlen werd ich mir nochmal anguggn, danke für den Hinweis! Soweit ich mich erinnern kann gab es bei anderen Programmen (z.B. Borland C++ Builder) bezüglich der Randomisierung irgendwie weniger Probleme, oder ich habs einfach nur anders in Erinnerung - wie auch immer.

Ich wünsche noch einen angenehmen Montag!

stargazer
Jenna86
Jenna86 18.07.2011 um 18:44:47 Uhr
Goto Top
Ich glaube das Wichtigste überhaupt beim Programmieren ist, dass man vorher schon einen "Plan" hat, wie man was lösen möchte.

Ich würde die ganze Uhr mal in verschiedene Teilprobleme unterteilen:

- Anzahl an Punkten pro Box ermitteln
- Anordnung der Punkte per Zufall setzen
- Event, welches jeweils nach einer Sekunde ausgelöst wird und alles zeichnet.

Wenn du das geschafft hast kannst du dir Gedanken drüber machen, wie konkret du das Lösen möchtest

- Anzahl an Punkten pro Box ermitteln:
Für jede Ziffer der Uhrzeit den Wert bestimmen und mit diesem Wert dann die Anzahl der zu zeichnenden Quadrate in jeder Box festlegen
Hierzu einfach etwas Mathe:
Ist eine Zahl größer als 10 und man möchte wissen wie oft sie vorkommt teilt man durch 10. Getreu dem Motto "radieren wir einfach eine Stelle aus". Da C# beim Teilen von int-Variablen keinen Rest berücksichtigt ist das für uns schonmal gut.
Dadurch wird aus 11 / 10 = 1 oder aus 23 / 10 = 2
Die zweite Ziffer die wir wollen ist der Rest, der und bei dieser Teilung abhanden kommt. Diesen Rest bestimmen wir durch eine Modulu Operation.
Hier wird aus 11 % 10 = 1 Rest >1<
Oder aus 23 % 10 = 2 Rest >3<
Bei der Modulu Operation wird also nur der Rest als Ergebnis eingetragen.

- Anordnung der Punkte per Zufall setzen:
Ein Array, dessen Länge die Anzahl der zu zeichnenden Punkte bestimmt
und die Werte des Arrays, die die Position bestimmen
Heißt, ich habe z.B. ein Array der Länge 5, welches 5 Zufallszahlen enthalten soll für die Position.
Jetzt kann ich über eine Schleife die Positionen 1-5 bzw. die Indizes 0-4 durchlaufen und habe so für jeden Punkt der gespeichert ist den Zugriff auf die Position

for (int i = 0 ; i < array.Length ; i++ )
{
PositionDesPunktes = array[i];
}


- Event
TimerObjekt, ich denke, dass das keiner weiteren Klärung bedarf.

Grüße aus dem ( fast leeren ) Büro ^^
Jenna86
Jenna86 18.07.2011 um 20:49:06 Uhr
Goto Top
Also, wenn ich deinen Code so sehe solltest du zu aller erst wirklich versuchen dich mit grundlegenen Sachen wie der Schleifenprogrammierung auseinanderzusetzen etc.

Du solltest verstehen, dass man anstatt jedes Objekt einzeln zu bennen auch in ein Array ablegen kann und es dort über den Index ansteuern kann, statt über den Namen.

Zu deinem Code:
xaml, hmm. Okay, kenne ich in der Form auch noch nicht, aber grundlegend gibts ja die gleichen Methoden, man muss sie nur finden.

Folgendes:
-Arrays anlegen ( ist wirklich nahezu 1:1 wie ich es gemacht habe, halt.. nein, es ist 1:1 so ). Wo war die Schwierigkeit?

Instanzvariable:
System.Windows.Controls.Image block1,block2,block3,block4;

Arrays initialisieren:
        private void initArrays()
        {
            block1 = new System.Windows.Controls.Image[3];
            block1 = Image1x1;
            block1[1] = Image1x2;
            block1[2] = Image1x3;

            block2 = new System.Windows.Controls.Image[9];
            //uswusf
        }

Array benutzen:
//Einfacher Test für 11:11
            int num0 = RandomNumber(1, 4);
            int num1 = RandomNumber(1, 10);
            int num2 = RandomNumber(1, 6);
            int num3 = RandomNumber(1, 10);

            // dieser Aufruf ruft das Bild mit Index num0 auf und setzt die Sichtbarkeit
            // Ist num0 = 1 wird das Bild mit Index 1 gesetzt etc ( Allerdings musst du dann deine Zufallszahlen
            // bei 0 beginnen lassen.
            block1[num0].Visibility = Visibility.Visible;

            // dieser Aufruf ersetzt alles folgende:
            if (num0 == 1)
                Image1x1.Visibility = Visibility.Visible;
            if (num0 == 2)
                Image1x2.Visibility = Visibility.Visible;
            if (num0 == 3)
                Image1x3.Visibility = Visibility.Visible;

            //entsprechend fortfahren, dann kannst du die methoden von mir nutzen und nach und nach einbauen
            //die randomizePosition oder wie sie hieß ist dann dafür da, wenn du mehrere Positionen per Zufall               bestimmen willst

Also, schau dir das nochmal an.
Ich glaube wirklich, dass man noch mehr Hilfe garnicht geben kann.

Wie g ewohnt, bei Rückfragen einfach Fragen
stargazer
stargazer 19.07.2011 um 18:51:13 Uhr
Goto Top
Hi Jenna,

ich bin leider immer noch nicht in der Lage den Code zu verstehen. Allerdings liegt das nicht am Code selber, sondern an der Rückmeldung, die das Programm mir gibt, denn wenn ich wie hier...

private void initArrays()
{
block1 = new System.Windows.Controls.Image[3];
block1 = Image1x1;
block1[1] = Image1x2;
block1[2] = Image1x3;

block2 = new System.Windows.Controls.Image[9];
uswusf
}


...versuche ein Array zu initialisieren bekomme ich "Der Name 'block1' ist im aktuellen Kontext nicht vorhanden." (Selbiges Problem hatte ich auch im vorigen "PictureBox"-Array-Beispiel, daher konnte ich auch dort nicht nachvollziehen, was du eigentlich gemacht hast...) Muss ich die Namen vielleicht noch vorher irgendwie definieren? Wie gesagt, ich hab kein Plan von Arrays :/


Also hab ich mal ein wenig experimentiert und bin auf das hier gekommen:


private void initArrays()
{
System.Windows.Controls.Image block1 = new System.Windows.Controls.Image[3] { Image1x1, Image1x2, Image1x3 };
System.Windows.Controls.Image block2 = new System.Windows.Controls.Image[9] { Image2x1, Image2x2, Image2x3, Image2x4, Image2x5, Image2x6, Image2x7, Image2x8, Image2x9 };
System.Windows.Controls.Image block3 = new System.Windows.Controls.Image[6] { Image3x1, Image3x2, Image3x3, Image3x4, Image3x5, Image3x6 };
System.Windows.Controls.Image block4 = new System.Windows.Controls.Image[9] { Image4x1, Image4x2, Image4x3, Image4x4, Image4x5, Image4x6, Image4x7, Image4x8, Image4x9 };
}

Danach hab ich das Random-System etwas verändert, um einigermaßen randome Zahlen zu erschaffen. Über 4 Timer wird nun in unterschiedlichen Abständen jeweils eine Zahl generiert.

Jetzt wollte ich also mal schnell diesen code ( block1[num0].Visibility = Visibility.Visible; ) in den Timer einbauen, aber leider bekam ich auch hier nun die selbe Fehlermeldung wie vorhin: "Der Name 'block1' ist im aktuellen Kontext nicht vorhanden."

Wie gehe ich diesbezüglich vor?


EDIT


hab den ganzen code
System.Windows.Controls.Image block1 = new System.Windows.Controls.Image[3] { Image1x1, Image1x2, Image1x3 };
System.Windows.Controls.Image block2 = new System.Windows.Controls.Image[9] { Image2x1, Image2x2, Image2x3, Image2x4, Image2x5, Image2x6, Image2x7, Image2x8, Image2x9 };
System.Windows.Controls.Image block3 = new System.Windows.Controls.Image[6] { Image3x1, Image3x2, Image3x3, Image3x4, Image3x5, Image3x6 };
System.Windows.Controls.Image block4 = new System.Windows.Controls.Image[9] { Image4x1, Image4x2, Image4x3, Image4x4, Image4x5, Image4x6, Image4x7, Image4x8, Image4x9 };
nun einfach in die Timerfunktion gepackt, jetzt gehts Problemlos.

Wie gehe ich nun am besten vor, wenn ich mehrere pro Block zugleich Sichtbar machen will? Bedingungssätze oder lieder neues Array?


grüße

stargazer


EDIT 2

Hab die Instanzvariable übersehen haha, nochmal von vorn!


EDIT 3

Hab nun alles so gemacht, wie es Sinn ergibt, es tritt jedoch ein runtime error auf ( Eine nicht behandelte Ausnahme des Typs "System.NullReferenceException" ist in Tix Clock.exe aufgetreten ), weshalb ich doch die ganze Arrayerstellung in den Timer versetzt habe. Nun fehlt mir nur noch eine Idee, um die Anzahl der sichtbaren Images für die Stunden festzulegen.
Jenna86
Jenna86 19.07.2011 um 19:57:16 Uhr
Goto Top
Zitat von @stargazer:
Hab nun alles so gemacht, wie es Sinn ergibt, es tritt jedoch ein runtime error auf ( Eine nicht behandelte Ausnahme des Typs
"System.NullReferenceException" ist in Tix Clock.exe aufgetreten ), weshalb ich doch die ganze Arrayerstellung in den
Timer versetzt habe. Nun fehlt mir nur noch eine Idee, um die Anzahl der sichtbaren Images für die Stunden festzulegen.

Hi,

das mit den Instanzvariablen hatte ich schonmal in einer Antwort erwähnt, dass du das beachten musst. Stichwort "Sichtbarkeit von Variablen"
Definierst du eine Variable in einer Methode, so handelt es sich um eine lokale Variable, die nach Beendigung der Methode entfernt wird und somit nur in der Methode, wo sie definiert wird benutzt werden kann.
Instanzvariablen, also Variablen, die du direkt in der Klasse definierst sind in jeder Methode sichtbar und jede Methode kann den Wert lesen / ändern.

System.NullReferenceException tritt auf, wenn du auf einen Index aus einem Array zugreifst, dem einfach noch nichts zugewiesen ist.
Eine IndexOutOfBoundsException tritt auf, wenn du auf einen Index außerhalb der Arraygrenzen zugreifen willst.
Solltest du allerdings alles durch googlen innerhalb von weniger als 30Sekunden finden.

Die Anzahl der Sichtbaren Images für die Stunden... Habe ich grundlegen auch schon alles erklärt und sogar Methoden geliefert, die genau das tun.
>         enum Pos
>         {
>             HourFirst,
>             HourLast,
>             MinuteFirst,
>             MinuteLast
>         }
> 

Hiermit bekomme ich die Anzahl an Punkten, die im jeweiligen Feld dargestellt werden soll.
>         private int getPointsToDraw(int charOfTime)
>         {
>             int pointsToDraw = 0;
> 
>             switch (charOfTime)
>             {
>                 case (int)Pos.HourFirst:
>                         pointsToDraw = DateTime.Now.Hour / 10;
>                     break;
>                 case (int)Pos.HourLast:
>                         pointsToDraw = DateTime.Now.Hour % 10;
>                     break;
>                 case (int)Pos.MinuteFirst:
>                     pointsToDraw = DateTime.Now.Minute / 10;
>                     break;
>                 case (int)Pos.MinuteLast:
>                     pointsToDraw = DateTime.Now.Minute % 10;
>                     break;
>             }
>             return pointsToDraw;
>         }
> 

Zitat von @Jenna86:
- Anordnung der Punkte per Zufall setzen:
Ein Array, dessen Länge die Anzahl der zu zeichnenden Punkte bestimmt
und die Werte des Arrays, die die Position bestimmen
Heißt, ich habe z.B. ein Array der Länge 5, welches 5 Zufallszahlen enthalten soll für die Position.
Jetzt kann ich über eine Schleife die Positionen 1-5 bzw. die Indizes 0-4 durchlaufen und habe so für jeden Punkt der
gespeichert ist den Zugriff auf die Position

Zitat von @Jenna86:
Die Methode liefert mir eine ArrayListe, welche die Position für das jeweilige Rechteck liefert
>         private ArrayList randomizePositions(int numberofpositions, int numberofshownrecs)
>         {
>             Random rand = new Random(DateTime.Now.Millisecond);
>             ArrayList positions = new ArrayList();
>             int tmp = 0;
> 
>             //get random position(s) for this field
>             for (int i = 0; i < numberofshownrecs; i++)
>             {
>                 while (true)
>                 {
>                     tmp = rand.Next(0, numberofpositions);
>                     if (!positions.Contains(tmp))
>                     {
>                         positions.Add(tmp);
>                         break;
>                     }
>                 }
>             }
> 
>             return positions;
>         }
> 

Wie du die Methode aufrufst und benutzt findest du im Code weiter oben.
Sie bekommt zwei Parameter übergeben. Der erste Parameter gibt an, wieviele Felder eine zufällige Position bekommen sollen und der zweite Parameter gibt an, wieviele Felder zur Auswahl stehen.
Hast du also z.B. eine "2" für die Minuten, wo es "9" mögliche Felder gibt wird dir diese Methode ein Array der Größe "2" zurückgeben mit zwei zufälligen Positionen.
Also der Index 0, für die erste der zwei Zahlen hat z.B. eine "7", also soll der Punkt in Feld 7 gesetzt werden, wobei der zweite Index im Array, also "1" z.B. eine "2" enthält, wodurch dann der zweite Punkt an die Position "2" gezeichnet wird.

Punktnummer = Index --------- Indexinhalt = Position
array -> Position 7 meinethalben
array[1] -> Position 2
array[2] -> Position 5

so als Beispiel...

Das heißt ich habe drei Punkte die ich zeichnen soll ( weil das Array die Größe 3 hat ) und jeden dieser Punkte setze ich auf die Position, auf die das Array am entsprechenden Index "zeigt".

Noch ein Beispiel:

13:59Uhr

Die Methode getPointsToDraw(int charOfTime) wird für jeden Punkt benutzt um zu wissen, wie viele Punkte man für die Zahl zeichnen muss...
Ob ich nun als Parameter das Enum oder eine Zahl benutze ist geschmackssache.

int anzahlPunkteStelle0 = getPointsToDraw(0); liefert eine 1
int anzahlPunkteStelle1 = getPointsToDraw(1);
liefert eine 3

Alternativ kannst du auch das Enum benutzen ( zur besseren Lesbarkeit )
int anzahlPunkteStelle0 = getPointsToDraw((int)Pos.HourFirst);
int anzahlPunkteStelle1 = getPointsToDraw((int)Pos.HourLast);

Der erste Name im Enum entspricht der 0, der zweite Name der 1 uswusf...

Grüße
Jenna
stargazer
stargazer 20.07.2011 um 03:09:21 Uhr
Goto Top
Hi Jenna,

ich möchte mich nochmal ganz Herzlich für deine Mühen bedanken! Ohne dich hätte ich das mit den Arrays bestimmt nicht so schnell geblickt! In diesem Sinne: Danke!

Ich hab das Programm jetzt fertig, teste es noch auf Fehler, die evtl häufiger vorkommen als sie sollten, da ich für das letzte Problem eine andere Lösung "erdacht" habe, als du vorgeschlagen hast - wenn sie auch komplizierter ist (ich habe mit mehreren Timern und Listen gearbeitet, falls du Lust hast dir das anzuguggn lad ich das gern noch hoch <: ).

Demnach ist mein Projekt - dank deiner Hilfe - letzten Endes doch ganz glimpflich verlaufen!

Vielen Dank! Ich hoffe, ich vergesse das nicht alles wieder!


stargazer
Jenna86
Jenna86 20.07.2011 um 18:11:11 Uhr
Goto Top
Heyho,

es war ja eine schwere Geburt, aber letzten Endes funktioniert es ja schonmal.
Jetzt kannst du ja versuchen noch mehr auf Verständnis zu setzen und dann geht dir das alles auch leichter von der Hand.

Gerne kannst du das Projekt nochmal hochladen, schaut ja optisch schonmal ganz nett aus ( auf Optik habe ich im Vergleich wohl ziemlich 'geschissen' ).
Die Lösung interessiert mich natürlich. Es besteht ja immer die Möglichkeit, dass man noch was lernen kann ( und wenn es durch das "Verbessern" von Code kommt ).

Schön, dass ich dir helfen konnte.

Dann wünsche ich dir viel Spaß mit C#, die Möglichkeiten sind ja quasi unendlich face-smile

Grüße
( ein vor lauter Code bald nichts mehr sehen könnender und deshalb gleich Feierabend-machender
)
"Jenna"
stargazer
stargazer 20.07.2011 um 18:20:56 Uhr
Goto Top
Peace!

Ich hab das gesamte Projekt nochmal auf Mediafire hochgeladen ( http://www.mediafire.com/?yiggk58xaxxayy7 ). Hab noch n paar kleinigkeiten verändert, allerdings eher Optisch :D

Ich wünsch noch nen schönen Abend!

stargazer