AWT Einzelne Komponenten zur Laufzeit austauschen?

PinkMuffin

Bekanntes Mitglied
Hallo,
ich habe wieder ein Problem mit einer GUI..
Es geht wieder um ein Quiz. Das letzte Quiz habe ich (mit Forenhilfe) mit einem CardLayout gelöst. Im Prinzip steht es mir frei, meine derzeitige Lösung ist, dass jedes mal ein neuer FrageFrame erstellt und der alte disposed wird, aber das führt zu einem recht unschönem Ergebnis, weil es dann eben "blinkt", wenn man eine Antwort abgibt. Ich möchte, dass spezielle Komponenten ersetzt werden, wenn ich einen Button drücke, aber es geht nicht.
Die Frage (und die Antworten) bleibt immer gleich, der Rest geht allerdings und man kommt auch auf den ScoreFrame am Ende.

[CODE lang="java" title="Controller"]public class Controller
{
private Spiel spiel;
StartFrame startFrame;
ScoreFrame scoreFrame;
FrageFrame frageFrame;
private int aktuelleFrage=0;

public Controller()
{
spiel = new Spiel();
}

public boolean erhoeheFrage()
{
aktuelleFrage++;
if (aktuelleFrage>=spiel.getFrageListe().size())
return false;
return true;

}

public void erhoeheScore()
{
spiel.getAktiverSpieler().erhoeheScore();
}

//Frame-Anzeige-Methoden
public void zeigeStartFrame()
{
startFrame = new StartFrame(this);
}

public void zeigeScoreFrame()
{
scoreFrame = new ScoreFrame(spiel.getSpielerListe(), this);
frageFrame.dispose();
}

public void zeigeFrageFrame() //Braucht aktuelle Frage
{
frageFrame = new FrageFrame(aktuelleFrage, spiel.getFrageListe(), this);
}

public void setAktuelleFrage(int aktuelleFrage)
{
this.aktuelleFrage = aktuelleFrage;
}

public void aktualisiereFrage()
{
frageFrame.setAktuelleFrage(aktuelleFrage);
frageFrame.repaint();
}


}[/CODE]

[CODE lang="java" title="FrageFrame"]public class FrageFrame extends JFrame
{
int aktuelleFrage;
ArrayList <Frage>frageListe;
private JButton[] buttons;
private JPanel buttonPanel1, buttonPanel2, helpPanel, fragePanel;
private Controller control;

public FrageFrame(int aktuelleFrage, ArrayList <Frage>frageListe, Controller control)
{
this.aktuelleFrage = aktuelleFrage;
this.frageListe = frageListe;
this.control = control;

this.setTitle("Cortility-Quiz");
this.setBounds(0, 0, 600, 350);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel fragePanel = new JPanel();
JLabel frage = setzeLabel(aktuelleFrage);
fragePanel.setBackground(Color.decode("#E0006C"));
fragePanel.add(frage);

//Zufallsbefuellung der Buttons später evtl normale Befuellung und Zufallsverteilung
buttons = buttonsBefuellen();

buttonPanel1 = new JPanel();
buttonPanel2 = new JPanel();
buttonPanel1.add(buttons[0]);
buttonPanel1.add(buttons[1]);
buttonPanel2.add(buttons[2]);
buttonPanel2.add(buttons[3]);

this.getContentPane().setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));
this.getContentPane().setBackground(Color.decode("#D1DCE3"));
buttonPanel1.setBackground(Color.decode("#D1DCE3"));
buttonPanel2.setBackground(Color.decode("#D1DCE3"));
this.add(fragePanel);
this.getContentPane().add(Box.createVerticalStrut(30));
this.add(buttonPanel1);
this.add(buttonPanel2);

this.setLocationRelativeTo(null);
this.setVisible(true);

}

public JButton[] buttonsBefuellen()
{
JButton[] buttons = new JButton[4];
//FrageButtonListener richtigeAntwortListener = new FrageButtonListener(true, this);
//FrageButtonListener falscheAntwortListener = new FrageButtonListener(false, this);

boolean buttonsLeer = true;
do
{
int leereButtons=4;
for(int i=0; i<3😉
{
AntwortListener antwortListenerFalse = new AntwortListener(control, false);
Random zufall = new Random();
int buttonWahl = zufall.nextInt(4);
if(buttons[buttonWahl]==null)
{
//Button generieren
buttons[buttonWahl] = new JButton(frageListe.get(aktuelleFrage).getFalscheAntworten(i));
buttons[buttonWahl].setBackground(Color.white);
buttons[buttonWahl].setForeground(Color.decode("#66808d"));
buttons[buttonWahl].setPreferredSize(new Dimension((this.getWidth()-50)/4, this.getHeight()/4));
buttons[buttonWahl].addActionListener(antwortListenerFalse);

leereButtons--;
i++;
}
}

//Sobald drei Buttons befüllt sind, erhält der letzte Button die richtige Antwort.
if(leereButtons == 1)
{
for(int i = 0; i<buttons.length; i++)
{
if(buttons==null)
{
AntwortListener antwortListenerTrue = new AntwortListener(control, true);
buttons = new JButton(frageListe.get(aktuelleFrage).getRichtigeAntwort());
buttons.setBackground(Color.white);
buttons.setForeground(Color.decode("#66808d"));
buttons.setPreferredSize(new Dimension((this.getWidth()-50)/4, this.getHeight()/4));
buttons.addActionListener(antwortListenerTrue);
buttonsLeer = false;
}
}
}
}while(buttonsLeer);
return buttons;
}

public JLabel setzeLabel(int aktuelleFrage)
{
JLabel frage = new JLabel(frageListe.get(aktuelleFrage).getFrage());
frage.setFont(new Font("Serif", 0, 20));
frage.setForeground(Color.WHITE);
return frage;
}

public void setAktuelleFrage(int aktuelleFrage)
{
this.aktuelleFrage = aktuelleFrage;
}

}
[/CODE]

