Mostrar Mensajes

Esta sección te permite ver todos los posts escritos por este usuario. Ten en cuenta que sólo puedes ver los posts escritos en zonas a las que tienes acceso en este momento.


Mensajes - Kabuto

Páginas: 1 ... 18 19 20 21 22 [23] 24 25 26 27 28 ... 50
441
Si, es por el Console.ReadKey() que no se lo puse.

Yo es que programo desde Visual Studio, y automáticamente te mantiene la consola abierta sin tener que usar un ReadKey()

442
Algo he podido avanzar, no mucho.
He escrito lo que vendría a ser el "modelo" de las Unidades, es decir, la clase Unidad y la clase que gestionaría las Unidades.
En realidad es todo muy parecido a las clases ya escritas para  la gestión de Terminales: guardar en txt, leerlo, registrar Unidad, modificar, eliminar....generar una placa al azar que sea única, un método para retornar las Unidades registradas en un array primitivo y así poder mostrarlas en un ComboBox rápidamente...
La lógica a seguir es la misma, solo cambia la entidad que se va a gestionar.

Esta sería la clase Unidad:
Código: [Seleccionar]
public final class Unidad {

private String placa;
private int capacidad;
private String nombreTerminal;

public Unidad(String placa, int capacidad, String nombreTerminal) {
this.placa = placa;
this.capacidad = capacidad;
this.nombreTerminal = nombreTerminal;
}

public String getPlaca() {
return placa;
}

public void setPlaca(String placa) {
this.placa = placa;
}

public int getCapacidad() {
return capacidad;
}

public void setCapacidad(int capacidad) {
this.capacidad = capacidad;
}

public String getNombreTerminal() {
return nombreTerminal;
}

public void setNombreTerminal(String nombreTerminal) {
this.nombreTerminal = nombreTerminal;
}

public String toTXT() {
return String.format("%s -- %d -- %s", placa, capacidad, nombreTerminal);
}

@Override
public String toString() {
return String.format("%s -- %s", placa, nombreTerminal);
}

@Override
public boolean equals(Object objeto) {
if (objeto instanceof Unidad) {
Unidad otraUnidad = (Unidad) objeto;
return placa.equals(otraUnidad.placa);
}
else
return false;
}

}

Y la clase GestorUnidad:
Código: [Seleccionar]
public final class GestorUnidad {

private ArrayList<Unidad> unidades;

public GestorUnidad() {
unidades = new ArrayList<Unidad>();
cargarDatos();
}

private void cargarDatos() {

try {
BufferedReader br = new BufferedReader(new FileReader("unidades.txt"));
String linea = br.readLine();

while(linea != null) {

//Separamos datos contenidos en la linea
String[] datos = linea.split(" -- ");
//Creamos una Unidad con los datos de esta línea
unidades.add(new Unidad(datos[0], Integer.valueOf(datos[1]), datos[2]));
//siguiente linea
linea = br.readLine();
}

br.close();

} catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(null, "No se encuentra archivo: unidades.txt\n"
+ "Se intentará generar uno nuevo cuando se registre una Unidad nueva",
"Cargar Datos Unidades", JOptionPane.WARNING_MESSAGE);
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "Error intentando leer: unidades.txt",
"Cargar Datos Unidades", JOptionPane.WARNING_MESSAGE);
} catch (Exception error) {
JOptionPane.showMessageDialog(null, "Error recuperando datos de: unidades.txt\n"
+ "Error:\n" + error.getLocalizedMessage(),
"Cargar Datos Unidades", JOptionPane.WARNING_MESSAGE);
}
}

private void guardarDatos() {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter("unidades.txt", false));
//Por cada Unidad, creamos una línea de texto en el archivo
for (Unidad und: unidades) {
bw.write(und.toTXT());
bw.newLine();
}
bw.close();
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Error intentando guardar: unidades.txt",
"Guardar Datos Unidades", JOptionPane.WARNING_MESSAGE);
}
}

public boolean registrarUnidad(Unidad und) {
if (unidades.contains(und)) {
JOptionPane.showMessageDialog(null, "Ya existe una Unidad registrada con esta placa",
"Registrar Unidad", JOptionPane.WARNING_MESSAGE);
return false;
}
else if (cuentaTerminalesAsignadas(und.getNombreTerminal()) >= 2) {
JOptionPane.showMessageDialog(null, "Ya existen dos Unidades asignadas a la Terminal: "
+ und.getNombreTerminal() +"\nDeberá asignar esta Unidad a otra Terminal",
"Registrar Unidad", JOptionPane.WARNING_MESSAGE);
return false;
}
else {
unidades.add(und);
JOptionPane.showMessageDialog(null, "Nueva Unidad registrada",
"Registrar Unidad", JOptionPane.INFORMATION_MESSAGE);
guardarDatos();
return true;
}
}

public void modificarUnidad(Unidad und) {
//Buscamos la Unidad correspondiente y transferimos atributos
boolean modificacionAceptada = true;
for (Unidad unidad: unidades) {
if (unidad.equals(und)) {
//Si no varía la terminal asignada, no se requiere comprobación extra
if (unidad.getNombreTerminal().equals(und.getNombreTerminal()))
unidad.setCapacidad(und.getCapacidad()); //Único atributo que puede variar es capacidad
else {
//Terminal asignada varía. Hay que comprobar
if (cuentaTerminalesAsignadas(und.getNombreTerminal()) >= 2) {
JOptionPane.showMessageDialog(null, "Ya existen dos Unidades asignadas a la Terminal: "
+ und.getNombreTerminal() +"\nNo se puede aceptar este cambio",
"Modificar Unidad", JOptionPane.WARNING_MESSAGE);
modificacionAceptada = false;
}
else {
unidad.setCapacidad(und.getCapacidad());
unidad.setNombreTerminal(und.getNombreTerminal());
}
}
break;
}
}

if (modificacionAceptada) {
JOptionPane.showMessageDialog(null, "Unidad modificada",
"Modificar Unidad", JOptionPane.INFORMATION_MESSAGE);
guardarDatos();
}

}

public boolean borrarTerminal(Unidad und) {
int respuesta = JOptionPane.showConfirmDialog(null, "¿Confirma que desea eliminar esta Unidad",
"Eliminar Unidad", JOptionPane.YES_NO_OPTION);

if (respuesta == JOptionPane.YES_OPTION && unidades.remove(und)) {
guardarDatos();
return true;
}
else
return false;
}

/**
* Hace un recuento de cuantas Unidades tienen asignadas la
* Terminal indicada como argumento.<br>Cada Terminal solo puede
* tener hasta dos Unidades asignadas, así que antes de registrar
* una Unidad hay que controla esta limitación.
* @param nomTerminal Nombre de la Terminal a consultar.
* @return Cantidad de Unidades asignadas a la Terminal consultada.
*/
private int cuentaTerminalesAsignadas(String nomTerminal) {
int cont = 0;
for (Unidad und: unidades)
if (und.getNombreTerminal().equals(nomTerminal))
cont++;

return cont;
}

//TODO: metodo de generar placas y posible array para combobox

/**
* Construye una placa al azar y la retorna tras comprobar que es
* única.<br>Una placa se compone de tres consonantes y un número de
* tres dígitos.<br>Ejemplo: <i>[ABC000]</i>
* @return
*/
public String getPlaca() {
final char[] consonantes = {'B','C','D','F','G','H','J','K','L','M','N','P','Q','R','S',
'T','V','W','X','Y','Z'};
Random azar = new Random();
StringBuilder placa = new StringBuilder();
boolean esUnico = false;

while(!esUnico) {
//Primero obtenemos tres consonantes random
for (int i = 0; i < 3; i++)
placa.append(consonantes[azar.nextInt(consonantes.length)]);
//Y ahora un número de 3 dígitos, entre 000 y 999
placa.append(String.format("%03d", azar.nextInt(1000)));
//Comprobamos si existe alguna unidad con esta placa
esUnico = true;
for (Unidad und: unidades)
if (und.getPlaca().equals(placa.toString()))
esUnico = false; //Placa repetida, el bucle lo intentará de nuevo
}

return placa.toString();
}

public Unidad[] getArrayUnidades() {
return unidades.toArray(new Unidad[unidades.size()]);
}

}


Ahora habría que hacer la "vista", un panel para la gestión de Unidades, que al igual que el "modelo", será prácticamente copiar lo ya hecho para la gestión de Terminales, pero adaptado a la entidad/clase Unidad.

443
Hola.
Tu programa funciona pero no muestra los resultados al final por un error de sintaxis cuando intentas concatenar variables y cadenas de texto.
Tú lo haces separando con comas.

Citar
            Console.WriteLine("<==========>");
            Console.WriteLine(nombre1, " = ",promedio1 );
            Console.WriteLine("<==========>");
            Console.WriteLine(nombre2, " = ", promedio2);
            Console.WriteLine("<==========>");
            Console.WriteLine(nombre3, " = ", promedio3);
            Console.WriteLine("<==========>");
            Console.WriteLine(nombre4, " = ", promedio4);

Para concatenar, se usa el símbolo de sumar +
Citar
            Console.WriteLine("<==========>");
            Console.WriteLine(nombre1 + " = " + promedio1);
            Console.WriteLine("<==========>");
            Console.WriteLine(nombre2 + " = " + promedio2);
            Console.WriteLine("<==========>");
            Console.WriteLine(nombre3 + " = " + promedio3);
            Console.WriteLine("<==========>");
            Console.WriteLine(nombre4 + " = " + promedio4);

Las comas sí se usan cuando en la cadena ponemos caracteres "comodín", encerrados entre llaves e identificándolos con números para indicar el orden de la variable que los sustituye.
Por ejemplo:
Código: [Seleccionar]
Console.WriteLine("{0} = {1}", nombre1, promedio1 );
Al margen de esto...
...como tú mismo ya te has dado cuenta, tu solución no es la más óptima.
Para 5 alumnos, fíjate la cantidad de variables y líneas de instrucciones repetitivas que has tenido que usar.

Pues imagina si te pidieran hacerlo para los 30 alumnos de una clase...., o para los 300 alumnos de todo el centro de estudios.

Usando arrays y bucles, se puede hacer con menos líneas de código, sin importar si son 5 alumnos, 500 ó 50 millones...
Las líneas de código serán las mismas.

Te pongo una solución usando un vector para los nombres y una matriz para las calificaciones.
Al principio, el programa pregunta cuántos alumnos se quieren ingresar, así se puede ver que el código será el mismo sin importar el número de alumnos.

Míratelo, pruébalo, y pregunta si hay algo que no entiendes.
Un saludo.

Código: [Seleccionar]
static void Main(string[] args)
        {
            //Vector para los nombres
            string[] alumnos;
            //Matriz para las calificaciones
            double[,] notas;

            Console.Write("Cuantos alumnos quiere ingresar?: ");
            int numAlumnos = Int32.Parse(Console.ReadLine());

            //Inicializamos los arrays con la cantidad de alumnos indicada
            alumnos = new string[numAlumnos];
            notas = new double[numAlumnos,4]; //4 notas por cada alumno

            //Con 2 bucles anidados, iremos pidiendo nombres de alumnos y sus 4 notas
            for (int i = 0; i < numAlumnos; i++)
            {
                Console.WriteLine("\nAlumno #" + (i+1));
                Console.Write("Nombre: ");
                alumnos[i] = Console.ReadLine();
                //Tenemos nombre, pedimos notas
                for (int j = 0; j < 4; j++)
                {
                    Console.Write("Nota #{0}: ", (j+1));
                    notas[i, j] = Double.Parse(Console.ReadLine());
                }
                Console.WriteLine("\n\t***Alumno Registrado***\n");
            }


            //Disponemos de todos los datos, pasamos a calcular y mostrar los promedios.
            Console.WriteLine("\n\tPROMEDIO DE NOTAS\n");
            for (int i = 0; i < numAlumnos; i++)
            {
                //Sumamos las 4 notas de este alumno
                double sumaNotas = 0d;
                for (int j = 0; j < 4; j++)
                    sumaNotas += notas[i, j];
                //Mostramos su nombre y promedio
                double promedio = sumaNotas / 4d;
                Console.WriteLine("{0} --> {1:f2}", alumnos[i], promedio);
            }

            Console.WriteLine("\n\tFIN DE PROGRAMA");

        }

444
hola, si ese fue unas de las  partes del enunciado que no pude hacer porque no sabia como hacerlo, me refiero ( que una Terminal no puede ser eliminada, ni modificada, si ya está asignada a una Ruta.)

Aún no he llegado a eso, primero habría que ponerse con la gestión de Unidades, pero si estoy rumiando en mi mente en cómo se podría resolver esa parte.

Supongo que lo más probable es que, puesto seguramente haremos una clase que se dedique a gestionar Rutas, le podremos escribir un método de tipo boolean que reciba una Terminal y nos diga si actualmente está asignada a alguna Ruta o no.

Así, antes de aceptar ninguna modificación o eliminación, preguntaremos al gestor de Rutas.

Incluso, se puede valorar añadir un atributo boolean a las Terminales que cuando esté asignada a una Ruta tenga valor TRUE y cuando no, sea FALSE.
Usando ese boolean, podemos hacer que el formulario de Gestión de Terminales desactive automáticamente los botones de "modificar" y "eliminar" cuando en el ComboBox seleccionamos una Terminal que está asignada a alguna Ruta.
Pero esto implicaría añadir más código extra, ya veremos...

445
Sería importante ver tu código para poder decirte que es lo que está mal.

Por otra parte, en principio tu planteamiento es correcto.
Para los nombres de alumnos, un array de 5 elementos string.

Para las notas, lo ideal sería una matriz de 5x4 (5 alumnos, 4 notas por cada alumno)

Insisto, publica tu código y corregimos lo que esté mal.

446
Ya tengo las funcionalidades de "modificar" y "eliminar" Terminal.

En la clase GestionTerminales añadimos estos dos métodos:

Código: [Seleccionar]
public void modificarTerminal(Terminal ter) {
//Buscamos la Terminal equivalente y transferimos los atributos
boolean modificacionAceptada = true;
for (Terminal terminal: terminales) {
if (terminal.equals(ter)) {
//Si el lugar es el mismo, no requiere comprobación previa
if (terminal.getLugar().equals(ter.getLugar())) {
terminal.setNomTerminal(ter.getNomTerminal());
terminal.setNumTerminal(ter.getNumTerminal());
}
else { //Lugar es distinto, requiere comprobación
if (cuentaTerminalesEnLugar(ter.getLugar()) >= 2 ) {
JOptionPane.showMessageDialog(null, "Ya existen dos Terminales en: " + ter.getLugar()
+ "\nNo se puede aceptar este cambio", "Modificar Terminal", JOptionPane.WARNING_MESSAGE);
modificacionAceptada = false;
}
else {
terminal.setNomTerminal(ter.getNomTerminal());
terminal.setLugar(ter.getLugar());
terminal.setNumTerminal(ter.getNumTerminal());
}
}
//Detenemos bucle for
break;
}
}

if (modificacionAceptada) {
JOptionPane.showMessageDialog(null, "Terminal modificada",
"Modificar Terminal", JOptionPane.INFORMATION_MESSAGE);
guardarDatos();
}
}

