Einfaches Programm für Schüler

Liebe Experten!

Ich bin Lehrer und möchte ein kleines Programm für SchülerInnen erstellen, bei dem diese Bildern bestimmte Begriffe zuordnen müssen. Beispiel: Es wird das Bild einer Bandsäge gezeigt, dann müssen sie den Begriff Bandsäge aus einer Liste mit mehreren Begriffen auswählen und bestätigen. Es sollte auch permanent die erfolgreichen Prozente dargestellt werden.

Da ich aber vom Programmieren (ausser ein kurzer Expresskurs in der Ausbildung in VB) keine Ahnung habe, wende ich mich nun an euch.

Meine Programmierungsidee war folgende:
Ich erstelle 100 Pictureboxen, stelle überall die Sichtbarkeit aus und lasse eine Zufallszahl generieren, bei der immer mit If-Funktionen ein bestimmtes Bild sichtbar wird. Dann erstelle ich eine Combobox, bei der ich alle Begriffe händisch eingebe und dann über einen Button bestätigen kann. Immer mit Wenn Bild1 = sichtbar und Begriff 1 ausgewählt ist, dann bei Richtige + 1.

Da diese Variante aber sehr aufwenig ist, bitte ich euch mir nun zu helfen.

Ich möchte dass man zuerst einen Ordner (den mit den 100 Bildern drin) auswählen kann, dann in einer Picturebox ein zufälliges Bild angezeit wird, die Dateinamen (=Begriffe) in die Combobox automatisch importiert werden und dann das Ganze über einen Button auswählen und prozentuell berechnen kann.

Ich habe, wie gesagt, keine Ahnung von irgendwelchen Schleifen, deshalb wären ein Code und einfache Antworten sehr hilfreich.

Vielen, vielen Dank bereits im Voraus,
Philipp

P.S.: Der Link zum Programm das ich bereits angefangen habe:
http://www.bildhost.com/di/23UY/Unbenannt.jpg

Hallo, ich kann gerne versuchen dir ein paar Tipps oder Codeschnipsel zu geben. Falls du damit nicht oder nur mit sehr viel Aufwand zu einer funktionierenden Lösung kommst, kann ich dir gerne auch einen komplett fertigen Code geben.

Was du also als erstes machen müsstest ist eine Liste aller Bilder einzulesen und zu speichern. Theoretisch kannst du später, bei der Auswahl des Bildes, auch jedes mal den Ordner mit den Bildern neu auslesen und nicht auf die am Anfang eingelesene Liste zurückgreifen, das ist aber weniger performant - vor allem ist es aber sicherer die Liste am Anfang einzulesen (v.a. in dem Fall, falls zwischendurch Bilder im Verzeichnis hinzukommen). Wir werden nur die Dateinamen, bzw. die Pfade, der Bilder speichern und nicht die Bilder selbst (falls hochauflösende Bilder genommen werden, z.B. Digitalkamera-Fotos, könnte man sich sonst schnell in der Situation befinden, dass man mehrere hundert MB an Bilddateien in den Arbeitsspeicher einließt (was passiert, wenn man etwas in einer Variable speichert) und das ist definitiv nicht zu empfehlen; indem wir nur die Pfade zu den Bildern speichern, ist das viel ressourcenschonender). Zusätzlich müssen wir von allen Bildern auch den Dateinamen ohne Dateipfad und Dateiendung in der ComboBox speichern.

Ganz am Anfang, außerhalb eines Subs (aber innerhalb der Class), definieren wir eine Liste, die String-Typen aufnimmt, für unsere Bilder (und initialisieren sie gleich mit, mit dem Schlüsselwort New):
Private bilder As New List(Of String)

Dann, in einem Sub (am besten der Load-Sub der Form), kommt der Code zum Vorbereiten des Programmes (der also einmal am Anfang ausgeführt wird). Als erstes eine Variable mit dem Ordnerpfad mit den Bildern:
Dim pfad As String = „Pfad zum Ordner mit den Bildern“

Mit einer „For Each“-Schleife kann man ganz einfach eine Auflistung von Elementen durchlaufen, wobei jedes einzelne Element eines Durchlaufs im Inneren der Schleife durch „bildpfad“ angesprochen werden kann. „IO.Directory.GetFiles“ gibt uns eine Auflistung aller Dateien mit Dateipfaden zurück, welche wir dann durchlaufen. Zusätzlich sagen wir „GetFiles“, dass nur Dateien mit der Dateiendung „.jpg“ gefunden werden sollen, also normale Bilder (das musst du evtl. entsprechend anpassen, je nachdem welche Endung deine Bilddateien haben).
For Each bildpfad As String In IO.Directory.GetFiles(pfad, „*.jpg“, IO.SearchOption.TopDirectoryOnly)

Jetzt sind wir im Inneren der Schleife. Wir definieren uns einen String, in dem wir dann den Namen des Bildes speichern wollen, also ohne Pfad und Dateiendung.
Dim bildname As String

