681
De todo un poco... / Re:juego de batalla naval en netbeans con swing
« en: 21 de Junio 2020, 01:01 »
A ver, que he rascado algo más de tiempo.
Podemos comenzar a meterle mano ya a la GUI, así vamos concretando algunas ideas de la "Vista" para saber mejor que necesitamos del "Controlador" y del "Modelo" (la clase BattleShip)
La primera pantalla que ha de mostrar el programa es un formulario de login.
O sea, dos campos para nombre y password y por ejemplo tres botones:
Login, Nuevo Usuario y Cerrar Programa.
Podemos crear una clase que herede de JPanel y modelar este formulario.
Lo haremos sencillo, sin demasiadas florituras. Solo conseguir que los elementos queden más o menos alineados.
Le daremos dos métodos básicos en todo formulario. Uno para limpiar los campos y otro para retornar los valores introducidos por el usuario.
Este último comprobará que los campos tienen datos.
Si los tiene, los retornará juntos en un array de dos String: nombre y password.
Si falta alguno, mostrará un aviso al usuario y retornará valor null.
Este, y otros paneles que iremos haciendo, los mostraremos en un JFrame.
Este JFrame lo crearemos en la clase main, la principal. Haremos que herede de JFrame y de atributos tendrá la clase BattleShip, el "Modelo" y los distintos paneles que iremos creando, la "Vista".
Por lo tanto, esta clase equivaldrá al "Controlador", es decir, será quien ponga en comunicación la "Vista" con el "Modelo".
Estas tareas de Controlador las realizará mediante distintas clases internas de ActionListener que se asignarán a los botones de cada panel.
Por ejemplo, ya podemos incluir en esta clase main el ActionListener correspondiente al botón de validar los datos del login.
Recogerá los datos que retorna la clase PanelLogin y se los pasará a la clase BattleShip para que busque un Player que coincida con esos datos.
De momento, solo mostrará avisos indicando si el login es válido o no.
Esta sería la clase principal Main, donde ponemos como atributo un objeto de PanelLogin, lo inicializamos en el constructor, le agregamos al boton Login el ActionListener escrito al final del código.
Establecemos como contenedor del JFrame el objeto PanelLogin para que sea visible en pantalla.
En esa clase ActionListener, pasamos los datos de login a un método boolean de la clase BattleShip, que aún no está escrito.
Pues vamos a escribírselo:
Es sencillo, recibe el array con los dos String, nombre y password.
Recorre los Players registrados y si encuentra coincidencia, marca a ese Player como logueado y retorna true.
De lo contrario, retorna falso.
Con todo esto, podemos probar a ver como va la interfaz.
![](https://i.ibb.co/2h2Ggkt/00.jpg)
Si probamos a loguearnos:
![](https://i.ibb.co/3Wgrdnv/01.jpg)
Login rechazado.
Claro, nuestra lista de Players esta vacía. Aún no hemos registrado Jugadores.
Tenemos que dotar de funcionalidad para poder hacer registros mediante el botón "Nuevo Usuario".
¿Que hacemos cuando el usuario pulse este botón?
Mostrar un nuevo formulario para pedirle nombre y password es redundante, podemos usar el mismo PanelLogin. Así, con los mismos datos, el usuario podrá loguearse con el botón "Login" o bien registrarse con el botón "Nuevo Usuario".
Para ello, volvemos a la clase Main y creamos un nuevo ActionListener para esta funcionalidad.
Haremos que BattleShip reciba un nuevo Player con los datos obtenidos del PanelLogin y si todo va bien, quedará registrado.
A Main le añadimos esta clase interna:
Por último, el método de la clase BattleShip que recibe nuevos jugadores, lo vamos a retocar para que cuando el registro sea aceptado, este nuevo usuario quede ya logueado.
Y ahora ya podemos registrar nuevos jugadores.
Podemos comenzar a meterle mano ya a la GUI, así vamos concretando algunas ideas de la "Vista" para saber mejor que necesitamos del "Controlador" y del "Modelo" (la clase BattleShip)
La primera pantalla que ha de mostrar el programa es un formulario de login.
O sea, dos campos para nombre y password y por ejemplo tres botones:
Login, Nuevo Usuario y Cerrar Programa.
Podemos crear una clase que herede de JPanel y modelar este formulario.
Lo haremos sencillo, sin demasiadas florituras. Solo conseguir que los elementos queden más o menos alineados.
Le daremos dos métodos básicos en todo formulario. Uno para limpiar los campos y otro para retornar los valores introducidos por el usuario.
Este último comprobará que los campos tienen datos.
Si los tiene, los retornará juntos en un array de dos String: nombre y password.
Si falta alguno, mostrará un aviso al usuario y retornará valor null.
Código: [Seleccionar]
public class PanelLogin extends JPanel{
private JTextField campoNombre;
private JTextField campoPass;
public JButton botonLogin;
public JButton botonNuevo;
private JButton botonSalir;
public PanelLogin() {
campoNombre = new JTextField(10);
campoPass = new JTextField(10);
botonLogin = new JButton("Login");
botonNuevo = new JButton("Nuevo Usuario");
botonSalir = new JButton("Cerrar Programa");
botonSalir.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0); //Esto cierra el programa
}
});
setLayout(new BorderLayout());
add(new PanelCentro(), BorderLayout.CENTER);
add(new PanelSur(), BorderLayout.SOUTH);
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
}
//Paneles que componen el panel principal
private class PanelCentro extends JPanel {
public PanelCentro() {
JPanel datos = new JPanel();
datos.setLayout(new GridLayout(2,2,5,5));
JPanel nombreLabel = new JPanel();
nombreLabel.setLayout(new FlowLayout(FlowLayout.RIGHT));
nombreLabel.add(new JLabel("Nombre: "));
JPanel nombreCampo = new JPanel();
nombreCampo.setLayout(new FlowLayout(FlowLayout.LEFT));
nombreCampo.add(campoNombre);
JPanel passLabel = new JPanel();
passLabel.setLayout(new FlowLayout(FlowLayout.RIGHT));
passLabel.add(new JLabel("Password: "));
JPanel passCampo = new JPanel();
passCampo.setLayout(new FlowLayout(FlowLayout.LEFT));
passCampo.add(campoPass);
datos.add(nombreLabel);
datos.add(nombreCampo);
datos.add(passLabel);
datos.add(passCampo);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(datos);
JPanel boton = new JPanel();
boton.add(botonLogin);
add(boton);
setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10),
BorderFactory.createTitledBorder("Datos Login")));
}
}
private class PanelSur extends JPanel {
public PanelSur() {
JPanel nuevo = new JPanel();
nuevo.add(botonNuevo);
JPanel salir = new JPanel();
salir.add(botonSalir);
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(nuevo); add(salir);
}
}
//Métodos de la clase
public void resetFormulario() {
campoNombre.setText(null);
campoPass.setText(null);
}
/**
* Recupera los datos del formulario y los retorna juntos en un array
* de dos elementos: nombre y password.
* @return Array String[] con los dos datos del formulario.
*/
public String[] getDatosLogin() {
String nombre = campoNombre.getText();
String password = campoPass.getText();
if (nombre.isEmpty()) {
JOptionPane.showMessageDialog(null, "El campo Nombre no puede estar vacío",
"Login Player", JOptionPane.ERROR_MESSAGE);
return null;
}
if (password.isEmpty()) {
JOptionPane.showMessageDialog(null, "El campo Password no puede estar vacío",
"Login Player", JOptionPane.ERROR_MESSAGE);
return null;
}
//Tenemos datos, los devolvemos en un array
return new String[] {nombre, password};
}
}
Este, y otros paneles que iremos haciendo, los mostraremos en un JFrame.
Este JFrame lo crearemos en la clase main, la principal. Haremos que herede de JFrame y de atributos tendrá la clase BattleShip, el "Modelo" y los distintos paneles que iremos creando, la "Vista".
Por lo tanto, esta clase equivaldrá al "Controlador", es decir, será quien ponga en comunicación la "Vista" con el "Modelo".
Estas tareas de Controlador las realizará mediante distintas clases internas de ActionListener que se asignarán a los botones de cada panel.
Por ejemplo, ya podemos incluir en esta clase main el ActionListener correspondiente al botón de validar los datos del login.
Recogerá los datos que retorna la clase PanelLogin y se los pasará a la clase BattleShip para que busque un Player que coincida con esos datos.
De momento, solo mostrará avisos indicando si el login es válido o no.
Esta sería la clase principal Main, donde ponemos como atributo un objeto de PanelLogin, lo inicializamos en el constructor, le agregamos al boton Login el ActionListener escrito al final del código.
Establecemos como contenedor del JFrame el objeto PanelLogin para que sea visible en pantalla.
Código: [Seleccionar]
public class Main extends JFrame{
private BattleShip batalla;
private PanelLogin panelLogin;
public Main() {
batalla = new BattleShip();
panelLogin = new PanelLogin();
panelLogin.botonLogin.addActionListener(new AccionLogin());
setContentPane(panelLogin);
setTitle("BattleShip");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setResizable(false);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Main();
}
});
}
//Clases ActionListener para PanelLogin
private class AccionLogin implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String[] datos = panelLogin.getDatosLogin();
if (datos != null) {
if (batalla.validarLogin(datos))
JOptionPane.showMessageDialog(null, "Login Aceptado");
else
JOptionPane.showMessageDialog(null, "Login Rechazado");
}
}
}
}
En esa clase ActionListener, pasamos los datos de login a un método boolean de la clase BattleShip, que aún no está escrito.
Pues vamos a escribírselo:
Código: [Seleccionar]
/**
* Recibe nombre y password para comprobar si existe un Player registrado
* con estos datos.<br>Si existe, este Player queda logueado.
* @param datos Array String[] con nombre y password.
* @return <i>True</i> si los datos son válidos, <i>False</i> en caso contrario.
*/
public boolean validarLogin(String[] datos) {
//Recorremos jugadores y buscamos mismo nombre, y mismo password
for (Player player: jugadores)
if (player.getNombre().equals(datos[0]) && player.getPassword().equals(datos[1])) {
//Login valido
jugador1 = player;
return true;
}
//Finalizado bucle for sin retornar true, es que el login no es válido
return false;
}
Es sencillo, recibe el array con los dos String, nombre y password.
Recorre los Players registrados y si encuentra coincidencia, marca a ese Player como logueado y retorna true.
De lo contrario, retorna falso.
Con todo esto, podemos probar a ver como va la interfaz.
![](https://i.ibb.co/2h2Ggkt/00.jpg)
Si probamos a loguearnos:
![](https://i.ibb.co/3Wgrdnv/01.jpg)
Login rechazado.
Claro, nuestra lista de Players esta vacía. Aún no hemos registrado Jugadores.
Tenemos que dotar de funcionalidad para poder hacer registros mediante el botón "Nuevo Usuario".
¿Que hacemos cuando el usuario pulse este botón?
Mostrar un nuevo formulario para pedirle nombre y password es redundante, podemos usar el mismo PanelLogin. Así, con los mismos datos, el usuario podrá loguearse con el botón "Login" o bien registrarse con el botón "Nuevo Usuario".
Para ello, volvemos a la clase Main y creamos un nuevo ActionListener para esta funcionalidad.
Haremos que BattleShip reciba un nuevo Player con los datos obtenidos del PanelLogin y si todo va bien, quedará registrado.
A Main le añadimos esta clase interna:
Código: [Seleccionar]
private class AccionNuevoUsuario implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String[] datos = panelLogin.getDatosLogin();
if (datos != null) {
//Con los datos obtenidos, creamos un nuevo Player
if (batalla.addPlayer(new Player(datos[0], datos[1])))
JOptionPane.showMessageDialog(null, "Registro aceptado",
"Nuevo Usuario", JOptionPane.INFORMATION_MESSAGE);
}
}
}
Al botón correspondiente, le añadimos esta nueva acción:Código: [Seleccionar]
public Main() {
batalla = new BattleShip();
panelLogin = new PanelLogin();
panelLogin.botonLogin.addActionListener(new AccionLogin());
panelLogin.botonNuevo.addActionListener(new AccionNuevoUsuario());
Por último, el método de la clase BattleShip que recibe nuevos jugadores, lo vamos a retocar para que cuando el registro sea aceptado, este nuevo usuario quede ya logueado.
Código: [Seleccionar]
/**
* Recibe un Player para añadir al listado. El nuevo Player quedará logueado<br>
* El Player será rechazado si ya existe otro con el mismo nombre.
* @param jugador Objeto Player que queremos registrar.
* @return <i>True</i> si se admitó el registro,
* <i>False</i> si ha sido rechazado.
*/
public boolean addPlayer(Player jugador) {
if (jugadores.contains(jugador)) {
JOptionPane.showMessageDialog(null, "Este Jugador ya está registrado", "Nuevo Jugador",
JOptionPane.WARNING_MESSAGE);
return false; //Ya existe este Player, lo rechazamos
}
else {
jugadores.add(jugador);
jugador1 = jugador; //El nuevo usuario queda logueado
return true;
}
}
Y ahora ya podemos registrar nuevos jugadores.