Código: [Seleccionar]
public boolean borrarTerminal(Terminal ter) {
int respuesta = JOptionPane.showConfirmDialog(null, "¿Confirma que desea eliminar esta Terminal",
"Eliminar Terminal", JOptionPane.YES_NO_OPTION);

if (respuesta == JOptionPane.YES_OPTION && terminales.remove(ter)) {
guardarDatos();
return true;
}
else
return false;
}

Son muy sencillos, ambos reciben un objeto Terminal, que es el que nos proporciona el Panel de Gestión de Terminales con los datos del formulario.

Para modificar, se busca el equivalente en el ArrayList y se le transfieren los datos de los atributos.
En el caso de que se haya modificado el Lugar, primero se comprueba si este cambio es posible debido a la limitación de solo dos Terminales en un mismo Lugar.

Para eliminar, simplemente se pide confirmación antes de eliminar del ArrayList.

En la clase PanelTerminal, solo hay que añadir dos métodos más, que serán los encargados de setear las acciones que vamos a escribir en el Main.

Código: [Seleccionar]
public void setAccionModificar(ActionListener accion) {
btModificar.addActionListener(accion);
}

public void setAccionEliminar(ActionListener accion) {
btEliminar.addActionListener(accion);
}

Y ahora sí en la clase Main escribimos la acciones.

Son muy simples, para modificar, pedimos al PanelTerminal que nos de la Terminal modificada y se la pasamos al gestor de terminales que ya sabe lo que hay que hacer.

Código: [Seleccionar]
private class AccionModificarTerminal implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
Terminal modificada = pnTerminal.getTerminal();
if (modificada != null)
terminales.modificarTerminal(modificada);
}
}

Y para borrar Terminal, muy parecido, solo que esta vez deberemos actualizar el JComboBox para que no figure la Terminal que ha sido eliminada:
Código: [Seleccionar]
private class AccionBorrarTerminal implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
Terminal borrar = pnTerminal.getTerminal();
if (borrar != null) {
if (terminales.borrarTerminal(borrar)) {
JOptionPane.showMessageDialog(null, "Terminal Eliminada",
"Eliminar Terminal", JOptionPane.INFORMATION_MESSAGE);
pnTerminal.actualizarPanel(terminales.getArrayTerminales());
}
}
}
}

No olvidemos setear estas acciones al PanelTerminal desde el constructor de Main:
Código: [Seleccionar]
pnTerminal.setAccionModificar(new AccionModificarTerminal());
pnTerminal.setAccionEliminar(new AccionBorrarTerminal());

Y listo, con esto acabaríamos con las Terminales.

Bueno, no del todo, porque el enunciado establece que una Terminal no puede ser eliminada, ni modificada, si ya está asignada a una Ruta.
Pero como aún no hemos llegado a las Rutas, pues esta limitación habrá que dejarla para más adelante.

447
Señalo en rojo los cambios.
Primero añadir el gestor y el panel como atributos de clase:
Citar
public class Main extends JFrame{

   //Usuario que ha logueado, puede ser Admin o Pasajero
   private Usuario logueado;

   //Gestores
   private GestorUsuario usuarios;
   private GestorTerminal terminales;

   //Paneles
   private PanelPrincipal pnPrincipal;
   private PanelLogin pnLogin;
   private PanelAdmin pnAdmin;
   private PanelPasajero pnPasajero;
   private PanelFormularioPasajero pnFormuPasajero;
   private PanelTerminal pnTerminal;

En el constructor, inicializamos ambos objetos.
Al panel de gestión, le añadiremos dos ActionListener, uno es para el botón "volver" del formulario de Gestión Terminales, que lo que hace es regresar al usuario al Panel de Administrador.
La otra acción es la que corresponde al botón de crear/registrar nueva Terminal.
De momento, los botones de modificar y eliminar, no tendrán ActionListener todavía.

No olvidemos añadir el nuevo panel al "Panel Principal" que gestiona todos los paneles.

En color verde, señalo una línea importante. Es en la que al Panel de Administrador, le damos una acción al botón de "gestionar terminales".

Citar
   public Main() {

      usuarios = new GestorUsuario();
      terminales = new GestorTerminal();
      pnPrincipal = new PanelPrincipal();
      pnLogin = new PanelLogin();
      pnLogin.setAccionBotonLogin(new AccionLogin());
      pnAdmin = new PanelAdmin();
      pnAdmin.setAccionLogout(new AccionLogout());
      pnAdmin.setAccionTerminal(new AccionAdministrarTerminal());
      pnPasajero = new PanelPasajero();
      pnPasajero.setAccionLogout(new AccionLogout());
      pnFormuPasajero = new PanelFormularioPasajero();
      pnFormuPasajero.setAccionRegistrar(new AccionRegistrar());
      pnFormuPasajero.setAccionCancelar(new AccionLogout());
      pnTerminal = new PanelTerminal(terminales.getArrayTerminales());
      pnTerminal.setAccionCrear(new AccionCrearTerminal());
      pnTerminal.setAccionVolver(new AccionVolverAdministracion());


      //Añadimos cada panel al panel principal.
      pnPrincipal.add(pnLogin, "login");
      pnPrincipal.add(pnAdmin, "admin");
      pnPrincipal.add(pnPasajero, "pasajero");
      pnPrincipal.add(pnFormuPasajero, "formuPasajero");
      pnPrincipal.add(pnTerminal, "terminal");


      setContentPane(pnPrincipal);

      setTitle("Gestion de Terminales");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      pack();
      setLocationRelativeTo(null);
      setVisible(true);
   }

Vamos a ver ahora los ActionListener que hay que añadir.
Uno es el que aplicamos al botón "Gestionar Terminales" del Panel de Administrador. Consiste en simplemente pedir que se muestre el nuevo panel de Gestión de Terminales.
Código: [Seleccionar]
private class AccionAdministrarTerminal implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
pnPrincipal.mostrarPanel("terminal");
}
}

Otro es la acción para el botón "volver" del panel de Gestión de Terminales. Lo que hace es volver al Panel de Administrador.

Código: [Seleccionar]
private class AccionVolverAdministracion implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
pnPrincipal.mostrarPanel("admin");
}
}

Por último, la acción para crear un Terminal.
En esta vemos que su funcionalidad varía según el modo actualmente activo (lo sabemos por el atributo boolean) en el panel de Gestión de Terminales.
Si está en "modo gestión", se activa el "modo crear" y seteamos en el formulario un nuevo ID autogenerado por el gestor de terminales para poder crear una Terminal nueva. Lo señalo en verde.

Si ya está activo el "modo crear", lo que hay que hacer es recoger los datos del formulario, crear una Terminal y pasársela al gestor de terminales para que la registre (si cumple los requisitos necesarios).
Si se acepta el registro, se actualiza el JComboBox del panel de Gestión de Terminales y se regresa al "modo gestión". Lo señalo en rojo

Citar
   private class AccionCrearTerminal implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         
         if (pnTerminal.modoGestion) {
            //Si está en "modo gestion", pasamos al "modo crear"
            pnTerminal.setModoCrear();
            pnTerminal.setID(terminales.generaID());
         }

         else {
            /*
             * Si está en "modo crear", comprobaremos si hay datos
             * para crear una Terminal, registrarla y volver al
             * "modo gestion"
             */

            Terminal nueva = pnTerminal.getTerminal();
            if (nueva != null) {
               if (terminales.registrarTerminal(nueva)) {
                  //Si la terminal ha sido aceptada, hay que actualizar el panel Terminal
                  pnTerminal.actualizarPanel(terminales.getArrayTerminales());
                  pnTerminal.setModoGestion();
               }

            }
         }
         
      }
   }

Si ponemos en marcha el programa y entramos como Administrador, ahora podemos acceder al panel de Gestión de Terminales


Al acceder al nuevo panel, como es la primera vez que lo iniciamos y aún no hemos registrado terminales, casi todo el formulario aparece desactivado.

Solo están activos el botón para volver al panel de Administrador, y el de Crear Terminal.
Este será el botón que vamos a pulsar, y lo que ocurre es que se activa el "modo creación".



Vemos que el campo ID ha recibido un identificador al azar. Podemos ponerle un nombre, seleccionar un Lugar y un número de terminal.
También vemos que el botón "crear", ahora pone "registrar".
Si lo pulsamos, la nueva Terminal queda registrada y automáticamente se actualiza el JComboBox.
Si registramos unas cuantas terminales más, veremos que el JCombobox va creciendo y podemos seleccionar cualquier Terminal para ver sus datos.



Si intentamos crear más de dos terminales en un mismo Lugar, no nos lo permite.

Hay un par de fallos. Por ejemplo, si entramos en el "modo creación", la única forma de salir de este modo es registrando una Terminal, es decir, no podemos cancelar el proceso de creación, ni siquiera regresando al panel de Administrador y volviendo de nuevo a Gestionar Terminales

Otro, algo que no había pensado hasta ahora mismo, es que supongo que al crear dos terminales en un mismo Lugar, estas terminales no pueden tener el mismo número. Es decir, si una tiene el número de terminal 1, pues la otra obligatoriamente tendrá que ser 2.
El enunciado creo que no dice nada de esto, pero suena lógico.

En fin, son detalles menores que se pueden corregir más adelante. Lo interesante ahora sería seguir con lo de "Modificar" y "Eliminar" Terminales, para así poder pasar a la Gestión de Unidades.

448
Tenemos que crear un nuevo panel que se dedique a la Gestión de Terminales. Tiene que servirnos para crear Terminales, consultarlas, modificarlas y eliminarlas.
Para no complicarnos con interfaces complejas, podemos hacerlo todo con un único formulario.
Se puede ofrecer un JComboBox con la lista de Terminales creadas, si es que las hay, para que el usuario pueda elegir una u otra.
Cada vez que elige una, se mostrarían su ID y nombre en campos de texto.
El Lugar y el número de Terminal, se mostrarían en otros JComboBox, ya que estos elementos han de ser seleccionados dentro de unos valores determinados.

De este modo podría modificar o eliminar Terminales, con los botones correspondientes.
Un tercer botón permitiría iniciar la creación de una nueva Terminal.
Durante el proceso de creación, no conviene que los otros botones sigan activos, ni tampoco el selector de Terminales (el JComboBox).

Esto me ha llevado a pensar en usar un boolean como atributo de clase, para hacer que el formulario tenga dos modos de funcionamiento diferentes.
Durante el "modo gestión", se puede seleccionar terminales, modificar y eliminar.

Pero cuando se pulsa el botón de Crear Terminal, se activa el "modo creación", que lo que hace es bloquear los otros botones y solo deja funcionando los necesario para introducir los datos de la nueva Terminal y pedir que sea registrada.

Otro atributo que tendrá esta clase, será un objeto Terminal que será una referencia al objeto Terminal que tenemos seleccionado en cada momento.
De este modo, si se quiere hacer modificaciones, tenemos a mano la Terminal a la que hay que aplicarle los cambios.

Este sería el código para crear el panel Gestión de Terminales. Fíjate que en su constructor, la hago llegar el array con la lista actual de Terminales registradas. Esto es necesario para poder inicializar el JComboBox de Terminales.
Código: [Seleccionar]
package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import terminal.*;

@SuppressWarnings("serial")
public class PanelTerminal extends JPanel{

//Terminal seleccionada en el formulario
Terminal seleccion;
//Este panel tendrá dos modalidades de funcionamiento: creación y gestión
boolean modoGestion;
//Mostrará terminales registradas para poder seleccionarlas
private JComboBox<Terminal> jcTerminales;
//Campos del formulario para registrar o modificar terminales
private JTextField jtIdTerminal;
private JTextField jtNombreTerminal;
private JComboBox<Lugar> jcLugar;
private JComboBox<String> jcNumTerminal;
//Botones de gestión
private BotonOpcion btCrear;
private BotonOpcion btModificar;
private BotonOpcion btEliminar;
//Para regresar al menú de administrador
private JButton btVolver;


public PanelTerminal(Terminal[] terminales) {

jtIdTerminal = new JTextField(8);
jtIdTerminal.setEditable(false);
jtNombreTerminal = new JTextField(8);
jcLugar = new JComboBox<Lugar>(Lugar.values());
jcNumTerminal = new JComboBox<String>(new String[] {"1", "2"});
btCrear = new BotonOpcion("Crear<br>Terminal");
btModificar = new BotonOpcion("Modificar<br>Terminal");
btEliminar = new BotonOpcion("Eliminar<br>Terminal");
btVolver = new JButton("Volver Menú Administración");

jcTerminales = new JComboBox<Terminal>();
jcTerminales.addItemListener(new SeleccionTerminal());
actualizarPanel(terminales);
setModoGestion();


setLayout(new BorderLayout());
add(new PanelNorte(), BorderLayout.NORTH);
add(new PanelCentro(), BorderLayout.CENTER);
add(new PanelSur(), BorderLayout.SOUTH);
}

private class PanelNorte extends JPanel {

public PanelNorte() {
JLabel titulo = new JLabel("Gestión de Terminales");
titulo.setFont(new Font("Verdana", Font.ITALIC, 36));
add(titulo);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(20, 20, 0, 20),
BorderFactory.createRaisedSoftBevelBorder()));
}
}

private class PanelCentro extends JPanel {

public PanelCentro() {

JPanel pnSup = new JPanel();
pnSup.add(new JLabel("Seleccione terminal: "));
pnSup.add(jcTerminales);

JPanel pnCen = new JPanel();
pnCen.setLayout(new GridLayout(2,2));
pnCen.add(new PanelConComponente("ID: ", jtIdTerminal));
pnCen.add(new PanelConComponente("Nombre: ", jtNombreTerminal));
pnCen.add(new PanelConComponente("Lugar: ", jcLugar));
pnCen.add(new PanelConComponente("Número: ", jcNumTerminal));
pnCen.setBorder(BorderFactory.createTitledBorder("Datos de la Terminal"));

JPanel pnInf = new JPanel();
pnInf.setLayout(new GridLayout(1,3,10,10));
pnInf.add(btCrear); pnInf.add(btModificar); pnInf.add(btEliminar);
pnInf.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createRaisedSoftBevelBorder(),
BorderFactory.createEmptyBorder(5, 5, 5, 5)));