Jetzt schneiden wir von bildpfad den vorderen Teil bis zum Namen der Datei ab und weisen das Ergebnis bildname zu.
bildname = bildpfad.Substring(pfad.Length + 1)

Hier wird der hintere Teil, also die Dateiendung, weggeschnitten. Im Beispiel ist diese „.jpg“, also vier Zeichen lang. Eventuell muss also die 4 angepasst werden.
bildname = bildname.Substring(0, bildname.Length - 4)

Jetzt können wir den Namen des Bildes der ComboBox hinzufügen…
ComboBox1.Items.Add(bildname)

…und den Pfad des Bildes der bilder-Variable.
bilder.Add(bildpfad)

Das Vorherige wird nun durch die Schleife automatisch für alle Elemente in der Auflistung durchgeführt - also für alle Bilddateien im angegebenen Verzeichnis. Das „Next“ gibt nur das Ende der „For Each“-Schleife an.
Next

Das Bisherige sind die vorbereitenden Aufgaben, die einmal ausgeführt werden müssen. Um ein neues Bild anzuzeigen, holen wir uns eine Zufallszahl um damit ein Bild zufällig auszuwählen und anzuzeigen.

Dim zufallszahl As Integer

Wir berechnen unsere Zufallszahl durch die Rnd-Funktion, die einen Wert im Intervall von 0 bis ausschließlich 1 zurückgibt. Diese multiplizieren wir mit der Anzahl unserer Bilder, welche wir einfach bekommen über die Anzahl der Elemente in unserer bilder-Variable (bilder.Count). Darauf wenden wir eine Floor-Funktion (also Abrunden) an. Das CInt ist nur noch dafür da, das ganze in einen Integer zu wandeln.
zufallszahl = CInt(Math.Floor(bilder.Count * Rnd()))

Mit der Load-Methode einer PicureBox (hier heißt die PictureBox PictureBox1) können wir ein Bild von einem Dateipfad anzeigen lassen. Mit „Item(zufallszahl)“ holen wir uns aus der bilder-Variable den Pfad des Bildes an der Stelle der Zufallszahl, welches wir Load als Argument übergeben.
PictureBox1.Load(bilder.Item(zufallszahl))

Bevor wir ein neues Bild anzeigen, müssen wir das aktuelle Bild aber entfernen, so dass die Zufallsfunktion das selbe Bild nicht noch einmal ausspuckt. Genauer gesagt, müssen wir es aus der bilder-Variable entfernen und aus der ComboBox.

Mit Remove kann man aus einer Liste ein angegebenes Element entfernen. „PictureBox1.ImageLocation“ gibt den Pfad des angezeigten Bildes aus - dieser Pfad ist auch in „bilder“ enthalten. Mit Remove können wir diesen daher aus der Liste entfernen.
bilder.Remove(PictureBox1.ImageLocation)

Falls der Nutzer richtig geraten hat, kann man somit das aktuell ausgewählte Element und somit der Namen des Bildes in der ComboBox, einfach entfernen:
ComboBox1.Items.RemoveAt(ComboBox1.SelectedIndex)

Und die Auswahl der ComboBox auf das erste Element einstellen.
ComboBox1.SelectedIndex = 0

Falls er nicht richtig geraten hat, müssten wir die ComboBox durchsuchen nach dem richtigen Element und dieses entfernen. Das lasse ich jetzt hier aber weg, da es im Grunde nichts neues ist. Es müsste wieder der Name des Bildes aus dem Pfad des Bildes herausgeschnitten werden (den bekommen wir über PictureBox1.ImageLocation), damit wir dieses Element aus der ComboBox entfernen können. Das Entfernen macht man mit:
ComboBox1.Items.Remove(„Name des Bildes“)

Was jetzt nur noch gemacht werden muss, ist die Benutzerausgabe auszuwerten, z.B. auf Buttonklick. Eine Abfrage nach Gleichheit des Inhaltes einer ComboBox mit Namen ComboBox1 und des Pfades des angezeigten Bildes einer PictureBox mit Namen PictureBox1 ist möglich über:
PictureBox1.ImageLocation = ComboBox1.SelectedItem

In einer If-Funktion kann man auf diese Weise leicht abfragen, ob der Benutzer das richtige eingegeben hat. Falls ja, kann man z.B. eine globale Variable, die die Anzahl der Richtigen zählt, erhöhen und diese Zahl in einem Label anzeigen, oder natürlich verrechnet mit der Anzahl aller Bilder als Prozentzahl anzeigen.

Das ist viel mehr, als ich eigentlich schreiben wollte, aber hoffentlich kannst du damit was anfangen. Falls nicht - keine Schande. Sag bescheid, dann kann ich dir einen komplett fertigen Code schicken. :smile:

Vielen, vielen Dank für deine schnelle Antwort.
Ich hab mal die Codeabschnitte eingefügt, aber es kommt immer eine Fehlermeldung.
Ich glaube auch, dass ich manche Befehle in falsche Fenster (wie zum Beispiel das mit dem Button) kopiert habe.
Mir ist aufgefallen, dass ich direkt im Code den Pfad des Zielordners angebe. Ich glaube es wäre doch sinnvoller, wenn man beim Programmstart den Ordner einmalig auswählen muss, weil wenn ich das Ganze am Schul-PC laufen lasse, stimmt doch der Pfad nicht mehr überein, oder?
Außerdem ist mir bei der Items-Lösch-Funktion nicht ganz klar, was ich in „Name des Bildes“ schreiben soll, kommt hier nicht einfach die Variable „bildname“?

Im angefügten Bild der Code.
http://www.bildhost.com/di/3DIK/Code.jpg

Danke noch mal vereits im Voraus,
Philipp

Falsches Brett, du gehörst ins .Net Brett o.w.T.

Den Code, den ich geschrieben und erklärt habe, deckt die Kernfunktionen des Programmes ab - neues Bild anzeigen, aktuelles Bild entfernen, das Ganze vorbereiten. Damit man es aber wirklich zu einem funktionierenden Programm machen kann, müssen die Teile an die richtigen Stellen im Programm kopiert werden und eventuell noch einige If-Abfragen rein (wie z.B. eine, die dafür sorgt, dass das Programm aufhöhrt, wenn alle Bilder abgearbeitet wurden).
Du hast letztlich den gesamten Code in den Form1_Load-Sub kopiert. Das Programm würde dann beim Start diesen Code einmalig ausführen und danach nichts mehr tun. (Der Fehler resultiert daher, dass in der ComboBox nichts ausgewählt ist (was ja auch nicht der Fall sein kann, da das Programm erst noch gestartet wird) - der Codeteil zum Entfernen des Bildes, wo der Fehler auftritt, ist dafür gedacht dann ausgeführt zu werden, wenn der Benutzer eine Auswahl getätigt hat und den Button klickt.)

Tatsächlich muss der vorbereitende Code nur einmal bei Programmstart ausgeführt werden - ist also dort, wo er ist, gut aufgehoben. Die anderen Teile müssen aber wo anders hin. So muss der Code, der das aktuelle Bild entfernt, dann aufgerufen werden, wenn der Benutzer den Button klickt und direkt danach der Code, der ein neues Bild anzeigt. Diser Code muss aber auch ganz am Anfang einmal ausgeführt werden, damit das erste Bild angezeigt wird.

Ich hoffe es ist nicht zu schlimm, wenn ich das ganze etwas ausschweifender erkläre. Wenn ich es aber jetzt richtig erkläre, hast du irgendwann später vielleicht auch noch Nutzen davon.

In Visual Basic werden Benutzeroberflächen Ereignis-gesteuert programmiert. Wenn der Benutzer einen Button klickt wird ein sogenanntes Ergeignis automatisch ausgelöst. Da man oft sein Programm nur dann Dinge tun lassen will, wenn der Benutzer mit dem Programm interagiert, er also z.B. auf einen Button klickt, können wir solche Ereignisse „behandeln“, was bedeutet, wir schreiben Code, der ausgeführt wird, wenn das Ereignis eintritt. Dafür braucht man Ereignisbehandler, welche meistens diese Form haben:

Private Sub STEUERELEMENT_EREIGNIS(sender As System.Object, e As System.EventArgs) Handles STEUERELEMENT.EREIGNIS

Zum Beispiel kann unser Steuerelement, dass das Ereignis auslöst, ein Button sein (Button1 wäre ein möglicher Name eines solchen Buttons) und das Ereignis könnte das Klick-Ereignis des Buttons sein, also Click. Wenn du einen Button einfügt in den Form-Designer und dann doppelt auf diesen klickst landest du ja im Code-Editor - aber nicht irgendwo, sondern in einem neu erstellten (falls noch nicht vorhandenem) Ereignisbehandler dieses Buttons.
Diese Ereignisbehandler sind die Dinge, die du glaube ich mit „Fenster“ in deiner vorigen Antwort meintest. Und wenn du eben Code in den Ereignisbehandler Button1_Click schreibst, wird der Code jedesmal und nur dann ausgeführt, wenn der Benutzer auf den Button klickt.