[CODE lang="java" title="Listener für die Buttons"]public class AntwortListener implements ActionListener
{
Controller control;
boolean richtig;

public AntwortListener(Controller control, boolean richtig)
{
this.control = control;
this.richtig = richtig;
}

@Override
public void actionPerformed(ActionEvent arg0)
{

if (richtig)
control.erhoeheScore();
//control.frageFrame.dispose();
if(control.erhoeheFrage())
{
//control.zeigeFrageFrame();
control.aktualisiereFrage();
}
else
control.zeigeScoreFrame();
}

}[/CODE]
 
EDIT:
Ich hab jetzt ein bisschen rumgebastelt und wenn ich folgendes in den FrageFrame einbaue,

Java:
    public void neuZeichnen()
    {
        this.remove(fragePanel);
        this.remove(buttonPanel1);
        this.remove(buttonPanel2);
       
        fragePanel = setzeFragePanel(); // ist das gleiche, wie vorher setze Label, nur wird hier gleich das ganze Panel erzeugt
       
        buttonPanel1.remove(buttons[0]);
        buttonPanel1.remove(buttons[1]);
        buttonPanel2.remove(buttons[2]);
        buttonPanel2.remove(buttons[3]);
        buttons = buttonsBefuellen();
        buttonPanel1.add(buttons[0]);
        buttonPanel1.add(buttons[1]);
        buttonPanel2.add(buttons[2]);
        buttonPanel2.add(buttons[3]);
       
        this.add(fragePanel);
        this.add(buttonPanel1);
        this.add(buttonPanel2);
       
        this.repaint();
    }

dann ändert sich was am FrageFrame, allerdings wird das adden der Elemente komplett ignoriert. (Oder zumindest nicht so ausgeführt, wie ich das gedacht hätte. Der erste Frame ist noch richtig, aber der zweite ist dann komplett leer. Ich hab spaßeshalber mal das remove weggelassen, dann bleibt mein FragePanel mit der Frage unverändert stehen (obwohl es sich verändern sollte) und die Buttons fehlen aber trotzdem..
 
Wenn das Layout selbst bleibt:: Wieso änderst Du denn dann nicht einfach nur den Text der Buttons und so? Immer alles neu aufbauen ist recht umständlich und so doch auch nicht notwendig.
 
Wenn das Layout selbst bleibt:: Wieso änderst Du denn dann nicht einfach nur den Text der Buttons und so? Immer alles neu aufbauen ist recht umständlich und so doch auch nicht notwendig.
Ja, vermutlich fast schon ein Beispiel für Overengineering, ich hab mir das alles durch die umständliche Zufallsgenerierung komplizierter gemacht, als es eigentlich war (weil ja zwei verschiedene Listener gebraucht wurden) 😅
vielen Dank für den Tipp, jetzt funktioniert alles 😀
Manchmal bin ich ein Idiot. Ich schiebe die Änderung der Buttongenerierung jetzt schon Stunden vor mir her, weil ich mir die Arbeit sparen wollte, dabei hat es nicht mal 10 Minuten gedauert und alles andere einfacher gemacht

Falls jemand ein ähnliches Problem hat:
Die zufällige Verteilung von Buttons lässt sich so relativ gut lösen:
[CODE lang="java" title="Zufallsverteilung von Buttons"]import java.awt.GridLayout;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ButtonFrame extends JFrame
{
private JButton[] buttons;
private JPanel buttonPanel;


public ButtonFrame()
{
this.setTitle("Title");
this.setBounds(0, 0, 600, 350);
this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);

buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(2,2));
buttonsBefuellen();
buttonsZuordnen();
this.add(buttonPanel);
this.setLocationRelativeTo(null);
this.setVisible(true);
}

public void buttonsBefuellen()
{
buttons = new JButton[4];
ButtonListener listenerFalsch = new ButtonListener();
ButtonListener listenerRichtig = new ButtonListener();
for(int i=0; i<3; i++)
{
buttons = new JButton("falsche Antwort");
buttons.addActionListener(listenerFalsch);
}
buttons[3]= new JButton("richtige Antwort");
buttons[3].addActionListener(listenerRichtig);

}

public void buttonsZuordnen()
{
int buttonsVerteilt = 0;
Random zufall = new Random();
do
{
int buttonWahl = zufall.nextInt(4);
if(buttons[buttonWahl]!= null)
{
buttonPanel.add(buttons[buttonWahl]);
buttons[buttonWahl]=null;
buttonsVerteilt++;
}

}while(buttonsVerteilt!=4);


}

}[/CODE]

Und die Methode, die dann den Frame neu schreibt, sieht jetzt so aus:
Java:
    public void neuZeichnen()
    {
        frage.setText(frageListe.get(aktuelleFrage).getFrage());
        buttonPanel.removeAll();
       
        buttonsBefuellen();
        buttonsZuordnen();

        this.repaint();
    }
 

Neue Themen


Zurück
Oben