setLayout(new BorderLayout());
add(pnSup, BorderLayout.NORTH);
add(pnCen, BorderLayout.CENTER);
add(pnInf, BorderLayout.SOUTH);
setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));

}
}

private class PanelConComponente extends JPanel {

public PanelConComponente(String texto, JComponent componente) {
add(new JLabel(texto)); add(componente);
}
}

private class PanelSur extends JPanel {

public PanelSur() {
JPanel pnBoton = new JPanel();
pnBoton.add(btVolver);
add(pnBoton);
}
}


private class BotonOpcion extends JButton {

public BotonOpcion(String texto) {
super("<html><p style=\"text-align:center\">" + texto + "</p></html>");
setFont(new Font("Verdana", Font.BOLD, 14));
setFocusPainted(false);
setBackground(new Color(102, 204, 255));
setForeground(Color.WHITE);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEtchedBorder(),
BorderFactory.createEmptyBorder(10, 10, 10, 10)));
addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {
setForeground(new Color(204, 0, 0));
}
@Override
public void mouseExited(MouseEvent e) {
setForeground(Color.WHITE);
}
});
}
}

//Métodos
/**
* Activa el "modo gestión".<br>
* Este modo es el normal, todos los botones están activos así como
* el ComboBox para seleccionar terminal, si es que existen terminales.<br>
* El botón "Crear" permanece activo y si se le pulsa, se activará el
* "modo creación".
*/
public void setModoGestion() {
modoGestion = true;
if (jcTerminales.getItemCount() > 0) {
jcTerminales.setEnabled(true);
btModificar.setEnabled(true);
btEliminar.setEnabled(true);
jtNombreTerminal.setEditable(true);
jcLugar.setEnabled(true);
jcNumTerminal.setEnabled(true);
}
else { //No hay Terminales para seleccionar en el JComboBox, no tiene sentido activar controles
jcTerminales.setEnabled(false);
btModificar.setEnabled(false);
btEliminar.setEnabled(false);
jtNombreTerminal.setEditable(false);
jcLugar.setEnabled(false);
jcNumTerminal.setEnabled(false);
}
btCrear.setText("<html><p style=\"text-align:center\">Crear<br>Terminal</p></html>");
}

/**
* Activa el "modo creacion".<br>
* Este modo se activa cuando se va a crear una nueva Terminal,
* en cuyo caso se desactivan los botones de "modificar" y "eliminar"
* terminales, así como el ComboBox para escoger terminales.<br>
* El botón "Crear" cambia su texto a "Registrar" y si se le pulsa,
* intentará registrar una nueva Terminal con los datos introducidos
* y si tiene éxito, actualizará el ComboBox de terminales y volverá de nuevo
* al "modo gestión".
*/
public void setModoCrear() {
modoGestion = false;
jtNombreTerminal.setEditable(true);
jcLugar.setEnabled(true);
jcNumTerminal.setEnabled(true);
jcTerminales.setEnabled(false);
btModificar.setEnabled(false);
btEliminar.setEnabled(false);
btCrear.setText("<html><p style=\"text-align:center\">Registrar<br>Terminal</p></html>");
}

/**
* Setea un ID en el campo correspondiente.<br>
* @param id String con el ID a setear.
*/
public void setID(String id) {
jtIdTerminal.setText(id);
}

/**
* Construye una Terminal con los datos proporcionados y la retorna<br>
* En la clase Main se evaluará si esta Terminal cumple los requisitos
* para poder ser registrada.
* @return Objeto Terminal según datos formulario.
*/
public Terminal getTerminal() {
String id = jtIdTerminal.getText();
String nombre = jtNombreTerminal.getText();
Lugar lugar = (Lugar) jcLugar.getSelectedItem();
String numero = (String) jcNumTerminal.getSelectedItem();

if (nombre.isBlank()) {
JOptionPane.showMessageDialog(null, "Ha de dar un nombre a la Terminal",
"Registrar Terminal", JOptionPane.WARNING_MESSAGE);
jtNombreTerminal.requestFocusInWindow();
return null;
}
else {
return new Terminal(id, nombre, lugar, numero);
}
}

public void actualizarPanel(Terminal[] terminales) {
//Renovamos combobox de terminales
jcTerminales.removeAllItems();
if (terminales.length > 0) {
for (Terminal ter: terminales)
jcTerminales.addItem(ter);
//Seleccionamos el último añadido a la lista
jcTerminales.setSelectedIndex(terminales.length - 1);
seleccion = (Terminal) jcTerminales.getSelectedItem();
mostrarSeleccionado();
}
}

private void mostrarSeleccionado() {
jtIdTerminal.setText(seleccion.getIdTerminal());
jtNombreTerminal.setText(seleccion.getNomTerminal());
jcLugar.setSelectedItem(seleccion.getLugar());
jcNumTerminal.setSelectedItem(seleccion.getNumTerminal());
}

public void setAccionVolver(ActionListener accion) {
btVolver.addActionListener(accion);
}

public void setAccionCrear(ActionListener accion) {
btCrear.addActionListener(accion);
}

//ActionListener
private class SeleccionTerminal implements ItemListener {
@Override
public void itemStateChanged(ItemEvent e) {
if (jcTerminales.getItemCount() > 0) {
seleccion = (Terminal) jcTerminales.getSelectedItem();
mostrarSeleccionado();
}
}
}
}

El siguiente paso es agregar todas esas novedades a la clase Main, tanto el panel de Gestión de Terminales ("vista"), como el gestor de terminales("modelo").
La clase Main quedaría así:
Código: [Seleccionar]
package gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import terminal.*;
import usuario.*;

@SuppressWarnings("serial")
public class Main extends JFrame{

//Usuario que ha logueado, puede ser Admin o Pasajero
private Usuario logueado;

//Gestores
private GestorUsuario usuarios;
private GestorTerminal terminales;

//Paneles
private PanelPrincipal pnPrincipal;
private PanelLogin pnLogin;
private PanelAdmin pnAdmin;
private PanelPasajero pnPasajero;
private PanelFormularioPasajero pnFormuPasajero;
private PanelTerminal pnTerminal;

public Main() {

usuarios = new GestorUsuario();
terminales = new GestorTerminal();
pnPrincipal = new PanelPrincipal();
pnLogin = new PanelLogin();
pnLogin.setAccionBotonLogin(new AccionLogin());
pnAdmin = new PanelAdmin();
pnAdmin.setAccionLogout(new AccionLogout());
pnAdmin.setAccionTerminal(new AccionAdministrarTerminal());
pnPasajero = new PanelPasajero();
pnPasajero.setAccionLogout(new AccionLogout());
pnFormuPasajero = new PanelFormularioPasajero();
pnFormuPasajero.setAccionRegistrar(new AccionRegistrar());
pnFormuPasajero.setAccionCancelar(new AccionLogout());
pnTerminal = new PanelTerminal(terminales.getArrayTerminales());
pnTerminal.setAccionCrear(new AccionCrearTerminal());
pnTerminal.setAccionVolver(new AccionVolverAdministracion());

//Añadimos cada panel al panel principal.
pnPrincipal.add(pnLogin, "login");
pnPrincipal.add(pnAdmin, "admin");
pnPrincipal.add(pnPasajero, "pasajero");
pnPrincipal.add(pnFormuPasajero, "formuPasajero");
pnPrincipal.add(pnTerminal, "terminal");


setContentPane(pnPrincipal);

setTitle("Gestion de Terminales");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}

//Acciones
/**
* Recoge los datos del formulario de login y permite acceder
* a un usuario registrado, o bien crear un nuevo registro.<br>
* Cuando el Usuario ha accedido al sistema, se mostrará un panel
* de opciones según si es Administrador o Pasajero.
*/
private class AccionLogin implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//Recuperamos datos del formulario login
String[] datosLogin = pnLogin.getDatos();

if (datosLogin !=  null) {
//Preguntamos si es nuevo registro
if (pnLogin.esNuevoRegistro()) {
pnFormuPasajero.setCedula(datosLogin[0]);
pnFormuPasajero.setPassword(datosLogin[1]);
pnPrincipal.mostrarPanel("formuPasajero");
pnLogin.resetFormulario();
}
else {//Es un login normal
//Intentamos login con los datos
logueado = usuarios.login(datosLogin[0], datosLogin[1]);
//Comprobamos si ha tenido exito el login y que tipo usuario se trata
if (logueado == null)
JOptionPane.showMessageDialog(null,
"Los datos introducidos no coinciden con ningun Usuario",
"Login Usuario", JOptionPane.WARNING_MESSAGE);
else {
//Login exitoso. Se mostrará un nuevo panel, según tipo usuario
if (logueado instanceof Administrador)
pnPrincipal.mostrarPanel("admin");
else
pnPrincipal.mostrarPanel("pasajero");
//El formulario de login se resetea
pnLogin.resetFormulario();
}
}
}
}
}

private class AccionLogout implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
logueado = null;
pnPrincipal.mostrarPanel("login");
}
}


/**
* Recoge los datos del formulario para registrar un nuevo Pasajero.<br>
* Tras comprobaciones para validar esos datos pedirá registrarlo en el
* Gestor de Usuarios, logueará a este Usuario para que inicie sesión
* y mostrará su menú correspondiente.
*/
private class AccionRegistrar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//Recuperamos datos
Object[] datosPasajero = pnFormuPasajero.getDatos();
String cedula = (String) datosPasajero[0];
String password = (String) datosPasajero[1];
String nombre = (String) datosPasajero[2];
String eMail = (String) datosPasajero[3];
String genero = (String) datosPasajero[4];
Date fechaNac = (Date) datosPasajero[5];

//Validamos datos
if (!pnFormuPasajero.validarEmail())
JOptionPane.showMessageDialog(null, "Dirección e-mail no es válida",
"Registrar Usuario", JOptionPane.WARNING_MESSAGE);
else if (cedula.isBlank() || password.isBlank() || nombre.isBlank())
JOptionPane.showMessageDialog(null, "Debe rellenar todos los campos",
"Registrar Usuario", JOptionPane.WARNING_MESSAGE);
else {
int respuesta = JOptionPane.showConfirmDialog(null, "¿Desea registrarse con estos datos?",
"Registrar Usuario", JOptionPane.YES_NO_OPTION);
if (respuesta == JOptionPane.YES_OPTION) {
//Creamos Pasajero
Pasajero pas = new Pasajero(cedula, password, nombre, fechaNac, genero, eMail);
//Registramos, si es posible..
if (usuarios.registrarUsuario(pas)) {
JOptionPane.showMessageDialog(null, "Usuario Registrado",
"Registrar Usuario", JOptionPane.INFORMATION_MESSAGE);
pnFormuPasajero.resetFormulario();
logueado = pas;
pnPrincipal.mostrarPanel("pasajero");
}
}
}

}
}

private class AccionAdministrarTerminal implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
pnPrincipal.mostrarPanel("terminal");
}
}

private class AccionCrearTerminal implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {

if (pnTerminal.modoGestion) {
//Si está en "modo gestion", pasamos al "modo crear"
pnTerminal.setModoCrear();
pnTerminal.setID(terminales.generaID());
}
else {
/*
* Si está en "modo crear", comprobaremos si hay datos
* para crear una Terminal, registrarla y volver al
* "modo gestion"
*/
Terminal nueva = pnTerminal.getTerminal();
if (nueva != null) {
if (terminales.registrarTerminal(nueva)) {
//Si la terminal ha sido aceptada, hay que actualizar el panel Terminal
pnTerminal.actualizarPanel(terminales.getArrayTerminales());
pnTerminal.setModoGestion();
}
}
}

}
}

private class AccionVolverAdministracion implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
pnPrincipal.mostrarPanel("admin");
}
}



public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Main();
}
});
}
}

En el siguiente post (en este no me cabe, demasiadas líneas de código) vemos en detalle, los cambios que hacemos en la clase Main.

449
Aunque se cumpla el plazo, intentaré seguir avanzando. Si sirve para aclararte conceptos de cara a próximas tareas, bienvenido sea.

Lo siguiente sería comenzar con la gestión de Terminales.
El enunciado indica que una Terminal tiene un ID autogenerado por el programa, un nombre, un lugar y un número de terminal (entre 1 y 2)
Del lugar, nos dan una lista determinada y solo podemos escoger un lugar de esa lista.
Además nos dice que esa lista tiene estar en una estructura de datos dentro del programa, no especifica cuál.

A mi me ha parecido adecuado crear un Enum (enumeración). Un Enum es un conjunto de valores determinados dentro de los cuáles podemos escoger.
En Java, un Enum es como una Clase, de la cuál no se pueden crear objetos, excepto los propios valores del Enum.
Como vamos a querer que esos valores se guarden en un archivo de texto, a cada uno de estos objetos valores/objetos podemos darle un atributo de tipo String. Este String será lo que se guardará en el archivo de texto cuando guardemos Terminales.
Y mediante este String, al leer los datos del archivo y tener que recrear a partir de ellos las Terminales, gracias a un método static que le incluyo al Enum, podremos relacionar el String con su valor Lugar correspondiente.

Código: [Seleccionar]
package terminal;

public enum Lugar {

SAN_JOSE("San José"), ALAJUELA("Alajuela"), HEREDIA("Heredia"),
CARTAGO("Cartago"), SAN_CARLOS("San Carlos"), PUNTARENAS("Puntarenas"),
LIMON("Limón");

private String nombre;

private Lugar(String nombre) {
this.nombre = nombre;
}

@Override
public String toString() {
return nombre;
}

/**
* Método estatico para, a partir de un String,
* identificar cuál es el objeto Lugar equivalente.<br>
* Esto será necesario cuando recuperemos datos del archivo txt,
* ya que el nombre del lugar se habrá guardado como un String, pero
* el programa va a trabajar con objetos Lugar.
* @param nomLugar String con el nombre del lugar, provendrá del archivo txt.
* @return Objeto Lugar equivalente.
*/
public static Lugar getLugar(String nomLugar) {
switch(nomLugar) {
case "San José":
return SAN_JOSE;
case "Alajuela":
return ALAJUELA;
case "Heredia":
return HEREDIA;
case "Cartago":
return CARTAGO;
case "San Carlos":
return SAN_CARLOS;
case "Puntarenas":
return PUNTARENAS;
case "Limón":
return LIMON;
default: //Será prácticamente imposible que se reciba un String distinto de los predefinidos.
return null; //Pero aún así contemplamos esa posibilidad.
}
}
}

Ahora que ya hemos definido la clase/enum Lugar, podemos crear la clase Terminal
Código: [Seleccionar]
package terminal;