Es gibt noch mehr Ereignisse. Ein Button allein hat viele Ereignisse („Click“, das ist das Standard-Ereignis, aber auch „DoubleClick“, „MouseDown“ (ausgelöst, wenn die Maus auf dem Button heruntergeklickt wird; Click würde nur ausgelöst werden, wenn die Maustaste auch losgelassen wird, usw.) und nicht nur Button haben Ereignisse, sondern z.B. auch die Form, also das ganze Fenster wo du deine Buttons und andere Dinge platzierst. Die Form hat z.B. das Load-Ereignis - das wird ausgelöst, wenn die Form geladen wird (vereinfacht: das Programm geladen wird). Zu diesem kommst du durch Doppelklick auf die Form selbst und das ist auch der Ergenisbehandler, in den du den gesamten Code reinkopiert hattest (Form1_Load).

Also, der vorbereitende Code muss ausgeführt werden, wenn das Programm startet - das Load-Ereignis der Form beitet sich da an. Steht also schon richtig. Der Teil, der ein neues Bild anzeigt, muss am Anfang natürlich auch einmal durchlaufen werden. Deswegen steht dieser auch richtig - noch in Form1_Load, aber nach dem Teil mit der For-Schleife. Was ich hier übrigens vergessen habe: Ein Aufruf, der den Zufallszahlengenerator initialisiert. Ich weiß nicht, ob man diesen auch weglassen kann, zur Sicherheit kannst du ihn aber hinschreiben:
Randomize()
Diese Zeile einfach nach der For-Schleife einfügen (also nach dem Next, das das Ende der Schleife markiert, aber noch vor dem Aufruf, das erste Bild anzuzeigen (da wir dort bereits eine Zufallszahl brauchen).

Der Teil, der das Bild entfernt (die bei dir vier Zeilen mit den vielen "Remove"s), darf aber nicht in Form1_Load, also rauslöschen. Stattdessen muss dieser in das Click-Ereignis des Buttons, so dass das nur ausgeführt wird, wenn der Button geklickt wird. Also muss es in Button1_Click. Hierbei hatte ich aber einen Fehler gemacht bzw. war ich etwas ungenau; für den allgemeinen Fall funktioniert das nicht:
ComboBox1.Items.RemoveAt(ComboBox1.SelectedIndex)
Denn das würde das aktuell ausgewählte Element aus der ComboBox entfernen - das wäre korrekt, falls der Benutzer richtig geraten hat, aber falls er falsch riet, wäre es blöd, wenn der von ihm fälschlicherweise ausgewählte Begriff entfernt wird. Deswegen müssen wir das zu entfernende Element - den richtige Begriff - aus der ComboBox löschen, indem wir ihn der Remove-Funktion der ComboBox übergeben. Diesen Namen des Bildes müssen wir uns aber erst „erarbeiten“ - die Variable bildname können wir deswegen nicht nehmen, da sie hier in diesem Bereich garnicht definiert ist. Variablen sind im Allgemeinen nur innerhalb des Abschnittes gültig, in dem sie definiert werden. EIn solcher Abschnitt ist z.B. die For-Schleife. Außerhalb der For-Schleife gibts diese Variable also nicht mehr. Auch gibt es die Variable bildpfad nicht mehr, also machen wir uns beide neu.
Das erstellt die bildpfad-Variable:
Dim bildpfad As String

Den Pfad des Bildes können wir uns aus der ImageLocation-Eigenschaft der PictureBox1 holen, denn dort wird ja unser aktuelles Bild noch angezeigt.
bildpfad = PictureBox1.ImageLocation

Und jetzt erstellen wir uns daraus wieder unseren Bildnamen.
Dim bildname As String
bildname = bildpfad.Substring(pfad.Length + 1)
bildname = bildname.Substring(0, bildname.Length - 4)

Mit bildname können wir ihn jetzt azs der ComboBox entfernen.
ComboBox1.Items.Remove(bildname)

Deren Auswahl sollten wir direkt danach auf das erste Element (in der Programmierung zählt man meist mit 0 beginnend) festlegen, sonst ist evtl. garnichts ausgewählt.
ComboBox1.SelectedIndex = 0

Und aus der bilder-Variable können wir auch das entsprechende Bild entfernen. Aber mit bildpfad, nicht mit bildname, da in bilder ja alle Bildpfade gespeichert sind.
bilder.Remove(bildpfad)

Das, was ich gerade an Code geschrieben habe (von „Dim bildpfad As String“ an), kannst du als Lösch-Funktion verwenden. Das, was ich in meiner ersten Antwort geschrieben hatte, funktioniert nicht im Allgemeinen.

Wir haben also jetzt in Button1_Click die Lösch-Funktion. Dort hinein muss aber auch der Teil, der ein neues Bild anzeigt, aber natürlich nach dem das aktuelle Bild entfernenden Teil. Letztlich haben wir den Code zum Anzeigen eines neuen Bildes dann am Ende zweimal, einmal in Button1_Click und einmal in Form1_Load.

Noch eine Sache, die fehlt: Damit der Code der Lösch-Funktion funktioniert, musst du den Teil, der den Pfad zu den Bildern speichert, vor die Form1_Load setzen, damit wir auf pfad auch später noch zugreifen können.
Zu deiner Frage, warum man den Pfadnamen fest im Code angibt: Du hast recht, es ist besser, so eine Sache wie den Pfad variabel zu halten. Ich wusste nur nicht, was für dich einfacher ist. Wenn du willst, dass dieser beim Start des Programmes eingegeben werden muss, kannst du es beispielsweise so machen, dass du in Form1_Load folgender Zeile schreibst:
pfad = InputBox(„Pfad angeben“)

Das muss dann aber als aller erstes in Form1_Load stehen. Gleichzeitig ist es dann sinnlos, der pfad-Variable ganz oben (noch vor der Form1_Load, wo wir sie ja gerade hinversetzt haben) einen Wert zuzuweisen, also löschst du dort einfach das " = „“", das direkt hinter „Dim pfad As String“ steht.

Jetzt hätten wir das Programm soweit, dass es prinzipiell erstmal funktioniert. Was wir noch machen können/müssen ist den Fall zu betrachten, wenn der Benutzer das letzte Bild bearbeitet hat, sowie eventuell mitzuzählen wie viele richtige er hat. Aber am besten wir bekommen diesen Teil erstmal zum Laufen - das Programm kann dann bereits getestet werden - bevor wir weitermachen.

Hallo Philipp,

Rima hilft Dir ja momentan sehr und der Ansatz klingt ziemlich gut. Visual Basic mache ch schon länger nicht mehr, dafür aber C#, was ähnlich ist.
Falls es noch Probleme gibt, stehe ich zur Verfügung.

Viel Erfolg,
Michael

Vielen Dank erstmal für die sehr gute und schnelle Erklärung.
Ich habe mir jetzt bei den Befehlen rechts immer die Beschreibung dazugeschrieben, damit ich es besser nachvollziehen kann.
Weiters habe ich nun die Codes neu angeordnet und immerhin wird ein Bild angezeigt :smile:

Ich glaube aber ich habe einen kleinen Fehler bei der If-Funktion, denn auch bei einer richtigen Auswahl wird der Begriff nicht aus der Combobox gelöscht.

Zudem bin ich mir nicht sicher, ober der Befehl „PictureBox1.Load(bilder.Item(zufallszahl))“ nach dem End If stimmt, weil da manchmal eine Fehlermeldung angezeigt wird (ich glaube genau dann, wenn eine Zufallszahl bestimmt wird, die bereits verwendet wurde und nicht mehr zur Verfügung steht). Dafür habe ich einfach die Variable „Zufallszahl“ gleich wie die Variable „Pfad“ oberhalb der Form1 definiert, weil ich diese ja in mehreren Ereignisbehandlern vorkommen.

Außerdem habe ich jetzt einen Timer eingefügt, da ich möchte, dass von Beginn an die Zeit gemessen wird, damit die Schüler/-innen sozusagen einen Vergleich miteinander anstellen können. Leider zählt hier die Zeit nicht, obwohl ich den Timer auf Enabled=>True (Außerdem Intervall 1000?) gesetzt habe.

Das mit dem Pfad habe ich nun vorerst so beibehalten, weil, wenn eine Inputbox zum selbereingeben daher kommt, machen die Kinder sicherlich einen Tippfehler (vertauschen z.B. / mit \ usw.). Hier wäre ein neues Fenster praktisch, bei dem man (wie z.B. beim Speichern in Word) über die graphische Oberfläche einen Ordner auswählen kann.

Was mir noch aufgefallen ist, ist dass die Bilder nicht alle im gleichen Format gespeichert sind und manche somit verzerrt dargestellt werden.

Vielen Dank schon mal im Voraus für die Info,
liebe Grüße, Philipp

P.S.: Hier wieder der Link zum Quelltext
http://www.bildhost.com/di/JBBA/Zwischenergebnis.jpg

Das Problem bei deiner If-Abfrage ist, dass hier den Bildpfad und Bildnamen durcheinanderschmeißt. Wir haben unterschieden zwischen Bildpfad und Bildname, damit wir den Bildnamen in der ComboBox anzeigen können (wo der Pfad zur Bilddatei ja nicht allzu schick aussehen würde) und den Bildpfad brauchen wir zum Laden des Bildes in die PictureBox.
Bei deiner If-Abfrage überprüfst du, ob die ImageLocation-Eigenschaft der PictureBox1 (welche der Pfad zum aktuell angezeigten Bild ist) gleich der SelectedItem-Eigenschaft der ComboBox1 ist (was der in der ComboBox angezeigte Bildname ist). Die PictureBox hat einen Pfad zur Bilddatei und die ComboBox hat nur den Namen der Bilddatei. Das heißt, die If-Abfrage ist niemals wahr, da selbst wenn das richtige in der ComboBox vom Benutzer ausgewählt ist, der Name des Bildes nicht gleich dem Pfad des Bildes ist (es werden vom Programm stupide die zwei Zeichenketten „C:\Pfad\zum\Bildordner\ich_bin_ein_bild.jpg“ und „ich_bin_ein_bild“ verglichen - und diese sind nun mal nicht gleich; dass sie fast gleich sind, bzw. etwas miteinander zu tun haben, weiß das Programm nicht).
Das bedeutet, es wird immer der Else-Fall deiner If-Abfrage ausgeführt - und diese macht letztlich nichts. Denn das einzige, was sie tut, ist einen Bildpfad (PictureBox1.ImageLocation) aus der ComboBox1 zu entfernen mittels ComboBox1.Items.Remove. Jedoch gilt hier wieder: In der ComboBox sind Bildnamen gespeichert, aus der PictureBox bekommt man aber immer einen Bildpfad. Dass heißt weder der Vergleich am Anfang der If-Bedingung kann jemals wahr sein, noch wird jemals ein Element aus der ComboBox entfernt durch die Codezeile im Else-Fall.
Im „Nicht-Else-Fall“ (also direkt nach der Bedingung der If-Abfrage) machst du es richtig. Dem Aufruf ComboBox1.Items.Remove übergibst du da in den Klammern einen Bildnamen (in die Variable bildname haben wir uns direkt davor ja den Bildnamen gespeichert, welchen wir aus bildpfad herausgeholt haben) und dem Aufruf bilder.Remove übergibst du in den Klammern den Bildpfad in der Variable bildpfad, denn unsere Liste „bilder“ speichert ebenfalls keine Bildnamen, sondern die Pfade zu den Bildern.

Die Bedingung deiner If-Abfrage müsste korrekt also lauten:
If bildname = ComboBox1.SelectedItem Then

Denn bildname enthält den Namen des Bildes, das gerade angezeigt wird (wir haben den Bildnamen aus der Variable bildpfad „errechnet“, welcher wir davor den Wert aus PictureBox1.ImageLocation zugewiesen haben) und wenn dieses gleich dem ausgewählten Wert in der ComboBox ist, hat der Nutzer richtig geraten.
Auch die Bedingung nach ElseIf müsste entsprechend abgeändert werden, jedoch kannst du das auch komplett weglassen - ein „Else“ würde reichen (in der ganzen Zeile, die mit ElseIf beginnt, nur ein einzelnes Else schreiben, das reicht).

Aber: Was bezweckst du mit der If-Abfrage denn eigentlich? So wie sie im Moment aussieht (bzw. korrigiert um das oben Erwähnte) würde sie, falls der Nutzer falsch geraten hat (Else-Fall), nur den Begriff aus der ComboBox entfernen, aber nicht das Bild aus der bilder-Liste. Das würde zu dem möglichen Fall führen, dass das Bild wieder dran kommt, der richtige Begriff aber nicht mehr in der ComboBox zur Auswahl steht! Deswegen solltest du, wenn du einen Begriff aus der ComboBox entfernst undbedingt auch das Bild aus der bilder-Liste entfernen (bzw. den Pfad des Bildes aus der bilder-Liste entfernen, immerhin ist es ja das, was die bilder-Liste speichert). Und das ist letztlich genau das, was du im „Nicht-Else-Fall“ ja tust.
Wenn du es so haben willst, dass, falls der Begriff falsch geraten wurde, das Bild (und der zugehörige Name in der ComboBox natürlich) weiterhin zur Auswahl verbleibt, so dass der Nutzer später das Bild nochmal bekommen kann, dann kannst du hier den Else-Fall einfach leer lassen; bzw den Else-Fall komplett weglassen.
Wenn du aber in beiden Fällen, wenn der Benutzer richtig oder falsch geraten hat, das Bild entfernen willst, dann brauchst du die If-Abfrage garnicht - oder du schreibst in den Else-Teil das gleiche wie davor, aber das ist wirklich sehr unnötig.

Der Befehl
PictureBox1.Load(bilder.Item(zufallszahl))
stimmt schon. Falls das übrigens für dich etwas verwirrend ist, was die Zeile macht, hier das gleiche aufgedröselt:
Dim neuesbild As String = bilder.Item(zufallszahl)
PictureBox1.Load(neuesbild)
Ist exakt das gleiche, nur in eine Zeile geschrieben. Fiel mir nur gerade auf, dass das eventuell nicht ganz klar ist, was das eigentlich tut.
Nein - der Befehlt stimmt schon. Das Problem ist, dass du keine neue Zufallszahl berechnest. Die Zeile zum Berechnen der Zufallszahl war diese hier:
zufallszahl = CInt(Math.Floor(bilder.Count * Rnd()))
Diesr rufst du aber nur ein einziges mal im Programm auf - in Form1_Load. Du berechnest zu Programmstart also einmal eine Zufallszahl - und verwendest diese dann immer wieder. Du musst aber jedes mal, wenn ein Bild angezeigt werden soll, eine neue Zufallszahl berechnen. Deswegen solltest du die Zeile vor das
PictureBox1.Load(bilder.Item(zufallszahl))
reinkopieren, damit das „zufallszahl“ in diesem Befehl eine frisch berechnete Zufallszahl ist.
Übrigens - so wie der Code geschrieben ist, kann es garnicht sein, dass es Probleme gibt, wenn eine Zufallszahl, die bereits mal kam, nochmal kommt. Denn wenn man mit bilder.Remove einen Bildpfad aus der Liste an einer bestimmten Stelle entfernt, rücken die anderen Bilder automatisch nach. Und in der Berechnung der Zufallszahl fließt bilder.Count mit ein, was dafür sorgt, dass die berechnete Zufallszahl maximal die Anzahl der Bilder in der Liste ist, so dass es keine Probleme gibt.

Zum Timer: Den Code verstehe ich nicht… Was der nämlich letztlich tut ist, die Zeit zu messen, die dein Computer benötigt um die Codezeile mit dem „Dim“ zwischen den beiden Zeilen wo das „Now()“ drin vorkommt auszuführen. Denn du speicherst die aktuelle Zeit vor und nach der Zeile in unterschiedlichen Variablen und berechnest dann die Differenz. Ich glaube nicht, dass es das ist, was du möchtest :smile:
Um die Zeit zu zählen solltest du dir eine globale Variable (also ganz oben) festlegen, die die Startzeit speichert. Zum Beispiel:
Dim startzeit As DateTime

Dann solltest du auch den Zeitgeber auf andere Art starten, also ihn von Anfang an auf Enabled zu setzen. Denn dadurch würde das Zählen schon anfangen, während der Benutzer noch den Pfad zum Ordner bei Programmstart eingibt (was wir zwar nicht nicht drinnen haben, was aber noch kommen wird, oder?). Am Ende der Form1_Load können wir dann den Timer starten über:
Timer1.Start()

Und direkt davor sollten wir der Variable startzeit die aktuelle Zeit zuweisen:
startzeit = Now()

Im Timer1_Tick (das ist der Ereignisbehandler für das Tick-Ereignis des Timers, welches alle 1000 Millisekunden ausgelöst wird (sofern du 1000 in der Intervall-Eigenschaft des Timers angegeben hast)) kannst du jetzt die Differenz zwischen aktueller und Startzeit ermitteln und dem Label zuweisen:
Dim aktuellezeit As DateTime
aktuellezeit = Now()
Dim differenz As TimeSpan
differenz = aktuellezeit.Subtract(startzeit)
Label1.Text = "Zeit: " & differenz.ToString()

Dieser Code im Eriegnisbehandler wird also jede Sekunde ausgeführt und berechnet die vergangene Zeit seit dem Start und zeigt diese an.

Zur Auswahl des Pfades zum Bildordner: So ein Dialog zur Auswahl eines Ordners ist recht leicht möglich zu implementieren. Füge deiner Form einen FolderBrowserDialog hinzu (in der Toolbox unter „Dialogfelder“) und schreibe in Form1_Load ganz oben:
If Not FolderBrowserDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
Me.Close()
Else
pfad = FolderBrowserDialog1.SelectedPath
End If

Das zeigt den FolderBrowserDialog an und prüft, ob dieser beendet wird, indem der Nutzer auf den OK-Button drückt. Falls das nicht der Fall ist wird gleich das ganze Programm geschlossen - plump, aber effektiv insofern, als dass der nachfolgende Code nicht ausgeführt wird, was katastrophal wäre, da der Benutzer offenbar keinen richtigen Pfad angegeben hat (sonst würd er nicht auf Abbrechen klicken) und dieser danach gebraucht wird. Falls er auf OK geklickt hat, wird der Pfad der Variable zugewiesen.

Wenn deine Bilder unterschiedliche Formate (was das Seitenverhältnis angeht) haben und du sie nicht zuschneiden möchtest, kannst du deine PictureBox anweisen, dass Bild zentriert anzuzeigen, ohne es auf die Grüße der PictureBox zu ziehen. Wähle die PictureBox aus und klick auf den kleinen Pfeil und wähle den Größenmodus „CenterImage“.

Ich habe nun die Fehler ausgebessert und das Programm läuft soweit bereits ganz gut. Einziger Fehler ist hierbei noch, dass, sobald nur noch 1 Begriff übrig ist, eine Fehlermeldung beim Befehl „PictureBox1.Load(bilder.Item(zufallszahl))“ kommt, mit dem Hinweiß „Argument-Out-Of-Range-Exception wurde nicht behandelt“.

Weiters habe ich nun ein paar Änderungen vorgenommen. Ganz am Anfang kommen nun 3 Buttons, bei denen man zwischen -Bild wird angezeigt=>Begriff auswählen-, -Bild wird angezeigt=>Begriff selber in Textfeld schreiben- und -Begriff wird angezeigt=>Bild auswählen- aussuchen kann. Meine Frage hierbei: Ist es möglich, alle Bilder als Mosaik anzeigen zu lassen um dann eines davon auszuwählen? Zudem habe ich die Combobox durch eine Listbox ersetzt, da diese bei hundert Bildern übersichtlicher ist.

Ich habe zudem noch versucht, den Enter-Button überflüssig zu machen, weil es meiner Meinung nach wahrscheinlich einfacher und schneller ist, den Begriff mit den Tastaturpfeilen auszuwählen und dann mit Enter statt mit dem Button zu bestätigen. Hierbei habe ich im Befehlsfenster der Listbox (Aktion Enter) die Befehle des Buttons reinkopiert, nur leider regt sich dabei dann noch nichts.

Das prozentuelle ausrechnen klappt auch noch nicht ganz, meine Idee war einfach 2 Variablen zu definieren (einmal richtige und einmal gesamtantworten) und dann mit einer if-abfrage zu starten. Ich habe dann bei Buttonclick eingetragen, dass gesamtantworten = gesamtantworten+1 und wenn es richtig gewählt wurde, dann auch richtige=richtige+1. Leider hat das nicht geklappt, deshalb habe ich es wieder gelöscht.

Es wäre auch toll, wenn bei richtiger Beantwortung aller Bilder ein neues Fenster mit „Gratulation, du hast as in xxx Sekunden mit xxx % Richtigkeit geschafft“. Wenn man das Ganze auch noch als pdf verwandeln kann, wäre es natürlich ein Highlight. Falls dies aber zu aufwändig ist, will ich dir nicht weiter zur Last fallen.

Meine letzte Frage ist nun, ob es auch möglich ist, die Bilder in Kategorien zu unterteilen? Wenn im Ordner 200 Bilder sind, und diese sind durcheinandergewürfelt, ist es schwierig, immer den korrekten Begriff zu finden. Es wäre toll wenn man beispielsweise die Bilder am Desktop in Unterordner = Kategorien einteilt, alle Bilder in jedem Unterordner in die Picturebox geladen wird aber in der Listbox eben die Ordnernamen als Trennwörter zwischen den Kategorien angezeigt werden.

Vielen, vielen Dank nochmals bereits im Voraus, ohne deine Hilfe wäre ich wirklich hoffnungslos verloren…

Danke, danke, danke.

Hier die Form:
http://www.bildhost.com/di/XPT1/Form.jpg

Hier der Code:
http://www.bildhost.com/di/V4WS/Code.jpg

Hallo,
ich habe etwas ähnliches in c# gemacht. Ich könnte die .exe ja mal zu mailen.

vG
der_kps

Hi… sorry für die äußerst späte Antwort :smile:

Leider habe ich inzwischen nicht mehr die Zeit um dir so zu antworten, wie bisher. Wenn du aber willst kann ich dir gerne das ganze fertig programmieren (ist ja immerhin für die Schule und daher guter Zweck :smile:), auch wenn du dabei dann selber weniger lernst. (In diesem Fall wäre es ganz gut, wenn du mir den Ordner des Projektes zukommen lässt.)

Zur prinzipiellen Möglichkeit der mosaikförmigen Anzeige der Bilder: Ich kenne kein vorgefertigtes Steuerelement, welches das kann, aber man kann es natürlich alles selber programmieren mit entsprechend vielen PictureBoxen. Sollte im Grunde garnicht so schwer sein.
Die Einteilung in Kategorien lässt sich bestimmt ebenfalls realisieren.

>> Hierbei habe ich im Befehlsfenster der Listbox (Aktion Enter) die Befehle des Buttons reinkopiert, nur leider regt sich dabei dann noch nichts.

Wo genau hast du die reinkopiert?
Was das angeht kenne ich selbst keine vorgefertigte Lösung, außer vielleicht das AcceptButton-Ereignis der Form zu missbrauchen.

Vielen Dank für deine Hilfe, ich habe jetzt nahezu alle Probleme gelöst, das Programm läuft soweit bereits super, auch das mit den mehreren Pictureboxen habe ich eingebaut. Das Einzige, das ich nicht hinbekomme ist, dass der Name des Ordners (aus dem die Bilder reingeladen werden) in einem Label angezeigt wird. Dass sollte eig. nur ein Befehl sein…

LG

OK, freut mich!

Meinst du den Ordner, in dem alle Bilder drinnen sind, oder einen der Unterordner?
In ersterem Fall kannst du mit der folgenden Zeile den letzten Ordner aus einem Pfad herausschneiden - und bekommst, wenn „pfad“ die Variable ist, die als String den Pfad zum Bilderordner enthält, den Namen des Ordners:
pfad.Substring(pfad.LastIndexOf("")+1)

Vorausgesetzt pfad ist derart aufgebaut: „LW:\Pfad\zum\Ordner“ und nicht etwa so: „LW:\Pfad\zum\Ordner“, also dass das letzte „“-Zeichen vor dem Ordnernamen steht.

Jetzt funktioniert wirklich alles :smile:

Danke, danke danke!!!