JApplet will sich nicht refreshen

HeroicGlaedr

Mitglied
Hallo,

Ich habe mir ein JApplet programmiert, in welchem ein JFrame (GUI) aufgerufen wird.
Das GUI hat ein CardLayout und wechselt zwischen zwei verschiedenen JPanels (Game und Home).
Beim Wechsel rufe ich invalidate() und repaint() auf. Dasselbe beim updaten von Komponenten (wie Bilder, etc.)

Wenn ich das JApplet unter Eclipse als Applikation laufen lasse, funktioniert alles wunderbar und
alle Komponenten (Bilder, Buttons, etc.) werden korrekt dargestellt.

Wenn ich es aber als JApplet laufen lasse, dann muss ich das GUI immer vergrössern/-kleinern, damit
es neu gezeichnet wird.

Hier den Code für das Applet:
Java:
public class MtGApplet extends JApplet {

	private static final long serialVersionUID = 855191779156553609L;
	
    /** Initializes the MtGApplet */
    @Override
    public void init() {
        try {
        	ImageLoader.getInstance().setApp(this);
        	java.awt.EventQueue.invokeAndWait(new Runnable() {
                public void run() {
                	new GUI (1055, 850);
                }
            });
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    public static void main(String[] args){
    	MtGApplet app = new MtGApplet();
    	app.init();
    }
}
Hier den Code für das GUI:
Java:
public class GUI extends JFrame{
	
	private static final long serialVersionUID = -4156161136650580297L;
	
	public static void main(String[] args) {
		new GUI (1055, 837);
	}
	private final String GAMEPANEL = "Game";
	private final String HOMEPANEL = "Home";
	private JPanelGame game;
	private JPanelHome home;
	private JPanel cards;
	
	private GameClient client;
	public GUI(int w, int h){
		this.setPreferredSize(new Dimension(w,h));
		game=new JPanelGame(this);
		home=new JPanelHome(this);
        client = new GameClient(this);
		/** CardLayout um zwischen verschiedenen Panels zu wechseln **/
        CardLayout cl = new CardLayout();
		cards = new JPanel(cl);
		cards.add(home,HOMEPANEL);
		cards.add(game,GAMEPANEL);
		cl.show(cards,HOMEPANEL);
		this.add(cards);
		this.pack();
		this.setVisible(true);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
	}
	/** Signal Spielstart **/
	public void gameStart(int i) {
		try{game.setUID(client.getUID());}
		catch(RemoteException e){e.printStackTrace();}
		showGamePanel();
		game.gameStartUpdate(i);
	}
	public GameClient getClient(){
		return client;
	}
	/** MVC Komponenten initialisieren **/
	public void initMVC(RemoteObservable[] obs) {
		game.initMVC(obs);
	}
    public void setClient(GameClient client) {
        this.client = client;
    }
    /** Zum Gamepanel wechseln **/
	public void showGamePanel(){
		((CardLayout) cards.getLayout()).show(cards,GAMEPANEL);
		invalidate();
		repaint();
	}
	/** Zum Homepanel wechseln **/
	public void showHomePanel(){
		((CardLayout) cards.getLayout()).show(cards,HOMEPANEL);
		invalidate();
		repaint();
	}
}

Was mache ich falsch?

MfG HeroicGlaedr
 
warum rufst du denn in der Reihenfolge:
Java:
 ((CardLayout) cards.getLayout()).show(cards,GAMEPANEL);
invalidate();
repaint();
auf?

Du lässt dir als erstes irgendeine "Karte" deines Card-Layouts anzeigen, dann erklärst du ihm, dass dieser Container ungültig ist und lässt ihn dann neu-zeichnen.

Ich behaupte mal, dass ein einfaches [c]validate();[/c] oder [c]revalidate[/c] weitaus sinnvoller ist und evtl. sogar ohne einen [c]repaint()[/c] Aufruf funktionieren sollte.
 
Hallo

Die Reihenfolge, die du mir genannt hast ist weitaus sinnvoller, da hast du recht!

Beim erneuten Versuch ändert sich aber nichts: Ich muss das Frame wieder vergrössern,
damit es korrekt dargestellt wird.

MfG
 
Zuletzt bearbeitet:
ok, das
Code:
revalidate()
wird von JComponent vererbt und ist bspw für JPanel´s verfügbar, während JFrame von Component erbt...ok.

am besten wäre ein KSKB, dann wäre es evtl leichter das Problem zu lösen.
evtl. hilft auch ein
Code:
validate();  repaint()
auf deinen von JPanel´s geerbten Klassen?
 
Hallo,

Ich habe auch probiert, revalidate() und repaint() auf den Panels zu invoken - kein Erfolg!

Ich kann dir hier den Code für das eine JPanel posten, werde mir danach mal Zeit machen,
ein KSKB zu schreiben.

Hier den Code fürs HomePanel:
Java:
public class JPanelHome extends javax.swing.JPanel {
	private static final long serialVersionUID = -5144783914570758206L;
	private GUI gui;
	
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButtonExit;
    private javax.swing.JButton jButtonJoin;
    private javax.swing.JLabel jLabelMagic;
    private javax.swing.JLabel jLabelNickname;
    private javax.swing.JTextField jTextFieldNickname;
    // End of variables declaration//GEN-END:variables
    
    /** Creates new form JPanelHome */
    public JPanelHome(GUI gui) {
        this.gui = gui;
        initComponents();
    }
    public void displayMessage(String str, String title, int i){
    	SwingUtilities.invokeLater(new Message(gui.getContentPane(),str,title,i));
    }
 private void jButtonExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonExitActionPerformed
        try{ gui.getClient().disconnect(); } catch(RemoteException ignore){}
        gui.setClient(null);
        System.exit(0);
    }//GEN-LAST:event_jButtonExitActionPerformed
    private void jButtonJoinActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonJoinActionPerformed
    	if(!jTextFieldNickname.getText().equals("")){
    		try {
                gui.getClient().connect(jTextFieldNickname.getText());
                jTextFieldNickname.setText("");
                displayMessage("You have been added to the Queue.\nPlease wait for the second Player to join the Game.",
                            "Queue",0);
                jButtonJoin.setEnabled(false);
                gui.getClient().sendReady();
            } catch(MaxPlayerReachedException e){
                displayMessage(e.getMessage(),"Queue",1);
            } catch(NameReservedException e){
                displayMessage(e.getMessage(),"Nickname",1 );
                jTextFieldNickname.requestFocusInWindow();
            } catch(RemoteException e){
                displayMessage("Cannot connect to Game-Server.\nPlease retry later.","Connection-Error",1);
            } catch (MalformedURLException e) {
                displayMessage("Cannot connect to Game-Server.\nThe specified URL was invalid.","Connection-Error",1);
            } catch (NotBoundException e) {
                displayMessage("Cannot connect to Game-Server.\nThe Game-Server is not running.","Connection-Error",1);
            }
        }
        else{
            displayMessage("You have forgotten to fill in your Nickname.","Nickname",0);
            jTextFieldNickname.requestFocusInWindow();
        }
    }
}