/**
 * Clase para modelar una Terminal.<br>
 * El atributo lugar es del tipo "enumerado" Lugar.<br>
 * Se sobreescribe el método toString() para usarlo posteriormente
 * para mostrar los objetos en un JComboBox.<br>Un método similar
 * llamado toTXT() será el que usaremos para
 * cuando se guarden los datos en un archivo de texto.
 */
public class Terminal {

private String idTerminal;
private String nomTerminal;
private Lugar lugar;
private String numTerminal;

public Terminal(String idTerminal, String nomTerminal, Lugar lugar, String numTerminal) {
this.idTerminal = idTerminal;
this.nomTerminal = nomTerminal;
this.lugar = lugar;
this.numTerminal = numTerminal;
}

public String getIdTerminal() {
return idTerminal;
}

public void setIdTerminal(String idTerminal) {
this.idTerminal = idTerminal;
}

public String getNomTerminal() {
return nomTerminal;
}

public void setNomTerminal(String nomTerminal) {
this.nomTerminal = nomTerminal;
}

public Lugar getLugar() {
return lugar;
}

public void setLugar(Lugar lugar) {
this.lugar = lugar;
}

public String getNumTerminal() {
return numTerminal;
}

public void setNumTerminal(String numTerminal) {
this.numTerminal = numTerminal;
}

/**
* Este será el String que usaremos para escribir datos en archivo texto
*/
public String toTXT() {
return String.format("%s -- %s -- %s -- %s", idTerminal, nomTerminal, lugar, numTerminal);
}

/**
* Este String se usará principalmente para mostrar las Terminales en un ComboBox
* que permitirá seleccionarlas en el panel de Gestión de Terminales.
*/
@Override
public String toString() {
return String.format("%s -- %s", idTerminal, nomTerminal);
}

/**
* Dos terminales son equivalente si tienen el mismo ID.
*/
@Override
public boolean equals(Object objeto) {
if (objeto instanceof Terminal) {
Terminal otraTerminal = (Terminal) objeto;
return idTerminal.equals(otraTerminal.idTerminal);
}
else
return false;
}

}

Y tal como hicimos con los Usuarios, vamos a querer tener una clase que se dedique a la Gestión de Terminales, que tenga un ArrayList donde agruparlos, se encargue de leer y guardar en archivo de texto, etc..
Además tendrá un método para generar al azar un ID que sea único.

Fijémonos que en el método para agregar una nueva Terminal, se hacen dos comprobaciones.
Primero, asegurarse de que no hay otra con el mismo ID, algo que por otra parte debería ser imposible ya que cada nueva Terminal recibe un ID que ya se ha comprobado que es único.
Segundo, comprueba si en el Lugar asignado a esta nueva Terminal hay ya otras dos Terminales emplazadas.
Porque el enunciado dice que no puede haber más de dos Terminales en el mismo sitio, así que si se intenta registrar una tercera, será rechazada.


Código: [Seleccionar]
package terminal;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JOptionPane;

/**
 * Esta clase gestionará un ArrayList con las Terminales disponibles.<br>
 * Se encargará de registrar y modificar terminales, así como de
 * guardar y leer el archivo txt con la información de las Terminales.
 */
public class GestorTerminal {

private ArrayList<Terminal> terminales;

public GestorTerminal() {
terminales = new ArrayList<Terminal>();
cargarDatos();
}

private void cargarDatos() {

try {
BufferedReader br = new BufferedReader(new FileReader("terminales.txt"));
String linea = br.readLine();

while(linea != null) {

//Separamos datos contenidos en la linea
String[] datos = linea.split(" -- ");
//Creamos una Terminal con los datos de esta línea
terminales.add(new Terminal(datos[0], datos[1], Lugar.getLugar(datos[2]), datos[3]));
//siguiente linea
linea = br.readLine();
}

br.close();

} catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(null, "No se encuentra archivo: terminales.txt\n"
+ "Se intentará generar uno nuevo cuando se registre una Terminal nueva",
"Cargar Datos Terminales", JOptionPane.WARNING_MESSAGE);
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "Error intentando leer: terminales.txt",
"Cargar Datos Terminales", JOptionPane.WARNING_MESSAGE);
} catch (Exception error) {
JOptionPane.showMessageDialog(null, "Error recuperando datos de: terminales.txt\n"
+ "Error:\n" + error.getLocalizedMessage(),
"Cargar Datos Terminales", JOptionPane.WARNING_MESSAGE);
}
}

private void guardarDatos() {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter("terminales.txt", false));
//Por cada Terminal, creamos una línea de texto en el archivo
for (Terminal ter: terminales) {
bw.write(ter.toTXT());
bw.newLine();
}
bw.close();
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Error intentando guardar: terminales.txt",
"Guardar Datos Terminales", JOptionPane.WARNING_MESSAGE);
}
}

public boolean registrarTerminal(Terminal ter) {
/*
* Primero comprobamos si ya existe una Terminal con el mismo identificador.
* Esta posibilidad es muy remota ya que los identificadores son autogenerados
* por el sistema, pero por si a caso. 
*/
if (terminales.contains(ter)) {
JOptionPane.showMessageDialog(null, "Ya existe una Terminal registrada con este ID",
"Registrar Terminal", JOptionPane.WARNING_MESSAGE);
return false;
}
else if(cuentaTerminalesEnLugar(ter.getLugar()) >= 2 ) {
JOptionPane.showMessageDialog(null, "Ya existen dos Terminales en: " + ter.getLugar()
+ "\nNo pueden registrarse más.", "Registrar Terminal", JOptionPane.WARNING_MESSAGE);
return false;
}
else {
terminales.add(ter);
JOptionPane.showMessageDialog(null, "Nueva Terminal registrada",
"Registrar Terminal", JOptionPane.INFORMATION_MESSAGE);
guardarDatos();
return true;
}
}

/**
* Hace un recuento de cuántas Terminales existen en un
* Lugar concreto. Esto es necesario ya que hay impuesto
* un límite de máximo 2 Terminales en un mismo Lugar.<br>
* Así que antes de aceptar registrar una Terminal, hay que
* comprobar este recuento.
* @param lugar Lugar que se quiere consultar.
* @return Cantidad de Terminales existente en el Lugar especificado
*/
private int cuentaTerminalesEnLugar(Lugar lugar) {
int cont = 0;
for (Terminal ter: terminales)
if (ter.getLugar().equals(lugar))
cont++;

return cont;
}

/**
* Genera automáticamente un identificador para poder crear
* y registrar nuevas terminales.<br>
* EL identificador será un String con el formato "TERxxx"
* donde las x serán los digitos correspondientes a un número
* al azar entre 000 y 999.
* @return String con un ID único autogenerado.
*/
public String generaID() {

Random azar = new Random();
String id = "";
boolean esUnico = false;

while (!esUnico) {
//Generamos ID
id = String.format("TER%03d", azar.nextInt(1000));
esUnico = true;
//Comprobamos si es realmente único
for (Terminal ter: terminales)
if (ter.getIdTerminal().equals(id))
esUnico = false; //Se encontró una Terminal con ese ID, el bucle volverá a intentarlo
}

return id;
}

/**
* Crea un array primitivo con los objetos Terminal y los retorna.<br>
* Será muy útil para configurar un JComboBox en el panel de Gestión de Terminales.
* @return Array con los objetos Terminal.
*/
public Terminal[] getArrayTerminales() {
return terminales.toArray(new Terminal[terminales.size()]);
}

}

Esta clase no es definitiva y más adelante habrá que añadirle más cosas. Por ejemplo, un método para eliminar Terminales.
Pero bueno, ahora ya tenemos la parte del "modelo" básica para poder crear y guardar Terminales.

Para probarlo, tenemos que centrarnos ahora en la parte de la "vista", en la interfaz gráfica.

450
Mmmhh.. la clase Archivo parece no estar mal del todo. Lo de contar palabras me temo que fallará cuando una palabra ocupe una línea completa, porque no tendrá ningún espacio en blanco ni delante ni detrás, así que ese código no la contará como palabra.

Pero lo que veo realmente raro es esto en la clase principal

Código: [Seleccionar]
for(int i = 1; i <= 5; i++) {
listFicheros.add(new File("C:\\Users\\user\\Desktop\\ArchivoJava.txt"));
}

Tú trabajas con un archivo, pero ese mismo archivo lo añades 5 veces.
Y luego haces los cálculos, con esas 5 copias del mismo archivo.

Por eso, aunque tengas solo 2 líneas en tu archivo, te dice que tienes 10 (2 x 5)
Aunque solo tienes 16 caracteres, te dice que tienes 80(16 x 5)

Y aunque tienes 3 palabras, solo te cuenta 2 (la primera que ocupa toda la línea la ignora) pero te dice que son 10 (2x5)

Resumiendo, no necesitas ese LinkedList para nada, a no ser que quieras que el programa te sirva para trabajar con varios archivos..., pero entonces procura que sean distintos, y no 5 copias del mismo.

Y tienes que revisar el método de contar palabras, para que te incluya también palabras que ocupen una línea completa.

451
Esta es la clase Main con todos los cambios necesarios para poder usar los paneles que hemos escrito en el mensaje anterior:
Código: [Seleccionar]
package gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import usuario.*;

@SuppressWarnings("serial")
public class Main extends JFrame{

///Uusario que ha logueado, puede ser Admin o Pasajero
private Usuario logueado;

//Gestores
private GestorUsuario usuarios;

//Paneles
private PanelPrincipal pnPrincipal;
private PanelLogin pnLogin;
private PanelAdmin pnAdmin;
private PanelPasajero pnPasajero;
private PanelFormularioPasajero pnFormuPasajero;

public Main() {

usuarios = new GestorUsuario();
pnPrincipal = new PanelPrincipal();
pnLogin = new PanelLogin();
pnLogin.setAccionBotonLogin(new AccionLogin());
pnAdmin = new PanelAdmin();
pnAdmin.setAccionLogout(new AccionLogout());
pnPasajero = new PanelPasajero();
pnPasajero.setAccionLogout(new AccionLogout());
pnFormuPasajero = new PanelFormularioPasajero();
pnFormuPasajero.setAccionRegistrar(new AccionRegistrar());
pnFormuPasajero.setAccionCancelar(new AccionLogout());

//Añadimos cada panel al panel principal.
pnPrincipal.add(pnLogin, "login");
pnPrincipal.add(pnAdmin, "admin");
pnPrincipal.add(pnPasajero, "pasajero");
pnPrincipal.add(pnFormuPasajero, "formuPasajero");


setContentPane(pnPrincipal);

setTitle("Gestion de Terminales");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}

//Acciones
/**
* Recoge los datos del formulario de login y permite acceder
* a un usuario registrado, o bien crear un nuevo registro.<br>
* Cuando el Usuario ha accedido al sistema, se mostrará un panel
* de opciones según si es Administrador o Pasajero.
*/
private class AccionLogin implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//Recuperamos datos del formulario login
String[] datosLogin = pnLogin.getDatos();

if (datosLogin !=  null) {
//Preguntamos si es nuevo registro
if (pnLogin.esNuevoRegistro()) {
pnFormuPasajero.setCedula(datosLogin[0]);
pnFormuPasajero.setPassword(datosLogin[1]);
pnPrincipal.mostrarPanel("formuPasajero");
pnLogin.resetFormulario();
}
else {//Es un login normal
//Intentamos login con los datos
logueado = usuarios.login(datosLogin[0], datosLogin[1]);
//Comprobamos si ha tenido exito el login y que tipo usuario se trata
if (logueado == null)
JOptionPane.showMessageDialog(null,
"Los datos introducidos no coinciden con ningun Usuario",
"Login Usuario", JOptionPane.WARNING_MESSAGE);
else {
//Login exitoso. Se mostrará un nuevo panel, según tipo usuario
if (logueado instanceof Administrador)
pnPrincipal.mostrarPanel("admin");
else
pnPrincipal.mostrarPanel("pasajero");
//El formulario de login se resetea
pnLogin.resetFormulario();
}
}
}
}
}

private class AccionLogout implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
logueado = null;
pnPrincipal.mostrarPanel("login");
}
}


/**
* Recoge los datos del formulario para registrar un nuevo Pasajero.<br>
* Tras comprobaciones para validar esos datos pedirá registrarlo en el
* Gestor de Usuarios, logueará a este Usuario para que inicie sesión
* y mostrará su menú correspondiente.
*/
private class AccionRegistrar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//Recuperamos datos
Object[] datosPasajero = pnFormuPasajero.getDatos();
String cedula = (String) datosPasajero[0];
String password = (String) datosPasajero[1];
String nombre = (String) datosPasajero[2];
String eMail = (String) datosPasajero[3];
String genero = (String) datosPasajero[4];
Date fechaNac = (Date) datosPasajero[5];

//Validamos datos
if (!pnFormuPasajero.validarEmail())
JOptionPane.showMessageDialog(null, "Dirección e-mail no es válida",
"Registrar Usuario", JOptionPane.WARNING_MESSAGE);
else if (cedula.isBlank() || password.isBlank() || nombre.isBlank())
JOptionPane.showMessageDialog(null, "Debe rellenar todos los campos",
"Registrar Usuario", JOptionPane.WARNING_MESSAGE);
else {
int respuesta = JOptionPane.showConfirmDialog(null, "¿Desea registrarse con estos datos?",
"Registrar Usuario", JOptionPane.YES_NO_OPTION);
if (respuesta == JOptionPane.YES_OPTION) {
//Creamos Pasajero
Pasajero pas = new Pasajero(cedula, password, nombre, fechaNac, genero, eMail);
//Registramos, si es posible..
if (usuarios.registrarUsuario(pas)) {
JOptionPane.showMessageDialog(null, "Usuario Registrado",
"Registrar Usuario", JOptionPane.INFORMATION_MESSAGE);
pnFormuPasajero.resetFormulario();
logueado = pas;
pnPrincipal.mostrarPanel("pasajero");
}
}
}

}
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Main();
}
});
}
}

¿Qué es lo que ha cambiado?

Declaramos los nuevos paneles como atributos de clase:
Citar
public class Main extends JFrame{

   //Usuario que ha logueado, puede ser Admin o Pasajero
   private Usuario logueado;

   //Gestores
   private GestorUsuario usuarios;

