Java jFrame aktualisieren

peps90

Ensign
Registriert
Apr. 2012
Beiträge
219
Hallo zusammen,

und zwar habe ich ein Memory Spiel mittels des JavaEditors erstellt. Dabei bin ich auf das Problem gestoßen, dass wenn ich die 2. Karte aufdecke, das Image auf den Button nicht gesetzt wird. Meine Vermutung ist, dass sich das Programm derzeit in der Methode "gameplay" befindet und deshalb erst nach dem durchlauf das jFrame aktualisiert..

Deshalb dachte ich, ich nutzt einfach repaint in der 275. Zeile, doch leider klappt es nicht.
Desweiteren habe ich noch einige Funktoinen getestet, doch die haben auch nicht funktioniert..

Hoffentlich kann mir jemand den goldenen Tipp geben, wie ich das jFrame aktualisiere bzw. die repaint Funktion richtig anwende..

Hier findet ihr das Programm:
https://drive.google.com/file/d/0B8u2WCol-xj3cXE2Qm8xYWQ4ZFU/edit?usp=sharing
Keine Anmeldung etc notwendig..

Danke im voraus,
Peps90
 
Also zunächst einmal, warum hast du diese ganzen jButtonX_ActionPerformed-Methoden, wenn du sowieso in jeder von denen gameplay mit verschiedenen Parametern ausführst? ^^ den Aufruf kannste dann auch gleich im actionlistener machen - wobei auch ein actionlistener für alle Buttons (bzw zumindest für die mit ähnlicher Funktion) "schöner" wäre..

dein Problem ist, dass du coverUp im selben else aufrufst in dem du vorher das Button image setzt. das mit dem thread.sleep() funktioniert da nicht so - das jframe wird wie du richtig erkannt hast erst nach dem durchlaufen der actionPerformed wieder aktuallisiert. was du willst ist ein thread, der gestartet wird, wenn das zweite bild angeklickt wird und der dann parallel zum normalen programmverlauf nach Xsec die bilder wieder zurücksetzt. da brauchst du dann auch das thread.sleep und das repaint.
 
Lukas-Arts schrieb:
Also zunächst einmal, warum hast du diese ganzen jButtonX_ActionPerformed-Methoden, wenn du sowieso in jeder von denen gameplay mit verschiedenen Parametern ausführst? ^^ den Aufruf kannste dann auch gleich im actionlistener machen - wobei auch ein actionlistener für alle Buttons (bzw zumindest für die mit ähnlicher Funktion) "schöner" wäre..

Das hatte mir der JavaEditor so erstellt, ich habe es anschließend nur etwas angepasst ;) :P


Lukas-Arts schrieb:
dein Problem ist, dass du coverUp im selben else aufrufst in dem du vorher das Button image setzt. das mit dem thread.sleep() funktioniert da nicht so - das jframe wird wie du richtig erkannt hast erst nach dem durchlaufen der actionPerformed wieder aktuallisiert. was du willst ist ein thread, der gestartet wird, wenn das zweite bild angeklickt wird und der dann parallel zum normalen programmverlauf nach Xsec die bilder wieder zurücksetzt. da brauchst du dann auch das thread.sleep und das repaint.

Zwar verstehe ich ungefähr, wie du es meinst, doch leider fehlt mir die Erfahrung in Java, genau das umzusetzen.. ^^

Wenn ich Thread.sleep() einfüge, erhalte ich die Meldung:
Compiliere ...\Memory\Memory.java mit Java-Compiler
Memory.java:275:11: error: cannot find symbol
Thread.Sleep(20);
^
symbol: method Sleep(int)
location: class Thread
1 error
Ergänzung ()

soares schrieb:
Ich sage nur: SwingWorker!

Mittel dieser Seite habe ich die Methode versucht, doch leider komme ich noch nicht darauf, wie ich einen Parameter an die Methode übergebe..
Ergänzung ()

SymA schrieb:

Folgendes habe ich eingefügt:
SwingUtilities.UpdateComponentTreeUI(cp);

doch er kann nicht auf cp (meinen frame) zugreifen, soweit ich es verstehe, ist "cp" mein frame..
 
Zuletzt bearbeitet:
peps90 schrieb:
und zwar habe ich ein Memory Spiel mittels des JavaEditors erstellt. Dabei bin ich auf das Problem gestoßen, dass wenn ich die 2. Karte aufdecke, das Image auf den Button nicht gesetzt wird. Meine Vermutung ist, dass sich das Programm derzeit in der Methode "gameplay" befindet und deshalb erst nach dem durchlauf das jFrame aktualisiert..

Vermutung? Das lässt sich doch wunderbar validieren. Falls der Editor keinen Debugger hat, eben mittels Logging (notfalls System.out). Dann sollte man schnell darauf kommen, dass dies kein Thread- oder Paint-Problem ist.