Wenn sich zwei Clients beim Server angemolden haben, ruft der Server (per RMI) die gameStart() Methode des GUIs auf, welche wiederum das Panel wechselt. Es scheint mir wirklich komisch, dass es nicht funktionieren will, da ich mit demselben Code keine solche Fehler bekomme wenn ich es normal als Applikation öffne..

EDIT

Habe mal rumgegoogled und ein bisschen über Swing und AWT drawing gelesen.
Ich bekomme immer so Screen Garbage, zuerst wird mir das GUI im JFrame angezeigt,
dann, wenn eine MessageBox kommt und ich sie wegclicke, wird es weiss dahinter. Hat das etwa mit "opacity" zu tun?

MfG
 
Zuletzt bearbeitet:
Hallo

Habe mich jetzt mal hingesetzt, um diesen KSKB zu schreiben. Ich habe keine Ahnung wo
ich anfangen soll, da das Projekt so komplex ist :bahnhof: (min. 50 Klassen).

Ich kann die Anwendung nicht wirklich auseinander reissen, ohne riesen Aufwand -.-
Was soll ich tun..
 
genau das ist die Kunst^^...das wichtige von dem unwichtigen zu unterscheiden.

Bau doch ein billiges JApplet, lasse 2 JPanels (mit Bildern bspw) per JButton wechseln und schaue, ob das Problem noch besteht....sollte alles klappen, sowohl außerhalb, als auch in der IDE...dann nehme deine entsprechende LayoutManager dazu, und immer so weiter...meistens kommt man dann sogar selbst auf die Lösung 😉
 
Also habe jetzt mal angefangen, funktioniert alles JPanel wechseln etc., muss jetzt
noch das MVC mit dem Server testen.. ich schreib nochmals wenn ich mehr weiss.

Scheint etwas mit RMI zu tun haben, glaube ich..
 
das bezweifel ich mal pauschal...da dein Frame ja nach dem resizen die richtigen Bilder anzeigt, hat es m.E. nur etwas mit den visuallen Komponenten zu tun.
 
Hmm.. komisch, habe jetzt alle meine MVC-Komponenten weggenommen und alles nach dem
Standard-Swing implementiert. Der Fehler scheint irgendwo dort zu liegen :/

Leider habe ich mein GUI mit NetBeans erstellt --> Code = unlesbar :shock:

EDIT:

Habe die Problemursache herausgefunden, ich versuche sie zu erläutern:
RMI-Methodenaufrufe auf dem GUI

Wenn sich beide GameClients beim Server angemolden haben, fängt dieser an
die Models zu initialisieren.
Java:
initMVC()
Er meldet die Models beim View an und sagt dem GUI dann, dass es jetzt das JPanel vom Home zum Game wechseln soll.
Java:
showGamePanel()

Dort passiert der Fehler. Wenn ich die GameClients anmelden lasse und der Server
anschliessend das JPanel wechselt gibt es so einen weissen Abdruck (Screen Garbage).

Wenn ich es selber tue (mittels JButton), funktioniert es wunderbar!
Ansonsten habe ich aber keine Ahnung, wie ich es beheben soll ???:L

Irgendwelche Vorschläge?

EDIT2:

Okay, die Bilder werden nach einer kleinen Weile beim Spielen verzerrt, wenn die JFrame
sich gegenseitig überlappen und es wird die Hälfte eines anderen Bildes angezeigt.

Meine Güte, das ist ja ein Albtraum, diese Applets!

EDIT3:

Nur zum nochmals nachfragen: Dass ist schon richtig so, dass
ich das GUI über den EDT laufen lasse?
Java:
java.awt.EventQueue.invokeAndWait(new Runnable())

Denn werden alle Aktionen innerhalb des GUI's über den EDT abgearbeitet.
Oder macht man das anders?

MfG
 
Zuletzt bearbeitet:
Hallo,

Ich habe dir hier noch einen Screenshot gemacht, damit du verstehst was ich meine.
GUI Screenshot

Es hat definitiv mit dem Zugriff des Servers auf das GUI zu tun, also die Updates
der Models auf das View.

Wenn ich die View Updates durch die Models auslasse, dann funktioniert der Code.
Soll ich noch den Code für die Models/Views anhängen (wären einige) ?

Ich glaube wir kommen der Sache näher..

MfG
 

Zurück
Oben