   //Paneles
   private PanelPrincipal pnPrincipal;
   private PanelLogin pnLogin;
   private PanelAdmin pnAdmin;
   private PanelPasajero pnPasajero;
   private PanelFormularioPasajero pnFormuPasajero;

En el constructor, inicializamos esos paneles, le damos funcionalidad a sus botones de acción y los añadimos al "Panel Principal", el que tiene el CardLayout que gestiona el resto de paneles:

Citar
   public Main() {

      usuarios = new GestorUsuario();
      pnPrincipal = new PanelPrincipal();
      pnLogin = new PanelLogin();
      pnLogin.setAccionBotonLogin(new AccionLogin());
      pnAdmin = new PanelAdmin();
      pnAdmin.setAccionLogout(new AccionLogout());
      pnPasajero = new PanelPasajero();
      pnPasajero.setAccionLogout(new AccionLogout());
      pnFormuPasajero = new PanelFormularioPasajero();
      pnFormuPasajero.setAccionRegistrar(new AccionRegistrar());
      pnFormuPasajero.setAccionCancelar(new AccionLogout());


      //Añadimos cada panel al panel principal.
      pnPrincipal.add(pnLogin, "login");
      pnPrincipal.add(pnAdmin, "admin");
      pnPrincipal.add(pnPasajero, "pasajero");
      pnPrincipal.add(pnFormuPasajero, "formuPasajero");



      setContentPane(pnPrincipal);

      setTitle("Gestion de Terminales");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      pack();
      setLocationRelativeTo(null);
      setVisible(true);
   }

En la clase ActionListener que corresponde al botón del formulario de Login, añadimos el código correspondiente a lo que ha de hacer cuando el JCheckBox de "Nuevo Registro" está seleccionado. Es decir, ha de pasar los valores de cédula y password que el usuario acaba de introducir al formulario de registrar nuevo usuario, y mostrarlo en pantalla.

Citar
   private class AccionLogin implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         //Recuperamos datos del formulario login
         String[] datosLogin = pnLogin.getDatos();

         if (datosLogin !=  null) {
            //Preguntamos si es nuevo registro
            if (pnLogin.esNuevoRegistro()) {
               pnFormuPasajero.setCedula(datosLogin[0]);
               pnFormuPasajero.setPassword(datosLogin[1]);
               pnPrincipal.mostrarPanel("formuPasajero");
               pnLogin.resetFormulario();
            }

            else {//Es un login normal
               //Intentamos login con los datos
               logueado = usuarios.login(datosLogin[0], datosLogin[1]);
               //Comprobamos si ha tenido exito el login y que tipo usuario se trata
               if (logueado == null)
                  JOptionPane.showMessageDialog(null,
                        "Los datos introducidos no coinciden con ningun Usuario",
                        "Login Usuario", JOptionPane.WARNING_MESSAGE);
               else {
                  //Login exitoso. Se mostrará un nuevo panel, según tipo usuario
                  if (logueado instanceof Administrador)
                     pnPrincipal.mostrarPanel("admin");
                  else
                     pnPrincipal.mostrarPanel("pasajero");
                  //El formulario de login se resetea
                  pnLogin.resetFormulario();
               }
            }
         }
      }
   }

Por último, se escribe una nueva clase ActionListener, la que se aplicará al botón de registrar al nuevo usuario.
Este código lo que hará será recuperar todos los datos introducidos en el formulario (que nos llega en el array de Object) y comprobará que los datos son válidos.

Si son válidos, se creará un nuevo objeto Pasajero con ellos y se pedirá al "Gestor de Usuarios" que lo registre en el ArrayList.
Si lo acepta (no lo aceptará si ya hay alguien con la misma cédula), entonces este usuario quedará logueado y se mostrará el "Menú de Pasajero"
Citar
   private class AccionRegistrar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         //Recuperamos datos
         Object[] datosPasajero = pnFormuPasajero.getDatos();
         String cedula = (String) datosPasajero[0];
         String password = (String) datosPasajero[1];
         String nombre = (String) datosPasajero[2];
         String eMail = (String) datosPasajero[3];
         String genero = (String) datosPasajero[4];
         Date fechaNac = (Date) datosPasajero[5];

         //Validamos datos
         if (!pnFormuPasajero.validarEmail())
            JOptionPane.showMessageDialog(null, "Dirección e-mail no es válida",
                  "Registrar Usuario", JOptionPane.WARNING_MESSAGE);
         else if (cedula.isBlank() || password.isBlank() || nombre.isBlank())
            JOptionPane.showMessageDialog(null, "Debe rellenar todos los campos",
                  "Registrar Usuario", JOptionPane.WARNING_MESSAGE);
         else {
            int respuesta = JOptionPane.showConfirmDialog(null, "¿Desea registrarse con estos datos?",
                  "Registrar Usuario", JOptionPane.YES_NO_OPTION);
            if (respuesta == JOptionPane.YES_OPTION) {
               //Creamos Pasajero
               Pasajero pas = new Pasajero(cedula, password, nombre, fechaNac, genero, eMail);
               //Registramos, si es posible..
               if (usuarios.registrarUsuario(pas)) {
                  JOptionPane.showMessageDialog(null, "Usuario Registrado",
                        "Registrar Usuario", JOptionPane.INFORMATION_MESSAGE);
                  pnFormuPasajero.resetFormulario();
                  logueado = pas;
                  pnPrincipal.mostrarPanel("pasajero");
               }
            }
         }

      }
   }

Estos son los cambios hechos en la clase Main, pero queda otro cambio pendiente.

En la clase GestionUsuarios, se requiere que escribamos el código del método para registrar nuevos usuarios.
Este método es muy simple: Recibe el usuario que se ha creado en el Main según los datos del formulario de registro.
Comprueba si ya existe un Usuario igual (alguien con misma cédula).
Si existe alguien igual, informa en pantalla y retorna false para informar de que ha rechazado el registro.
Si no, entonces lo registra en el ArrayList, guarda en el archivo de texto y retorna true para anunciar que el registro ha sido aceptado.

Código: [Seleccionar]
public boolean registrarUsuario(Usuario usuario) {
//Primero comprobamos que no exista ya un usuario con misma cédula
if (usuarios.contains(usuario)) {
JOptionPane.showMessageDialog(null, "Ya existe un Usuario registrado con esta Cédula",
"Registrar Usuario", JOptionPane.WARNING_MESSAGE);
return false;
}
else {
usuarios.add(usuario);
guardarDatos();
return true;
}
}


Y con todo esto, ya podemos registrar nuevos Usuarios Pasajeros.

Lo siguiente sería comenzar a dar funciones a algúna opción del panel de Administrador.


452
Lamento que andes corto de tiempo. Voy a intentar avanzar y explicar lo que pueda, pero por desgracia mi tiempo libre es muy escaso.

Lo siguiente que quería hacer era poder registrar nuevos Usuarios, que según el enunciado serán Pasajeros necesariamente. Parece ser que no hay opción de registrar administradores, para añadir más admin a parte del que puse en el código, sería escribiendo sus datos directamente en el txt.

Bueno, la forma de hacer un registro es desde la pantalla de login, se introduce cédula y password, y se marca el checkbox para indicar que queremos hacer nuevo registro:


Al pulsar el botón, ha de aparecer un formulario mostrando la cédula y password introducidos, además de otros campos como edad, email, radiobutton para el genero, un selector de fecha de nacimiento(JDateChooser) y un campo edad (no editable) donde la edad se autocalcula según la fecha seleccionada.

Así que toca escribir una nueva clase JPanel para modelar este formulario.
Este es el código que he escrito:
Código: [Seleccionar]
package gui;

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JRadioButton;
import javax.swing.JTextField;

import com.toedter.calendar.JDateChooser;

@SuppressWarnings("serial")
public class PanelFormularioPasajero extends JPanel {

private JTextField jtCedula;
private JPasswordField jtPassword;
private JTextField jtNombre;
private JTextField jtEdad;
private JTextField jtEmail;
private JRadioButton rbHombre;
private JRadioButton rbMujer;
private JDateChooser selecFecha;
private JButton btRegistrar;
private JButton btCancelar;

public PanelFormularioPasajero() {

jtCedula = new JTextField(8);
jtPassword = new JPasswordField(8);
jtNombre = new JTextField(8);
jtEdad = new JTextField(4);
jtEdad.setEditable(false);
jtEmail = new JTextField(8);
rbHombre = new JRadioButton("Hombre");
rbHombre.setSelected(true);
rbMujer = new JRadioButton("Mujer");
ButtonGroup gb = new ButtonGroup();
gb.add(rbHombre); gb.add(rbMujer);
selecFecha = new JDateChooser("dd/MM/yy", "##/##/##", '-');
selecFecha.setDate(new Date()); //Comienza con fecha actual
selecFecha.setMaxSelectableDate(new Date()); //Y Además no se permite fechas posteriores a hoy
btRegistrar = new JButton("Registrar");
btCancelar = new JButton("Cancelar");
btCancelar.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
resetFormulario();
}
});

setLayout(new BorderLayout());
add(new PanelNorte(), BorderLayout.NORTH);
add(new PanelCentro(), BorderLayout.CENTER);
add(new PanelSur(), BorderLayout.SOUTH);

}

private class Panel1 extends JPanel {

public Panel1() {

JPanel pnCedula = new JPanel();
pnCedula.add(new JLabel("Cédula:"));
pnCedula.add(jtCedula);

JPanel pnNombre = new JPanel();
pnNombre.add(new JLabel("Nombre:"));
pnNombre.add(jtNombre);

JPanel pnPassword = new JPanel();
pnPassword.add(new JLabel("Contraseña:"));
pnPassword.add(jtPassword);

setLayout(new GridLayout(1,3));
add(pnCedula); add(pnNombre); add(pnPassword);
}
}

private class Panel2 extends JPanel {

public Panel2() {

JPanel pnEmail = new JPanel();
pnEmail.add(new JLabel("E-Mail:"));
pnEmail.add(jtEmail);

JPanel pnEdad = new JPanel();
pnEdad.add(new JLabel("Edad:"));
pnEdad.add(jtEdad);

JPanel pnGenero = new JPanel();
pnGenero.add(rbHombre);
pnGenero.add(rbMujer);

setLayout(new GridLayout(1,3));
add(pnEmail); add(pnEdad); add(pnGenero);
}
}

private class Panel3 extends JPanel {

public Panel3() {

add(new JLabel("Fecha Nacimiento:"));
add(selecFecha);
}
}

private class PanelNorte extends JPanel {

public PanelNorte() {
JLabel titulo = new JLabel("Registro de nuevo usuario");
titulo.setFont(new Font("Verdana", Font.ITALIC, 36));
add(titulo);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(20, 20, 0, 20),
BorderFactory.createRaisedSoftBevelBorder()));
}
}

private class PanelCentro extends JPanel {

public PanelCentro() {

setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(new Panel1()); add(new Panel2()); add(new Panel3());
setBorder(BorderFactory.createEmptyBorder(20, 20, 10, 20));
}
}

private class PanelSur extends JPanel {

public PanelSur() {
JPanel pnRegistrar = new JPanel();
pnRegistrar.add(btRegistrar);
JPanel pnCancelar = new JPanel();
pnCancelar.add(btCancelar);

setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(pnRegistrar);
add(pnCancelar);
setBorder(BorderFactory.createEmptyBorder(10, 20, 20, 20));
}
}

//Metodos

/**
* Junta todos los datos en un array y los retorna.<br>
* Puesto que hay datos de distintas clases, String y Date,
* los retornamos como Object.
* @return Array de Object con los datos del formulario.
*/
public Object[] getDatos() {

Object[] datos = new Object[6];
datos[0] = jtCedula.getText();
datos[1] = String.valueOf(jtPassword.getPassword());
datos[2] = jtNombre.getText();
datos[3] = jtEmail.getText();
datos[4] = rbHombre.isSelected()?"Hombre":"Mujer";
datos[5] = selecFecha.getDate();
//La edad no se retorna, pero se calcula para mostrar en formulario
calcularEdad();

return datos;
}

/**
* Borra todos los datos insertados dejando limpio
* el formulario.
*/
public void resetFormulario() {
jtCedula.setText(null);
jtPassword.setText(null);
jtNombre.setText(null);
jtEdad.setText(null);
jtEmail.setText(null);
selecFecha.setDate(new Date());
}

/**
* Setea un valor para la cédula.<br>
* Este valor provendrá del formulario de login, cuando el usuario
* ha solicitado registrarse como nuevo usuario.
* @param cedula Valor String para el campo cédula
*/
public void setCedula(String cedula) {
jtCedula.setText(cedula);
}

/**
* Setea un valor para la contraseña.<br>
* Este valor provendrá del formulario de login, cuando el usuario
* ha solicitado registrarse como nuevo usuario.
* @param pass Valor String para el campo contraseña.
*/
public void setPassword(String pass) {
jtPassword.setText(pass);
}

/**
* Calcula la edad del usuario recuperando la fecha seleccionada en el
* JDateChooser y comparando con la fecha actual.<br>
*/
private void calcularEdad() {
Date selec = selecFecha.getDate();
Date hoy = new Date();

long diferencia = hoy.getTime() - selec.getTime();
//Convertimos a horas
long horas = diferencia/3600000;
//Horas a dias
int dias = (int) (horas/24);
//Y los años serán la edad
int edad = dias/365;
jtEdad.setText(Integer.toString(edad));
}

/**
* Una validación muy simple para comprobar si el valor introducido
* en el campo Email tiene el formato esperado para una dirección de
* correo electrónico.<br>
* La comprobación es muy básica, se limita a ver si hay una arroba y al menos un punto.
* Y que este punto está después de la arroba, con al menos 1 carácter entre ambos.
* @return TRUE si parece un e-mail válido en su formato, FALSE en caso contrario.
*/
public boolean validarEmail() {
String email = jtEmail.getText();

if (email.isBlank())
return false;
else {
int arroba = email.indexOf('@');
int punto = email.lastIndexOf('.');
if (arroba == -1 || punto == -1)
return false;
else
return punto - arroba > 1;
}
}

/*
* Los siguientes métodos son para agregar acciones a los botones
* del formulario. Estas acciones se escriben desde la clase Main
* donde se puede interactuar con otros objetos como paneles y el
* gestor de usuarios, que no son visibles desde esta clase.
*
* El botón Cancelar recibe una segunda acción desde esta misma clase,
* escrita en el constructor, que es simplemente resetear el formulario.
*/
public void setAccionRegistrar(ActionListener accion) {
btRegistrar.addActionListener(accion);
}

public void setAccionCancelar(ActionListener accion) {
btCancelar.addActionListener(accion);
}
}

