Vale, creo que entiendo lo que pides.
A ver, esta sería mi clase Preguntas
Es un array con los String de cada pregunta.
Uso una variable como índice para apuntar a la pregunta que actualmente se estará mostrando en la interfaz.
Dispone de unos métodos para apuntar a la pregunta siguiente o a la anterior, siempre controlando que el índice se mantenga dentro de los límites.
Otro método retorna la pregunta a la que se está apuntando actualmente.
public class Preguntas {
private final String[] PREGUNTAS = {
"1. Torpe o entumecido", "2. Acalorado", "3. Con temblor en las piernas",
"4. Incapaz de relajarse", "5. Con temor a que ocurra lo peor","6. Mareado, o que se le va la cabeza",
"7. Con latidos del corazón fuertes y acelerados","8. Inestable","9. Atemorizado o asustado",
"10. Nervioso","11. Con sensación de bloqueo","12. Con temblores en las manos",
"13. Inquieto, inseguro","14. Con miedo a perder el control","15. Con sensación de ahogo",
"16. Con temor a morir","17. Con miedo","18. Con problemas digestivos",
"19. Con desvanecimientos","20. Con rubor facial","21. Con sudores, frios o calientes"
};
public int actual; //Índice de la pregunta que actualmente se estará mostrando
public Preguntas() {
actual = 0; //Comienza por la primera pregunta
}
public void siguiente() {
//Incrementamos índice
actual++;
//Comprobamos que no hemos rebasado el límite del array de PREGUNTAS
if (actual == PREGUNTAS.length)
actual--;
}
public void anterior() {
//Decrementamos índice
actual--;
//Comprobamos que no estamos en índice negativo
if (actual < 0)
actual = 0;
}
public String getActual() {
return PREGUNTAS[actual];
}
}
Luego he creado una clase llamada PanelInventario que hereda de JPanel.
Va a modelar la interfaz que se ve en pantalla, pero además va a llevar todo el peso de la aplicación.
Así que entre sus atributos va a tener un objeto de la clase Preguntas que se encargará de suministrar las preguntas a un JLabel.
Tendrá también un Stack<Integer> para almacenar las respuestas que el usuario vaya dando en el JTextField.
Al JTextField, le he añadido un KeyListener para que haga un filtrado de lo que se teclea. Está programado para aceptar solo un dígito, y solo uno, entre 0 y 3.
Cualquier otro carácter será ignorado y NO se podrá introducir dos o más caracteres, solo uno.
De esta manera nos aseguramos que el Stack solo recibirá respuestas válidas.
Los botones de Regresar y Avanzar son los que hacen pop() y push(), respectivamente.
Cuando se pulsa Avanzar se hace push() con el valor introducido y se pasa a la siguiente pregunta.
Si se pulsa Regresar, se hace pop() para sacar el último valor introducido y se retrocede a la pregunta anterior.
En ambos casos se comprueba que botones conviene que se activen o desactiven.
Por ejemplo, si ya estamos en la última pregunta, el botón Avanzar se desactiva y se activa el botón Terminar, pero el de Regresar permanece activo.
Si regresamos, el botón Avanzar se reactiva y el de Terminar vuelve a quedar desactivado.
El botón de Terminar lo que hace es "popear" todos los valores del Stack y sumarlos para calcular un promedio que se mostrará en pantalla.
Tras esto, el inventario queda reseteado para poder repetir de nuevo el cuestionario.
public class PanelInventario extends JPanel {
private final String[] RESPUESTAS = {"[0]En Absoluto", "[1]Levemente",
"[2]Moderadamente","[3]Severamente"};
private Preguntas preguntas;
private Stack<Integer> respuestas;
private JLabel jlPregunta;
private JTextField jtRespuesta;
private JButton btRegresar;
private JButton btAvanzar;
private JButton btTerminar;
public PanelInventario() {
iniciarComponentes();
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Inventario de Ansiedad de Beck(BAI)"),
BorderFactory.createEmptyBorder(25, 25, 25, 25)));
JPanel pnPregunta = new JPanel();
pnPregunta.setLayout(new FlowLayout(FlowLayout.LEFT));
pnPregunta.add(jlPregunta);
JPanel pnRespuestas = new JPanel();
pnRespuestas.setLayout(new GridLayout(1, 4, 20, 0));
for (String resp: RESPUESTAS)
pnRespuestas.add(new JLabel(resp));
pnRespuestas.setBorder(BorderFactory.createEmptyBorder(10, 25, 10, 0));
JPanel pnRespuesta = new JPanel();
pnRespuesta.add(new JLabel("Responde [0-3]: "));
pnRespuesta.add(jtRespuesta);
JPanel pnSeleccion = new JPanel();
pnSeleccion.setLayout(new GridLayout(1,2));
JPanel pnReg = new JPanel();
pnReg.add(btRegresar);
JPanel pnAva = new JPanel();
pnAva.add(btAvanzar);
pnSeleccion.add(pnReg);
pnSeleccion.add(pnAva);
JPanel pnTer = new JPanel();
pnTer.add(btTerminar);
add(pnPregunta);
add(new JSeparator());
add(pnRespuestas);
add(new JSeparator());
add(pnRespuesta);
add(pnSeleccion);
add(pnTer);
}
private void iniciarComponentes() {
preguntas = new Preguntas();
respuestas = new Stack<Integer>();
jlPregunta = new JLabel(preguntas.getActual());
jlPregunta.setFont(new Font("Verdana", Font.BOLD, 20));
jtRespuesta = new JTextField(4);
jtRespuesta.addKeyListener(new SoloNumeros());
btRegresar = new JButton("<< Regresar");
btRegresar.addActionListener(new AccionRegresar());
btRegresar.setEnabled(false);
btAvanzar = new JButton("Avanzar >>");
btAvanzar.addActionListener(new AccionAvanzar());
btTerminar = new JButton("Terminar Test");
btTerminar.addActionListener(new AccionTerminar());
btTerminar.setEnabled(false);
}
/*
* Hace que el campo de texto únicamente pueda aceptar
* un único digito entre 0 y 3
*/
private class SoloNumeros implements KeyListener{
@Override
public void keyTyped(KeyEvent e) {
char caracter = e.getKeyChar();
switch (caracter) {
case '0':
case '1':
case '2':
case '3':
//Aceptable, pero solo si el campo esta vacío
if (!jtRespuesta.getText().isEmpty())
e.consume(); //Cosumimos, no queremos más caracteres.
else
jtRespuesta.setText(String.valueOf(caracter)); //Dígito aceptado
default:
e.consume(); //Consumimos, no es un dígito entre 0 y 3
}
}
@Override
public void keyPressed(KeyEvent e) {}
@Override
public void keyReleased(KeyEvent e) {}
}
private class AccionRegresar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//Extraemos última respuesta y la colocamos en pantalla
jtRespuesta.setText(respuestas.pop().toString());
//Recuperamos pregunta anterior
preguntas.anterior();
jlPregunta.setText(preguntas.getActual());
//Comprobamos que el boton avanzar queda activado
btAvanzar.setEnabled(true);
//El botón terminar queda obligatoriamente desactivado
btTerminar.setEnabled(false);
//El boton regresar, se desactiva si estamos en la primera
//pregunta, es decir, si el stack esta vacío
btRegresar.setEnabled(!respuestas.isEmpty());
jtRespuesta.requestFocus();
}
}
private class AccionAvanzar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//Recogemos respuesta, si es que la hay
if (jtRespuesta.getText().isBlank())
//No hay
JOptionPane.showMessageDialog(null, "Ha de dar una respuesta",
"Responder", JOptionPane.WARNING_MESSAGE);
else {
//Sí hay respuesta, la guardamos en el Stack
respuestas.push(Integer.parseInt(jtRespuesta.getText()));
//Comprobamos si el stack ya está completo
if (respuestas.size() == 20) {
//Completo, se desactiva el botón avanzar y se activa terminar
btAvanzar.setEnabled(false);
btTerminar.setEnabled(true);
btTerminar.requestFocus();
}
else {//No está completo
//Siguiente pregunta
preguntas.siguiente();
jtRespuesta.setText(null);
jlPregunta.setText(preguntas.getActual());
//Nos aseguramos que el botón regresar está activo
btRegresar.setEnabled(true);
jtRespuesta.requestFocus();
}
}
}
}
private class AccionTerminar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//Calculamos el promedio
int suma = 0;
//Vamos vaciando el stack y sumando sus valores
while(!respuestas.isEmpty())
suma += respuestas.pop();
float promedio = suma / 21f;
//Mostramos
JOptionPane.showMessageDialog(null, String.format("Promedio: %.2f",promedio),
"Terminar Test", JOptionPane.INFORMATION_MESSAGE);
//Reinicia panel
preguntas.actual = 0;
jlPregunta.setText(preguntas.getActual());
jtRespuesta.setText(null);
btTerminar.setEnabled(false);
btAvanzar.setEnabled(true);
btRegresar.setEnabled(false);
jtRespuesta.requestFocus();
}
}
}
Por último, una clase Main, que no tiene nada de especial.
Tan solo modela el JFrame principal, muestra un objeto de PanelInventario, que es quien hace todo el trabajo importante, y pone la aplicación en marcha.
public class Main extends JFrame{
public Main() {
JPanel pnPrincipal = new JPanel();
pnPrincipal.add(new PanelInventario());
pnPrincipal.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
setContentPane(pnPrincipal);
setTitle("Inventario con Stack");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Main();
}
});
}
}
No he hecho ninguna clase Respuestas. Podría haberse hecho, y que gestionara ella el Stack de respuestas.
Pero requiere de tan poca funcionalidad (hacer push y pop) que lo he puesto directamente todo en la clase PanelInventario, para ir más rápido.
Habría quedado más elegante, eso sí.
Creo que con los comentarios que tiene el código se entiende. Cualquier duda solo tienes que preguntar.
O si hay algo que debiera ser distinto, coméntalo por aquí.
Un saludo.