Oh, die Ausgabe ist ja bereits vorhanden. Nur richtig interpretiert werden muss sie noch :D
Ergänzung ()

Nur noch mal zur Klarstellung: Sollen wirklich beim Klick auf die zweite "Karte" alle offenen Karten zugedeckt werden? D.h. Du möchtest diese Aktion mit einer gewissen Zeitverzögerung nach dem Klick ausführen, damit nicht die Karten nicht sofort zugedeckt werden?



Und bitte, bitte kein NullLayout! GridLayout bietet sich hier doch geradezu an...
 
soares schrieb:
Ergänzung ()

Nur noch mal zur Klarstellung: Sollen wirklich beim Klick auf die zweite "Karte" alle offenen Karten zugedeckt werden? D.h. Du möchtest diese Aktion mit einer gewissen Zeitverzögerung nach dem Klick ausführen, damit nicht die Karten nicht sofort zugedeckt werden?

Richtig..

Die Karten sollen kurz gezeigt werden und anschließend sollen sich beide (da nur 2 max offen sein dürfen ;)) wieder zudecken


soares schrieb:
Und bitte, bitte kein NullLayout! GridLayout bietet sich hier doch geradezu an...

Es ist halb so wild, es war eine Beschäftigungsmaßnahme..
Doch trotzdem möchte ich nur, dass die 2. Karte erneut aufgedeckt wird, mehr benötige ich nicht.. :P

Falls ich es richtig verstanden habe, wenn ich einen 2. Thread erstelle und dieser durchläuft, aktualisiert sich die GUI?!
 
Wenn du den Dispatcher-Thread mit Thread.sleep o.Ä. blockierst, wird nichts gezeichnet, so einfach ist das.
Wenn du Animationen oder Zeitverzögerungen willst, musst du also mehreren Threads arbeiten. Eine Alternative zum Thread oder SwingWorker wären evtl. Timer.
 
peps90 schrieb:
Richtig.. Die Karten sollen kurz gezeigt werden und anschließend sollen sich beide (da nur 2 max offen sein dürfen ;)) wieder zudecken

OK, dann musst Du Deine Aktion zeitgesteuert starten. Das ginge zwar mit einem eigenen Thread, aber Java bietet auch hier Support-Klassen, die man nutzen sollte. In diesem Fall böte sich javax.swing.Timer an, der z.B. nach einer Sekunde Zeitverzögerung die Karten wieder umdrehen könnte.

Code:
private void createFlipTimer()
{
    flipTimer = new Timer(1000, new ActionListener()
    {
        public void actionPerformed(ActionEvent rEvent)
        {
            hideCards();
        }
    });
    flipTimer.setRepeats(false);
}


peps90 schrieb:
Richtig..Falls ich es richtig verstanden habe, wenn ich einen 2. Thread erstelle und dieser durchläuft, aktualisiert sich die GUI?!

Die GUI aktualisiert sich jetzt schon. Das Zeichnen geschieht lediglich so schnell, dass nicht auffällt, dass die zweite Karte erst angezeigt, und dann wieder umgedreht wird.

Grundsätzlich muss man mit Swing beachten, dass alle GUI-Operationen im EDT ausgeführt werden müssen (es gibt zwei, drei Ausnahmen, die man aber vernachlässigen kann), also auch das Erzeugen in main()!. Wenn Du also einen eigenen Thread erstellst, solltest Du javax.swing.SwingUtilities#invokeLater verwenden, um die GUI zu aktualisieren. SwingWorker vereinfacht dies. Aber hier wäre wie gesagt der Einsatz eines Swing-Timers sinniger (die Aktion wird dann automatisch im EDT ausgeführt).

Ich würde Dir auch nahelegen, den Code generischer zu machen. Es soll doch sicher noch eine Funktion hinzugefügt werden, die automatisch ein neues Spiel erstellt und die Karten zufällig anordnet?

Ich habe mal etwas mit dem Code herum gespielt ;) Das Erstellen der Buttons könnte so aussehen:

Code:
private void serveCards()
{
    ...

    Container board = getContentPane();

    for (int i = 0; i < fieldCount; i++)
    {
        ...

        board.add(createCard(getIcon(cardIndex));
    }
}

So leicht geht das, wenn man einen passenden Layout-Manager verwendet (Die Methode ist etwas verkürzt und enthält normalerweise noch die Logik zum Festlegen von Position und Icon einer Karte).

Die Buttons können auch alle den gleichen ActionListener verwenden. Jeder Button kann speichern, welches Icon er verwendet (javax.swing.JComponent#putClientProperty). Das Mitschleppen einer ID ist in meinen Augen unnötig. Die Instanz ist ja eindeutig. Statt einer ID kann man auch die Instanzen speichern.
 
Zurück
Oben