De él quiero comentar cosas sobre el JDateChooser. Nunca antes lo había usado, ya que es una librería externa "no oficial". Es muy útil sin duda, aunque como ya comenté, está basado en clases casi en desuso como Date y Calendar.
Revisando su documentación, he visto que en su constructor podemos indicarle que formato queremos para mostrar la fecha, así como una "careta" para que el campo de texto que incluye tome el tamaño adecuado.
El tercer argumento, el guión, es para indicar que caracter queremo usar como separador entre dia-mes-año
Código: [Seleccionar]
selecFecha = new JDateChooser("dd/MM/yy", "##/##/##", '-');
Para que el campo de texto del selector no aparezca vacío, le seteo la fecha actual:
Código: [Seleccionar]
selecFecha.setDate(new Date()); //Comienza con fecha actual
El enunciado no dice nada sobre límites de edad para registrar pasajeros, así que en principio se puede registrar alguien nacido hoy mismo, por lo que tendría 0 años....
Sin embargo, si he creído oportuno impedir que se puedan seleccionar fechas posteriores a la actual y esto lo limito con este método:
Código: [Seleccionar]
selecFecha.setMaxSelectableDate(new Date());
Explicado esto, veamos los métodos que va a tener esta clase.
El primero será para recopilar todos los datos del formulario y retornarlos. La idea es recibirlos en la clase Main, desde donde tomaremos decisiones según estos datos.

Código: [Seleccionar]
public Object[] getDatos() {

Object[] datos = new Object[6];
datos[0] = jtCedula.getText();
datos[1] = String.valueOf(jtPassword.getPassword());
datos[2] = jtNombre.getText();
datos[3] = jtEmail.getText();
datos[4] = rbHombre.isSelected()?"Hombre":"Mujer";
datos[5] = selecFecha.getDate();
//La edad no se retorna, pero se calcula para mostrar en formulario
calcularEdad();

return datos;
}

Los datos los juntamos en un array para que vayan todos juntos. Si todos los valores fuesen String, podríamos usar un array de String. Pero hay un dato que no lo es, la fecha de nacimiento (es un Date), así que para que puedan ir todos juntos, usaremos un array de Object.
Esto luego veremos que supone un pequeño inconveniente, para operar con ellos habrá que casting a String y Date según corresponda, pero se compensa por la comodidad de poder enviarlos todos juntos en el mismo array.

Otro método será el típico de resetear formulario, no requiere explicaciones:
Código: [Seleccionar]
public void resetFormulario() {
jtCedula.setText(null);
jtPassword.setText(null);
jtNombre.setText(null);
jtEdad.setText(null);
jtEmail.setText(null);
selecFecha.setDate(new Date());
}

Tendrá dos setter, uno para setear la Cédula y otro para setear el Password. Esto es porque dichos datos serán recuperados desde el formulario de login inicial. Luego el usuario podrá modificarlos si quiere antes de registrar

Código: [Seleccionar]
public void setCedula(String cedula) {
jtCedula.setText(cedula);
}

public void setPassword(String pass) {
jtPassword.setText(pass);
}


Método interesante es el de calcular la edad. Se recupera la fecha seleccionada en el JDateChooser y la actual.
Se calcula la diferencia entre ambas, en milisegundos.... los cuáles para transformar en años, de forma que se entienda lo que se hace, pues primero convierto a horas, luego a días y luego a años.
De este modo, se obtiene la edad del Pasajero. Este dato no es un atributo de la clase Pasajero, pero el enunciado pide que se calcule y se muestre en un campo de texto.

Código: [Seleccionar]
private void calcularEdad() {
Date selec = selecFecha.getDate();
Date hoy = new Date();

long diferencia = hoy.getTime() - selec.getTime();
//Convertimos a horas
long horas = diferencia/3600000;
//Horas a dias
int dias = (int) (horas/24);
//Y los años serán la edad
int edad = dias/365;
jtEdad.setText(Integer.toString(edad));
}

También se pide que el campo de e-mail sea validado. Para ello uso este método, muy sencillo aunque efectivo, en el que lo que hago es comprobar si el valor introducido tiene una arroba y si dentro de la cadena está en una posición anterior al del último "punto" de la cadena.
De este modo, no aceptaría un email como este: correo.mail@es.
Pero sí uno como este:correo@mail.es

Código: [Seleccionar]
public boolean validarEmail() {
String email = jtEmail.getText();

if (email.isBlank())
return false;
else {
int arroba = email.indexOf('@');
int punto = email.lastIndexOf('.');
if (arroba == -1 || punto == -1)
return false;
else
return punto - arroba > 1;
}
}

Luego hay dos métodos para setear acciones a los dos botones del formulario, uno para registrar los datos y otro para cancelar y volver al formulario de login.
Esta clase nos mostrará una interfaz como esta:


Y cuando pulsemos el botón "registrar", cuya acción luego escribiremos en la clase Main, haremos que nos pida confirmación de los datos introducidos.


Y si confirmamos, se guardarán los datos en el archivo de texto, este nuevo usuario quedará logueado y se nos mostrará la pantalla del "Menú de Pasajeros"



Este menú, según el enunciado, solo tendrá esas dos opciones.
Voy a poner el código para crear ese panel, es prácticamente calcado al que usamos para escribir el "Panel de Administrador", solo que en lugar de 4 botones, tendremos solo 2.
Al igual que el de Administrador, de momento estos botones no van a tener acciones.

Código: [Seleccionar]
package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class PanelPasajero extends JPanel {

private BotonOpcion btBuscaRuta;
private BotonOpcion btCompraBoletos;
private JButton btLogout;

public PanelPasajero() {

btBuscaRuta = new BotonOpcion("Buscador<br>de<br>Rutas");
btCompraBoletos = new BotonOpcion("Comprar<br>Boletos");
btLogout = new JButton("Cerrar Sesión");

setLayout(new BorderLayout());
add(new PanelNorte(), BorderLayout.NORTH);
add(new PanelCentral(), BorderLayout.CENTER);
add(new PanelSur(), BorderLayout.SOUTH);

}

private class PanelNorte extends JPanel {

public PanelNorte() {
JLabel titulo = new JLabel("Menú de Pasajeros");
titulo.setFont(new Font("Verdana", Font.ITALIC, 36));
add(titulo);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(20, 20, 0, 20),
BorderFactory.createRaisedSoftBevelBorder()));
}
}

private class PanelCentral extends JPanel {

public PanelCentral() {

setLayout(new GridLayout(1,1,15,15));
add(btBuscaRuta); add(btCompraBoletos);
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
}
}

private class PanelSur extends JPanel {

public PanelSur() {
JPanel pnBoton = new JPanel();
pnBoton.add(btLogout);
add(pnBoton);
}
}

private class BotonOpcion extends JButton {

public BotonOpcion(String texto) {
super("<html><p style=\"text-align:center\">" + texto + "</p></html>");
setFont(new Font("Verdana", Font.BOLD, 18));
setFocusPainted(false);
setBackground(new Color(102, 204, 255));
setForeground(Color.WHITE);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEtchedBorder(),
BorderFactory.createEmptyBorder(10, 10, 10, 10)));
addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {
setForeground(new Color(204, 0, 0));
}
@Override
public void mouseExited(MouseEvent e) {
setForeground(Color.WHITE);
}
});
}
}

//Métodos
public void setAccionLogout(ActionListener accion) {
btLogout.addActionListener(accion);
}
}

Bien, tenemos escrito el código para modelar el panel registro de nuevos usuarios y el del menú de opciones del pasajero.
En el siguiente post voy a poner los cambios que hay que hacer en la clase Main para incluirlos en nuestro programa.

453
Hola.

El método split() no te va a servir en este caso:
Código: [Seleccionar]
String[] partes = cadena.split(",");
Esto lo que hace es dividir una cadena, siempre que esta contenga la subcadena que especificamos entre comillas.
Es decir, para que te sirviera, habría que introducir el número de teléfono así:
Citar
3,2,2,1,2,3,4,5,6,7

Entonces, split(",") sí que podría crear un array con todos los dígitos separados.

De todos modos, no lo necesitas para lo que quieres resolver.


Otro fallo importante a destacar está en el método de comprobarNumeros, pues está declarado como tipo boolean, pero no retorna ningún valor.
Citar
        public static boolean comprobarNumeros(String num) {
         String str = cadena;
        boolean isNumeric = true;
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isDigit(str.charAt(i))) {
                isNumeric = false;
            }
        }
        System.out.println(isNumeric);
    }

Al final del método lo único que hace es mostrar en pantalla el valor del boolean isNumeric, pero no lo retorna. Así que el compilador de Java no lo va a aceptar, si el método se declara como tipo boolean, ha de retornar un valor boolean obligatoriamente.

Además, eso es lo que realmente necesitas. No sirve de mucho que en pantalla se muestre "true" o "false", lo que necesitas es que ese valor sea retornado para poder tomar decisiones dentro del código.

Citar
        public static boolean comprobarNumeros(String num) {
         String str = cadena;
        boolean isNumeric = true;
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isDigit(str.charAt(i))) {
                isNumeric = false;
            }
        }
        return isNumeric;
    }


Te dejo este código, bastante parecido en realidad al que estabas proponiendo, pero corrigiendo lo mencionado y cambiando algunos enfoques.
Asegúrate de que entiendes cada línea, si no es así, no dudes en preguntar cualquier cosa.

Un saludo.

Código: [Seleccionar]
public class EvaluaTelefono {

public static void main(String[] args) {

Scanner scn = new Scanner(System.in);
        String cadena ="";
 
        while (!cadena.equals("salir")) {
       
        System.out.println("\n\t Ingresa el numero telefonico con el formato que se indica");
            System.out.println("\t 322xxxxxx");
            System.out.println("\t Escriba \"salir\" para terminar programa");
            System.out.print("\n\t Cadena: ");
            cadena = scn.nextLine();
       
        if (!cadena.equals("salir")) {
                //Comprobamos si tiene 10 caracteres
                if (cadena.length() != 10) {
                System.out.println("El número ha de tener 10 cifras");
                }
                else if (!todoDigitos(cadena)) { //Comprobamos si todo son digitos
                System.out.println("El número ha de estar compuesto solo por dígitos");
                }
                else if (!cadena.startsWith("322")) { //Comprobamos si comienza por 322
                System.out.println("El número ha de comenzar por 322");
                }
                else { //Todas las comprobaciones han sido superadas
                System.out.println("El número es correcto");
                }
        }
        }
       
        scn.close();
        System.out.println("\n\t\tFIN DE PROGRAMA");

}

public static boolean todoDigitos(String cadena) {
//Recorremos cada caracter de la cadena a ver si son dígitos
for (int i = 0; i < cadena.length(); i++) {
if (!Character.isDigit(cadena.charAt(i)))
return false; //Si encontramos un caracter "no dígito" retornamos false
}
//Si el bucle for termina sin haber retornado false, es que TODOS son dígitos
return true;
}

}

454
Vamos a comenzar a hacer la interfaz.

El primer panel que mostraremos, sería una pantalla de login.
Pediremos cedula y password.
Podemos usar un JCheckBox para que el usuario indique si lo que quiere es crear un nuevo registro.
Tendrá un método para recoger los valores que introduzca el usuario en los dos campos de texto y retornarlos juntos.
Para que vayan juntos, se agruparán en un array de String.
Es necesario retornarlos porque no será aquí donde se comprueben si corresponden a un usuario registrado, esto se hará en la clase Main, que ya veremos después.

Otro método es para saber si el usuario quiere hacer registro nuevo y otro más para asignarle un ActionListener al botón. Este ActionListener se escribirá en la clase Main, donde se tendrá mejor acceso a la clase que gestiona usuarios y a los otros paneles de la interfaz.

Código: [Seleccionar]
package gui;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

@SuppressWarnings("serial")
public class PanelLogin extends JPanel{

private JTextField jtCedula;
private JPasswordField jtPassword;
private JCheckBox jcNuevoRegistro;
private JButton btLogin;

public PanelLogin() {
jtCedula = new JTextField(8);
jtPassword = new JPasswordField(8);
jcNuevoRegistro = new JCheckBox("Nuevo Registro");
jcNuevoRegistro.setToolTipText("Marque esta casilla para registrar un nuevo usuario");
btLogin = new JButton("Iniciar Sesión");

setLayout(new BorderLayout());
add(new PanelCentral(), BorderLayout.CENTER);
add(new PanelSur(), BorderLayout.SOUTH);

setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
}

private class PanelCentral extends JPanel {

public PanelCentral() {

JLabel texto = new JLabel("Introduzca datos para iniciar sesión");
texto.setFont(new Font("Verdana", Font.BOLD, 24));
JPanel pnTexto = new JPanel();
pnTexto.add(texto);

JPanel pnNombre = new JPanel();
pnNombre.add(new PanelCampoTexto("Cédula: ", jtCedula));

JPanel pnPass = new JPanel();
pnPass.add(new PanelCampoTexto("Password: ", jtPassword));

JPanel pnRegistro = new JPanel();
pnRegistro.add(jcNuevoRegistro);

setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(pnTexto); add(pnNombre); add(pnPass); add(pnRegistro);
}
}

private class PanelSur extends JPanel {

public PanelSur() {
JPanel pnBoton = new JPanel();
pnBoton.add(btLogin);
add(pnBoton);
}
}

private class PanelCampoTexto extends JPanel {

public PanelCampoTexto(String texto, JComponent campo) {
setLayout(new FlowLayout(FlowLayout.RIGHT));
add(new JLabel(texto));
add(campo);
}
}

//Métodos
/**
* Retorna los datos del formulario introducidos por el usuario.<br>
* Si algún campo esta vacío, se avisa en pantalla y se retorna null.<br>
* Si ambos campos contienen datos, se retornan juntos en un array.
* @return Array de String[] con el valor de la Cédula y el Password
*/
public String[] getDatos() {
String cedula = jtCedula.getText();
String password = String.valueOf(jtPassword.getPassword());
//Comprobamos si hay datos
if (cedula.isBlank()) {
JOptionPane.showMessageDialog(null, "El campo Cédula no puede estar vacío",
"Login Usuario", JOptionPane.WARNING_MESSAGE);
return null;
} else if (password.isBlank()) {
JOptionPane.showMessageDialog(null, "El campo Password no puede estar vacío",
"Login Usuario", JOptionPane.WARNING_MESSAGE);
return null;
} else {
//Juntamos ambos datos en un array y lo retornamos
return new String[] {cedula, password};
}
}

/**
* Indica si el Usuario está solicitando crear un nuevo registro
* con los datos que ha introducido.<br>El Usuario puede hacer esta
* solicitud marcando el CheckBox correspondiente.
* @return TRUE si es nuevo registro, FALSE en caso contrario.
*/
public boolean esNuevoRegistro() {
return jcNuevoRegistro.isSelected();
}

/**
* Resetea el formulario borrando los valores
* de todos sus campos.
*/
public void resetFormulario() {
jtCedula.setText(null);
jtPassword.setText(null);
jcNuevoRegistro.setSelected(false);
}

/**
* Recibe un ActionListener para agregarlo al botón de accion.<br>
* Este Listener se escribe en la clase Main porque requiere poder
* interactuar con otros objetos como el "Gestor de Usuarios" y
* el "Panel Principal" de la interfaz, que se encuentran fuera
* de este ámbito.
* @param accionBotonLogin ActionListener para el botón de acción
*/
public void setAccionBotonLogin(ActionListener accionBotonLogin) {
btLogin.addActionListener(accionBotonLogin);
}

}

Esto nos daría un panel como este, no es muy bonito, pero bueno. Cuando el programa esté terminado, se puede jugar a trastear con él para darle otra estética menos espartana



Si el login tiene éxito, se ha de mostrar un Panel de Administrador o un Panel de Pasajero, según el tipo de usuario que haya accedido al sistema.

Vamos primero con el panel de administrador.
Se trataría de un menú de 4 opciones, así que podemos usar 4 botones. Podemos mostrarlos con texto grande y hacerlos de gran tamaño, mostrados en una grilla (GridLayout) de 4x4.

Un quinto botón "normal" serviría para cerrar sesión (logout)

Código: [Seleccionar]
package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class PanelAdmin extends JPanel{

private BotonOpcion btTerminal;
private BotonOpcion btUnidad;
private BotonOpcion btRuta;
private BotonOpcion btReporte;
private JButton btLogout;

public PanelAdmin() {

btTerminal = new BotonOpcion("Gestión<br>de<br>Terminales");
btUnidad = new BotonOpcion("Gestión<br>de<br>Unidades");
btRuta = new BotonOpcion("Gestión<br>de<br>Rutas");
btReporte = new BotonOpcion("Reportes");
btLogout = new JButton("Cerrar Sesión");

setLayout(new BorderLayout());
add(new PanelNorte(), BorderLayout.NORTH);
add(new PanelCentral(), BorderLayout.CENTER);
add(new PanelSur(), BorderLayout.SOUTH);

}

private class PanelNorte extends JPanel {

public PanelNorte() {
JLabel titulo = new JLabel("Panel de Administrador");
titulo.setFont(new Font("Verdana", Font.ITALIC, 36));
add(titulo);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(20, 20, 0, 20),
BorderFactory.createRaisedSoftBevelBorder()));
}
}

private class PanelCentral extends JPanel {

public PanelCentral() {

setLayout(new GridLayout(2,2,15,15));
add(btTerminal); add(btUnidad);
add(btRuta); add(btReporte);
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
}
}

private class PanelSur extends JPanel {

public PanelSur() {
JPanel pnBoton = new JPanel();
pnBoton.add(btLogout);
add(pnBoton);
}
}

private class BotonOpcion extends JButton {

public BotonOpcion(String texto) {
super("<html><p style=\"text-align:center\">" + texto + "</p></html>");
setFont(new Font("Verdana", Font.BOLD, 18));
setFocusPainted(false);
setBackground(new Color(102, 204, 255));
setForeground(Color.WHITE);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEtchedBorder(),
BorderFactory.createEmptyBorder(10, 10, 10, 10)));
addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {
setForeground(new Color(204, 0, 0));
}
@Override
public void mouseExited(MouseEvent e) {
setForeground(Color.WHITE);
}
});
}
}

//Métodos
public void setAccionLogout(ActionListener accion) {
btLogout.addActionListener(accion);
}

}

Se vería algo como esto:


Al cerrar sesión, se volvería de nuevo al panel de login.
Y si se pulsará alguno de los 4 botones del menú, llevaría a otros paneles.
Como dije, todos estos paneles que habrá que ir creando, se pueden agrupar en un "Panel Principal" que use un CardLayout para gestionar todos estos paneles.
Este panel tendría este código.
Código: [Seleccionar]
package gui;

import java.awt.CardLayout;

import javax.swing.JPanel;

@SuppressWarnings("serial")
public class PanelPrincipal extends JPanel{

private CardLayout gestorPaneles;

public PanelPrincipal() {
gestorPaneles = new CardLayout();
setLayout(gestorPaneles);
}

public void mostrarPanel(String nombre) {
gestorPaneles.show(this,  nombre);
}

}
Sí, así de simple. Se le aplica un CardLayout y se le da un método mediante el cuál podamos pedirle que muestre un panel u otro, llamándolos por su "nombre.

Este "Panel Principal", será el contenedor del JFrame que escribiremos en nuestra clase Main.

Esta clase, es donde tendremos el Gestor de Usuarios (y posteriormente un Gestor de Terminales, de Unidades, de Rutas..)
Y tendremos todos los paneles, tendremos los ActionListener para los botones de acción de los paneles... Será la clase que haga de nexo con todo y ponga en marcha el programa.

Un atributo importante que tendrá será un objeto de clase Usuario, para representar el usuario que se haya logueado.
Según si este usuario es Administrador o Pasajero, se mostrarán unas opciones u otras.

De momento tengo este código, que junto a todo lo escrito anteriormente, ya podemos lanzar el programa y probar a loguearnos como Administrador con los datos
Cédula: CED000
Password: admin

Solo se puede iniciar y cerrar sesión, nada más. Lo siguiente que quiero añadir es el poder registrar un nuevo usuario. A ver cuando puedo...
Código: [Seleccionar]
package gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import usuario.*;

@SuppressWarnings("serial")
public class Main extends JFrame{

///Uusario que ha logueado, puede ser Admin o Pasajero
private Usuario logueado;

//Gestores
private GestorUsuario usuarios;

//Paneles
private PanelPrincipal pnPrincipal;
private PanelLogin pnLogin;
private PanelAdmin pnAdmin;

public Main() {

usuarios = new GestorUsuario();
pnPrincipal = new PanelPrincipal();
pnLogin = new PanelLogin();
pnLogin.setAccionBotonLogin(new AccionLogin());
pnAdmin = new PanelAdmin();
pnAdmin.setAccionLogout(new AccionLogout());

//Añadimos cada panel al panel principal.
pnPrincipal.add(pnLogin, "login");
pnPrincipal.add(pnAdmin, "admin");

setContentPane(pnPrincipal);

setTitle("Gestion de Terminales");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}

//Acciones
/**
* Recoge los datos del formulario de login y permite acceder
* a un usuario registrado, o bien crear un nuevo registro.<br>
* Cuando el Usuario ha accedido al sistema, se mostrará un panel
* de opciones según si es Administrador o Pasajero.
*/
private class AccionLogin implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//Recuperamos datos del formulario login
String[] datosLogin = pnLogin.getDatos();

if (datosLogin !=  null) {
//Preguntamos si es nuevo registro
if (pnLogin.esNuevoRegistro()) {
//TODO: Codigo para crear nuevo registro
}
else {//Es un login normal
//Intentamos login con los datos
logueado = usuarios.login(datosLogin[0], datosLogin[1]);
}

//Comprobamos si ha tenido exito el login y que tipo usuario se trata
if (logueado == null)
JOptionPane.showMessageDialog(null,
"Los datos introducidos no coinciden con ningun Usuario",
"Login Usuario", JOptionPane.WARNING_MESSAGE);
else {
//Login exitoso. Se mostrará un nuevo panel, según tipo usuario
if (logueado instanceof Administrador)
pnPrincipal.mostrarPanel("admin");
else
pnPrincipal.mostrarPanel("pasajero");
//El formulario de login se resetea
pnLogin.resetFormulario();
}
}
}
}

private class AccionLogout implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
logueado = null;
pnPrincipal.mostrarPanel("login");
}
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Main();
}
});
}
}

455
Veo que es una práctica bastante extensa.
Necesariamente habrá que usar clases y objetos.

No se cuánto tendrás avanzado. Yo voy a intentar empezarlo desde cero, según como lo haría yo, y a ver hasta donde llego.

De momento empezaría con la parte del login de usuario. Se puede hacer que el JFrame principal utilice un panel con un CardLayout. Este layout permite incorporar muchos paneles en uno solo, de manera que solo se muestre el que nos interese en cada momento.

Por ejemplo puede comenzar mostrando el formulario de login. Cuando el usuario acceda, si es un Administrador pues pasará a mostrar el menú de opciones de administración.
Y si es un Pasajero, pues pasará a mostrar su menú correspondiente.

Pero lo primero será crear las clases correspondientes a los usuarios.
Podemos hacer una clase Usuario, que sería abstracta, de la cuál luego heredarían Administrador y Pasajero.
Tendría solo los dos atributos de Cedula y Password, ya que son comunes a ambos tipos de Usuario.

También podemos sobreescribir  el método equals() para indicar que dos Usuarios se han de considerar "el mismo" si tienen la misma cédula.
Esto luego puede ser útil para evitar que se puedan registrar Usuarios con la misma cédula.

Código: [Seleccionar]
package usuario;

/**
 * Clase abstracta para modelar un Usuario.<br>
 * De esta clase heredarán Administrador y Pasajero.<br>
 * Los atributos mínimos para crear un usuario son la cédula
 * y la contraseña.
 */
public abstract class Usuario {

protected String cedula;
protected String password;

public Usuario(String cedula, String password) {
this.cedula = cedula;
this.password = password;
}

public String getCedula() {
return cedula;
}

public void setCedula(String cedula) {
this.cedula = cedula;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

/**
* Dos Usuarios son iguales si tienen
* la misma cédula.
*/
@Override
public boolean equals(Object objeto) {
if (objeto instanceof Usuario) {
Usuario otroUsu = (Usuario) objeto;
return cedula.equals(otroUsu.cedula);
}
else
return false;
}
}

Luego tendríamos la clase Administrador.
Esta clase en principio parece que no incorpora atributos extra: ni nombre, ni email, ni nada...

Sí le vamos a sobreescribir el método toString() para determinar como queremos representar los objetos Administrador en una línea de texto.
Esto será útil de cara a cuando haya que guardar los Usuarios en un archivo txt.
Según el enunciado, Administradores y Pasajeros se guardarán juntos en un mismo archivo.
Para poder distinguir unos de otros, podemos crear una regla identificativa. Yo por ejemplo, he optado por hacer que las líneas correspondientes a los usuarios Administradores, comiencen con una A mayúscula.
Cada dato se escribirá separado de dos guiones con espacios a los lados " -- ". Esto luego permitirá separar fácilmente unos datos de otros para cuando queramos recuperar los usuarios guardados en el txt y volver a registrarlos en el sistema.
Código: [Seleccionar]
package usuario;

/**
 * Clase para modelar un Administrador.<br>
 * No requiere de ningún atributo extra a parte de los
 * heredados de Usuario.<br>Sí se sobreescribe el método
 * <i>toString()</i> para indicar como vamos a querer
 * que se guarden sus datos en una línea del archivo txt.
 */
public final class Administrador extends Usuario {

public Administrador(String cedula, String password) {
super(cedula, password);
}

/**
* Devuelve los valores de los atributos con la letra A inicial
* para identificar al Usuario como un Administrador a la hora de
* recuperar los datos del archivo txt.
*/
@Override
public String toString() {
return String.format("A -- %s -- %s", cedula, password);
}

}

Ahora la clase Pasajero.
Esta clase si tendrá más atributos: nombre, email, genero, fecha nacimiento.
Todos los atributos serán String, excepto la fecha de nacimiento, que será de tipo Date..., al menos de momento.

Digo de momento, porque la clase Date no me gusta usarla debido a que se considera prácticamente obsoleta (deprecated). Esta clase tiene una serie de carencias que fueron solucionadas con clases como LocalDate y LocalTime, que son las que deberían usarse.

Sin embargo, el enunciado exige usar para la interfaz gráfica la librería externa JDateChooser, y por lo que he visto en su documentación, las fechas las trabaja con la clase Date. Así que parece que no quedará más remedio que usar estas clases.

Los objetos Pasajero, cuando se guarden en archivo de texto, se identificarán con una P mayúscula al principio de la línea.
Por cierto, para guardar la fecha en el archivo de texto, puesto que no es un String (es un Date), hay que decidir como hacerlo.
Se podría agregar código para transformar la fecha en un String tipo "dd-mm-aaaa", pero también es posible representar la fecha con un valor numérico de tipo long. Así que para ahorrar código probaremos a usar este valor.
Si luego vemos que no nos funciona bien, pues ya buscaremos otra forma de hacerlo.

Código: [Seleccionar]
package usuario;

import java.util.Date;

/**
 * Clase para modelar un Pasajero.<br>
 * incluye todos los atributos requeridos para construir un Pasajero.<br>
 * Sobreescribe el método <i>toString()</i> para indicar como vamos a querer
 * que se guarden sus datos en una línea del archivo txt.
 */
public final class Pasajero extends Usuario{

private String nombre;
private Date fechaNac;
private String genero;
private String eMail;

public Pasajero(String cedula, String password, String nombre,
Date fechaNac, String genero, String eMail) {
super(cedula, password);
this.nombre = nombre;
this.fechaNac = fechaNac;
this.genero = genero;
this.eMail = eMail;
}

public String getNombre() {
return nombre;
}

public void setNombre(String nombre) {
this.nombre = nombre;
}

public Date getFechaNac() {
return fechaNac;
}

public void setFechaNac(Date fechaNac) {
this.fechaNac = fechaNac;
}

public String getGenero() {
return genero;
}

public void setGenero(String genero) {
this.genero = genero;
}

public String geteMail() {
return eMail;
}

public void seteMail(String eMail) {
this.eMail = eMail;
}

/**
* Devuelve los valores de los atributos con la letra P inicial
* para identificar al Usuario como un Pasajero a la hora de
* recuperar los datos del archivo txt.<br>
* La fecha, un objeto Date, se guarda como milisegundos.
*/
@Override
public String toString() {
return String.format("P -- %s -- %s -- %s -- %d -- %s -- %s",
cedula, password, nombre, fechaNac.getTime(), genero, eMail);
}

}


Bien, tenemos clases que representan los distintos Usuario. Ahora hace falta una clase que los gestione, que tenga un ArrayList, que añada nuevos usuarios, que los busque para validar un login, que los guarde en un archivo txt, que los lea de ese archivo, etc...

He escrito la siguiente clase, que no está terminada, pues irá creciendo en código según avance con el programa.
De momento tiene métodos para leer archivo de texto, escribirlo en disco, y validar un login.
Le faltará por ejemplo un método para registrar nuevo usuario.

Código: [Seleccionar]
package usuario;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;

import javax.swing.JOptionPane;

/**
 * Esta clase gestionará un ArrayList con los Usuarios del sistema.<br>
 * Se encargará de registrar usuarios, comprobar datos para login,
 * guardar y leer el archivo txt con la información de los Usuarios.
 */
public final class GestorUsuario {

private ArrayList<Usuario> usuarios;

public GestorUsuario() {
usuarios = new ArrayList<Usuario>();
cargarDatos();
}

public Usuario login(String cedula, String password) {
//Buscará un usuario que coincida cedula y password, y lo retornará
for (Usuario usu: usuarios) {
if (usu.getCedula().equals(cedula) && usu.getPassword().equals(password))
return usu;
}
//Si bucle for no ha retornado ningun usuario, es que el login no es válido
return null;
}

/**
* Leerá el archivo de datos de Usuarios.<br>
* En caso de no existir archivo, o fracasar la lectura,
* creará automáticamente un usuario Administrador por defecto.
*/
private void cargarDatos() {

try {
BufferedReader br = new BufferedReader(new FileReader("usuarios.txt"));
String linea = br.readLine();

while(linea != null) {

//Separamos datos contenidos en la linea
String[] datos = linea.split(" -- ");

if (datos[0].equals("A")) {//Este usuario es un Administrador
//Administrador solo tiene cedula y password
usuarios.add(new Administrador(datos[1], datos[2]));
} else if (datos[0].equals("P")) { //Pasajero
//La fecha nacim. esta guardada en milisegundos,
//hay que generar un Date con ellos.
long milis = Long.parseLong(datos[4]);
Date fechaNac = new Date(milis);
usuarios.add(new Pasajero(datos[1], datos[2], datos[3], fechaNac, datos[5], datos[6]));
}

//siguiente linea
linea = br.readLine();
}

br.close();

} catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(null, "No se encuentra archivo: usuarios.txt\n"
+ "Se intentará generar uno nuevo", "Cargar Datos Usuarios",
JOptionPane.WARNING_MESSAGE);
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "Error intentando leer: usuarios.txt",
"Cargar Datos Usuarios", JOptionPane.WARNING_MESSAGE);
} catch (Exception error) {
JOptionPane.showMessageDialog(null, "Error recuperando datos de: usuarios.txt\n"
+ "Error:\n" + error.getLocalizedMessage(),
"Cargar Datos Usuarios", JOptionPane.WARNING_MESSAGE);
}

//Si fracasa la lectura de Usuarios, creamos nuevo archivo con un admin por defecto
if (usuarios.isEmpty()) {
usuarios.add(new Administrador("CED000", "admin"));
guardarDatos();
}

}

/**
* Guardará los datos de Usuarios en un archivo de texto.
*/
private void guardarDatos() {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter("usuarios.txt", false));
//Por cada usuario, creamos una línea de texto en el archivo
//Será necesario, hacer casting a cada tipo de Usuarios
for (Usuario usu: usuarios) {
if (usu instanceof Administrador)
bw.write(((Administrador)(usu)).toString());
else
bw.write(((Pasajero)(usu)).toString());

bw.newLine();
}
bw.close();
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Error intentando guardar: usuarios.txt",
"Guardar Datos Usuarios", JOptionPane.WARNING_MESSAGE);
}
}
}

456
Es otra posible solución.
Aunque no la he probado, pero creo que te pasará como me ocurría a mi al principio, no computará un valor numérico si se encuentra justo al final de la cadena

457
¿Qué es una unidad?¿Tiene atributos?
¿Qué es una ruta?¿Tiene atributos?
¿Cómo se supone que son las relaciones entre Unidades, Terminales y Rutas?
¿Una Ruta se compone de dos Terminales?
Para decidir cómo asignar Terminal a un Ruta, ¿depende de que compartan el atributo "lugar"?
¿Las Rutas son siempre dentro de un mismo "lugar"? ¿O una Ruta puede ir de un "lugar" a otro distinto?

Si es posible, estaría bien que compartieses el enunciado completo, para entender mejor lo que se pide modelar.

Kabuto también te quiero preguntar como funciona lo del frame es que lo intente con el jtabbed pane y agregando 2 paneles y le coloque el nombre Registrar y modificar pero no me funciona solo me sale el jOpanel diciendo que no existe el archivo

En el código que escribí, la primera vez que se inicia el programa SIEMPRE aparecerá el aviso de que no existe el archivo txt, porque aún no se han creado datos.

Después de crear datos, en las próximas sesiones sale un aviso similar indicando cuantas Terminales se han recuperado del archivo txt.

Al aceptar estos avisos, debería aparecer el marco JFrame con las dos pestañas para ir a un panel o a otro.



Si no ves este marco, comprueba que no se haya quedado "detrás" de tu editor de código.
Pulsa las teclas Alt+Tab a ver si así aparece.

458
Hola.
No, no vas bien.

Nada más empezar, tienes un bucle infinito

Código: [Seleccionar]
do
            {
                Console.WriteLine("Ingrese numero");


                numerIngre = Console.ReadLine();

            } while (respuesta == "si");

Esto se repite mientras respuesta sea igual a "si".
Pero como dentro del bucle, en ningún momento se altera el valor de respuesta, pues su valor SIEMPRE va a ser "si", así que el bucle se va a repetir infinitamente.

Luego, a parte de esto, eso de un switch que pregunta por "a", "b", "c"...
¿Por qué? ¿Por que así se enumeran las tareas en el enunciado?
Citar
//  a) La cantidad de números positivos.
            //b) La cantidad de números negativos.
            //   c) La cantidad de números pares.

Eso no tiene nada que ver con la lógica que ha de seguir el programa.
Ni pintan nada esos bucle for que van de 0 a 100..


La lógica a seguir sería:

- Pedir número.
- Si no es 0, comprobar si es negativo o positivo.
Si es negativo se incrementa un contador de negativos, si es positivo pues se incrementa un contador de positivos
-Comprobar si es par o impar e incrementar los contadores correspondientes.
- Preguntar si se quiere continuar si/no

-Repetir todo esto en un bucle mientras la respuesta a continuar sea "si".
- Cuando la respuesta sea "no", el bucle termina y entonces se muestra en pantalla los valores de los contadores.

El código podría ser como el que pondré a continuación.
Pruébalo, revisa los comentarios, asegurate de que entiendes cada línea, cada instrucción...
Cualquier cosa que no entiendas, o te parezca extraña o lo que sea, no dudes en preguntarlo y te lo explicaremos.  ;)

Un saludo.
Código: [Seleccionar]
        static void Main(string[] args)
        {
            //contadores
            int contPares = 0, contImpares = 0, contPositivos = 0, contNegativos = 0;
            //Variable para recoger lectura por teclado
            int valor;
            //Variable para consultar si desea continuar
            string respuesta;

            do
            {
                Console.Clear();
                //Pedimos valor
                Console.Write("Introduzca valor numerico: ");
                valor = int.Parse(Console.ReadLine());

                //Si no es un 0, comprobamos si es positivo o negativo
                if (valor != 0)
                {
                    if (valor > 0) //Positivo
                        contPositivos++;
                    else //Negativo
                        contNegativos++;
                }

                //Ahora comprobamos si es par. Un número es par si al dividir entre 2, su resto es 0 (usamos operador módulo)
                if (valor % 2 == 0) //Es par
                    contPares++;
                else //Es impar
                    contImpares++;

                //Evaluaciones completadas, preguntamos si quiere introducir otro número
                Console.Write("\nDesea ingresar otro número?[si/no]: ");
                respuesta = Console.ReadLine();

            } while (respuesta.Equals("si"));

            //Usuario ha terminado de ingresar valores. Mostramos resultados
            Console.Clear();
            Console.WriteLine("Numeros POSITIVOS ingresados: " + contPositivos);
            Console.WriteLine("Numeros NEGATIVOS ingresados: " + contNegativos);
            Console.WriteLine("Numeros PARES ingresados: " + contPares);
            Console.WriteLine("Numeros IMPARES ingresados: " + contImpares);

            Console.WriteLine("\n\t\tFIN DE PROGRAMA");
        }
    }

459
Hola.
Una forma sería recorrer la cadena String en busca de caracteres numéricos.
Al encontrar uno, lo podemos concatenar en otro String a parte y seguir buscando.
Si el siguiente carácter también es numérico, lo concatenamos en dicho String.

Cuando se encuentre un carácter que NO es numérico, lo que hacemos es comprobar si en el String donde hemos ido concatenado números, hay algo.
Si NO esta vacío, es que ya hemos concatenado una serie de números que componen una cifra. Así que este es el momento de convertir esa "subcadena" a tipo numérico y acumular la suma.
Y volvemos a dejar la subcadena vacía, para que el método siga buscando y cuando encuentre nuevos caracteres numéricos, repita el proceso de concatenarlos.

Bien, he escrito este método y funciona CASI bien.
Código: [Seleccionar]
private static void sumaNumerosCadena() {

Scanner teclado = new Scanner(System.in);
System.out.print("Cadena: ");
String cadena = teclado.nextLine();
teclado.close();

int suma = 0; //Aquí sumaremos los números encontrados
String subCadena = "";//Aquí concatenaremos los caracteres que representen cifras de números

for (int i = 0; i < cadena.length(); i++) {
//Buscamos caracteres que representen cifras
switch(cadena.charAt(i)) {
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
//Se ha encontrado una caracter numérico
subCadena = subCadena + cadena.charAt(i);//Concatenamos en la subCadena
break;
default:
/*
* El carácter no es numérico. Sin embargo, es posible que en
* la "subCadena" ya tengamos algunos numéros encontrados previamente.
* Hay que comprobarlo y en caso de tener algo, convertirlo a tipo numérico
* para poder acumular la suma
*/
if (!subCadena.isEmpty()) {//No está vacía, hay números, los computamos
System.out.println("Valor numérico detectado: " + subCadena);
//Parseamos la cadena a tipo entero
int valorNum = Integer.parseInt(subCadena);
//Acumulamos suma
suma += valorNum;
//Vacíamos la subCadena para cuando se vuelva a encontrar números en la cadena
subCadena = "";
}
}//fin del switch
}//fin del bucle for

System.out.println("\nLa suma de los números encontrados es: " + suma);
}

Al probarlo, me doy cuenta de que si al final de la cadena hay una cifra, no la recoge.
Citar
Cadena: estaban 12 niñas a las 8 pm en la calle 123
Valor numérico detectado: 12
Valor numérico detectado: 8

La suma de los números encontrados es: 20

¿Por qué ocurre esto?
Porque resulta que yo solo compruebo la subcadena cuando encuentro un carácter que No es número.
¿Y qué pasa si las últimos caracteres son TODOS numéricos?
Pues que cuando el bucle termina porque ya no quedan caracteres por comprobar, resulta que tengo esa última cifra concatenada en la subcadena, pero el programa termina sin que nadie se preocupe de convertirla a número y hacer la suma.

Entonces, para solucionarlo, después del switch, hay que hacer una comprobación extra.
Hay que preguntar si estamos ya en el último carácter, y si además la cadena NO está vacía.
Código: [Seleccionar]
if (i == (cadena.length()-1) && !subCadena.isEmpty())En cuyo caso, convertimos lo que haya a entero, y sumamos.

El método corregido queda así:
Código: [Seleccionar]
private static void sumaNumerosCadena() {

Scanner teclado = new Scanner(System.in);
System.out.print("Cadena: ");
String cadena = teclado.nextLine();
teclado.close();

int suma = 0; //Aquí sumaremos los números encontrados
String subCadena = "";//Aquí concatenaremos los caracteres que representen cifras de números

for (int i = 0; i < cadena.length(); i++) {
//Buscamos caracteres que representen cifras
switch(cadena.charAt(i)) {
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
//Se ha encontrado una caracter numérico
subCadena = subCadena + cadena.charAt(i);//Concatenamos en la subCadena
break;
default:
/*
* El carácter no es numérico. Sin embargo, es posible que en
* la "subCadena" ya tengamos algunos numéros encontrados previamente.
* Hay que comprobarlo y en caso de tener algo, convertirlo a tipo numérico
* para poder acumular la suma
*/
if (!subCadena.isEmpty()) {//No está vacía, hay números, los computamos
System.out.println("Valor numérico detectado: " + subCadena);
//Parseamos la cadena a tipo entero
int valorNum = Integer.parseInt(subCadena);
//Acumulamos suma
suma += valorNum;
//Vacíamos la subCadena para cuando se vuelva a encontrar números en la cadena
subCadena = "";
}
}//fin del switch

/*
* Cuando estamos ya en el último carácter de la cadena,
* conviene revisar si hay algo concatenado en la "subCadena".
* Ya que como no quedan caracteres por comprobar, el bucle
* va a terminar y puede quedarse algo concatenado pendiente
* de ser convertido a valor numérico
*/
if (i == (cadena.length()-1) && !subCadena.isEmpty()) {
System.out.println("Valor numérico detectado: " + subCadena);
int valorNum = Integer.parseInt(subCadena);
suma += valorNum;
}
}//fin del bucle for

System.out.println("\nLa suma de los números encontrados es: " + suma);
}

Y ahora en pantalla podemos ver que ya sí funciona correctamente y detecta todas las cifras, incluso la que está al final de la cadena:
Citar
Cadena: estaban 12 niñas a las 8 pm en la calle 123
Valor numérico detectado: 12
Valor numérico detectado: 8
Valor numérico detectado: 123

La suma de los números encontrados es: 143

460
Bueno, para empezar, sería saber en que lenguaje tienes que programarlo.


Luego, una forma que se me ocurre ahora mismo para resolverlo, sería utilizar una matriz de tipo char/caracteres. O también de String, podría servir.

Cada fila de la matriz podría estar compuesta de un tipo de carácter.
Por ejemplo, la primera fila, letras minúsculas.
Segunda, mayúsculas. Tercera, números. Cuarta, caracteres especiales.

abcdefghijklmn...
ABCDEFGHIJKLMN...
123456789012345...
|!"@·#$~%¬&/()...

Entonces, según lo que escoja el usuario, obtenemos posiciones al azar de las filas correspondientes.

Si solo quiere minúsculas, pues solo cogemos de la primera fila, la [ 0 ].
Y para la columna generamos un random, según la longitud de la matriz.
Supongamos que es 4x50.
Pues, escrito en una especie de pseudocódigo:
Código: [Seleccionar]
int col = random entre 0 y 49
obtener matriz[0][col]

Si quieres minúsculas y caracteres especiales, pues habría que coger de fila [ 0 ] y de [3]
¿Cómo hacemos para elegir aleatoriamente de una fila u otra.
Pues lo mismo, generando más valores random.
Podemos poner esos dos valores de fila en un array y sacar de ahí un valor u otro de forma random

Código: [Seleccionar]
int[] filasElegidas = {0,3}; //Minúsculas y especiales
int azar = random entre 0 y 1;
int fila = filasElegidas[azar];
int col = random entre 0 y 49
obtener matriz[fila][col]

Este proceso de obtención elementos al azar de la matriz, se haría dentro de un bucle que se repita tantas veces como el usuario haya indicado como longitud para su contraseña

Páginas: 1 ... 18 19 20 21 22 [23] 24 25 26 27 28 ... 50

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".