Autor Tema: java swing ventana gráfica  (Leído 8613 veces)

manuromero73

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 40
    • Ver Perfil
java swing ventana gráfica
« en: 10 de Septiembre 2022, 13:48 »
Hola me gustaría si me pueden ayudar con el ejercicico siguiente en Java.

Debe iniciar un programa con una ventana gráfica del tamaño de la pantalla del usuario. La ventana deberá dividirse de la siguiente manera. Un margen del 5% del tamaño de pantalla del usuario debe ser espacio libre. El espacio interior debe dividirse en dos mitades verticalmente. La mitad izquierda debe estar ocupada por un área donde el usuario pueda escribir a modo de text area. La mitad derecha debe estar ocupada en el 50 % superior por un label donde se podrán mostrar mensajes y en el 50 % inferior por dos botones centrados cuyo texto debe ser "Procesar" y "Borrar". Cuando el usuario pulse el botón Procesar en el Label se mostrará "Ha pulsado el botón procesar" y cuando pulse el botón Borrar se deberá borrar tanto el texto que pudiera existir en la caja de texto como el que pudiera existir en el label.

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #1 en: 10 de Septiembre 2022, 22:30 »
No se si tienes que hacerlo con el editor de ventanas de NetBeans, en ese caso no puedo ayudar porque nunca lo uso.

Sí puedo mostrar como lo haría yo, escribiendo código.

Hagamos primero un marco que contenga un "panel principal" con las dimensiones de la pantalla del usuario y un borde del 5%.
Para ello, la Toolkit nos puede proporcionar un objeto Dimension con las dimensiones de la pantalla, y con ello, establecer el tamaño del panel y calcular pixeles de los bordes

Código: [Seleccionar]
import java.awt.Dimension;
import java.awt.Toolkit;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Main extends JFrame {

public Main() {

setTitle("Marco Swing");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setContentPane(new PanelPrincipal());
pack();
setLocationRelativeTo(null);
setVisible(true);
}

private class PanelPrincipal extends JPanel {

public PanelPrincipal() {
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
setPreferredSize(dim);
int bordeAncho = dim.width * 5 / 100;
int bordeAlto = dim.height * 5 / 100;
setBorder(BorderFactory.createEmptyBorder(bordeAlto, bordeAncho, bordeAlto, bordeAncho));
}
}

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

Ok, si ejecutamos esto, veremos un marco ocupando toda la pantalla, pero no podemos apreciar ningún borde, porque el marco aún no contiene nada.

Vamos a añadir cosas.
El panel principal se ha de dividir en dos partes: a la izquiera un area de texto y a la derecha otra composición de dos paneles.

Empecemos con el area de texto.
Primero lo declaramos como atributo de clase.

A la clase PanelPrincipal, le aplicamos un GridLayout indicando que queremos una fila y dos columnas. Esas dos "columnas" serán los paneles izquierdo y derecho.
Así que primero añadimos a este layout un panel modelado en una clase llamada PanelCampoTexto y luego un panel "temporal", que de momento solo está para hacer bulto. Luego será sustituido para el panel que va a la derecha.

Esa clase PanelCampoTexto hay que escribirla. Y simplemente consiste en el area de texto, acompañado de un ScrollPane y maquetado con otro GridLayout de 1,1 para acoger como único elemento el ScrollPane.
La intención al usar GridLayout, es que este layout estira los elementos para que ocupen todo el ancho disponible.
Así no es necesario calcular dimensiones para los paneles y elementos que gestionan, estos ocupan todo el ancho disponible incluso aunque el usuario redimensione la ventana principal.

Citar
public class Main extends JFrame {
   
   private JTextArea campoTexto;
   
   public Main() {
      
      setTitle("Marco Swing");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setContentPane(new PanelPrincipal());
      pack();
      setLocationRelativeTo(null);
      setVisible(true);
   }
   
   private class PanelPrincipal extends JPanel {
      
      public PanelPrincipal() {
         Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
         setPreferredSize(dim);
         int bordeAncho = dim.width * 5 / 100;
         int bordeAlto = dim.height * 5 / 100;
         setBorder(BorderFactory.createEmptyBorder(bordeAlto, bordeAncho, bordeAlto, bordeAncho));
         
         setLayout(new GridLayout(1,2));
         add(new PanelCampoTexto()); //Panel que va a la izquierda
         add(new JPanel());//Panel temporal para ocupar parte derecha

      }
   }
   
   private class PanelCampoTexto extends JPanel {
      
      public PanelCampoTexto() {
         campoTexto = new JTextArea();
         setLayout(new GridLayout(1,1));
         JScrollPane scroll = new JScrollPane(campoTexto);
         add(scroll);
      }
   }


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

Si lo ejecutamos, ahora si apreciamos unos bordes y vemos que la mitad izquierda está ocupada por el area de texto.

Vamos a ver ahora el panel derecho.
Primero, declaramos el JLabel y los botones como atributos.

Creamos una nueva clase llamada, por ejemplo, PanelDerecho. Porque será el que pongamos a la derecha del panel principal.
Este panel tendrá dos subpaneles.
Uno arriba, con el JLabel.
Otro abajo, con los dos botones. Para facilitar el centrado de los botones, este panel también se subdividirá en otros dos paneles, uno para cada botón.

Opcionalmente podemos cambiar el tamaño de fuente de los botones y la etiqueta de mensajes.
Y ya puestos, también del área texto

Citar
public class Main extends JFrame {
   
   private JTextArea campoTexto;
   private JLabel etMensajes;
   private JButton btProcesar;
   private JButton btBorrar;

   
   public Main() {
      
      setTitle("Marco Swing");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setContentPane(new PanelPrincipal());
      pack();
      setLocationRelativeTo(null);
      setVisible(true);
   }
   
   private class PanelPrincipal extends JPanel {
      
      public PanelPrincipal() {
         Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
         setPreferredSize(dim);
         int bordeAncho = dim.width * 5 / 100;
         int bordeAlto = dim.height * 5 / 100;
         setBorder(BorderFactory.createEmptyBorder(bordeAlto, bordeAncho, bordeAlto, bordeAncho));
         
         setLayout(new GridLayout(1,2));
         add(new PanelCampoTexto()); //Panel que va a la izquierda
         add(new PanelDerecho());//Panel que va a la derecha
      }
   }
   
   private class PanelCampoTexto extends JPanel {
      
      public PanelCampoTexto() {
         campoTexto = new JTextArea();
         campoTexto.setFont(new Font("Verdana", Font.PLAIN, 44));
         setLayout(new GridLayout(1,1));
         JScrollPane scroll = new JScrollPane(campoTexto);
         add(scroll);
      }
   }
   
   private class PanelDerecho extends JPanel {
      
      public PanelDerecho() {
         
         etMensajes = new JLabel("Escriba y use botones", SwingConstants.CENTER);
         etMensajes.setFont(new Font("Verdana", Font.BOLD, 54));

         
         JPanel pnMensajes = new JPanel();
         pnMensajes.add(etMensajes);
         
         btProcesar = new JButton("Procesar");
         btProcesar.setFont(new Font("Verdana", Font.PLAIN, 34));
         btBorrar = new JButton("Borrar");
         btBorrar.setFont(new Font("Verdana", Font.PLAIN, 34));
         
         JPanel pnBotonProcesar = new JPanel();
         pnBotonProcesar.add(btProcesar);
         JPanel pnBotonBorrar = new JPanel();
         pnBotonBorrar.add(btBorrar);
         JPanel pnBotones = new JPanel();
         pnBotones.setLayout(new GridLayout(1,2));
         pnBotones.add(pnBotonProcesar);
         pnBotones.add(pnBotonBorrar);
         
         setLayout(new GridLayout(2,1));
         add(etMensajes);
         add(pnBotones);
         
      }
   }


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

Ahora esto ya tiene el aspecto que se pide, o al menos se acerca mucho.
Pero falta la funcionalidad, los botones no hacen nada todavía.
Así que vamos a escribir dos ActionListener, uno para cada botón y se los aplicamos.
Citar
public class Main extends JFrame {
   
   private JTextArea campoTexto;
   private JLabel etMensajes;
   private JButton btProcesar;
   private JButton btBorrar;
   
   public Main() {
      
      setTitle("Marco Swing");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setContentPane(new PanelPrincipal());
      pack();
      setLocationRelativeTo(null);
      setVisible(true);
   }
   
   private class PanelPrincipal extends JPanel {
      
      public PanelPrincipal() {
         Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
         setPreferredSize(dim);
         int bordeAncho = dim.width * 5 / 100;
         int bordeAlto = dim.height * 5 / 100;
         setBorder(BorderFactory.createEmptyBorder(bordeAlto, bordeAncho, bordeAlto, bordeAncho));
         
         setLayout(new GridLayout(1,2));
         add(new PanelCampoTexto()); //Panel que va a la izquierda
         add(new PanelDerecho());//Panel que va a la derecha
      }
   }
   
   private class PanelCampoTexto extends JPanel {
      
      public PanelCampoTexto() {
         campoTexto = new JTextArea();
         campoTexto.setFont(new Font("Verdana", Font.PLAIN, 44));
         setLayout(new GridLayout(1,1));
         JScrollPane scroll = new JScrollPane(campoTexto);
         add(scroll);
      }
   }
   
   private class PanelDerecho extends JPanel {
      
      public PanelDerecho() {
         
         etMensajes = new JLabel("Escriba y use botones", SwingConstants.CENTER);
         etMensajes.setFont(new Font("Verdana", Font.BOLD, 54));

         
         JPanel pnMensajes = new JPanel();
         pnMensajes.add(etMensajes);
         
         btProcesar = new JButton("Procesar");
         btProcesar.setFont(new Font("Verdana", Font.PLAIN, 34));
         btProcesar.addActionListener(new AccionProcesar());
         btBorrar = new JButton("Borrar");
         btBorrar.setFont(new Font("Verdana", Font.PLAIN, 34));
         btBorrar.addActionListener(new AccionBorrar());
         
         JPanel pnBotonProcesar = new JPanel();
         pnBotonProcesar.add(btProcesar);
         JPanel pnBotonBorrar = new JPanel();
         pnBotonBorrar.add(btBorrar);
         JPanel pnBotones = new JPanel();
         pnBotones.setLayout(new GridLayout(1,2));
         pnBotones.add(pnBotonProcesar);
         pnBotones.add(pnBotonBorrar);
         
         setLayout(new GridLayout(2,1));
         add(etMensajes);
         add(pnBotones);
         
      }
   }
   
   private class AccionProcesar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         etMensajes.setText("Ha pulsado el botón procesar");
      }
   }
   
   private class AccionBorrar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         etMensajes.setText(null);
         campoTexto.setText(null);
      }
   }


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

Y listo.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

manuromero73

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 40
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #2 en: 24 de Septiembre 2022, 20:17 »
Hola Kabuto en primer lugar muchas gracias por el codigo y por la explicacion, rara vez se encuentra alguien que explique tan completo. Ya he entregado el ejercicio pero me gustaria llegar a entenderlo bien por eso le estoy dedicando algun rato libre para repasarlo todo. En el primer codigo, donde creas el panel principal con la toolkit veo una clase Main con el constructor Main(), una clase privada PanelPrincipal y el método main()
Aquí cuando se crea el objeto con new Main() entiendo que se crea "el marco" que es el JFrame y que sería transparente y dentro de este "el lienzo" que seria el JPanel y que sería opaco. Una primera duda es con pack(); si comento esta instrucción la ventana no se despliega sino que aparece minimizada. ¿Por que si ya se ha establecido dimensiones con setPreferredSize? setLocationRelativeTo(null); creo que posiciona en el centro de la pantalla pero si lo comento me sale igual porque ya estamos ocupando toda la pantalla entonces entiendo que ¿aqui podriamos quitarlo sin perjuicio para el resultado? Otra duda es el por que declarar la clase PanelPrincipal como privada de la clase Main en lugar de hacerlo como clase independiente ¿Cual seria la ventaja?

Otra cosa que veo es la invocacion de la ejecucion, aparentemente con

Código: [Seleccionar]
public static void main(String[] args) {
new Main();
}

El resultado es el mismo que con

Código: [Seleccionar]
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Main();
}
});

¿Cual seria la ventaja?


Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #3 en: 25 de Septiembre 2022, 00:16 »
Citar
En el primer codigo, donde creas el panel principal con la toolkit veo una clase Main con el constructor Main(), una clase privada PanelPrincipal y el método main()
Aquí cuando se crea el objeto con new Main() entiendo que se crea "el marco" que es el JFrame y que sería transparente y dentro de este "el lienzo" que seria el JPanel y que sería opaco.

Sí, más o menos esa sería la explicación.
Nuestra clase Main es un JFrame, un "marco". Ahora se requiere de un "contenedor" (clase Container) que será el relleno opaco para el marco.

En este caso (hay otras formas de inicializar la propiedad "contenedor" de un JFrame), establecemos como "contenedor" un objeto que hereda de la clase JPanel, que a su vez es hija (nieta más bien) de la clase Container.
Código: [Seleccionar]
setContentPane(new PanelPrincipal());
Citar
Una primera duda es con pack(); si comento esta instrucción la ventana no se despliega sino que aparece minimizada. ¿Por que si ya se ha establecido dimensiones con setPreferredSize?

pack() autocalcula el tamaño del marco para ajustarse a los elementos y/o dimensiones que tenga el "contenedor".
Si no lo invocamos, no se calcula ningún tamaño para el marco y por eso solo aparece la barra de botones de la ventana.
Supongo que al pulsar el botón "maximizar", equivale a llamar a pack() y ahora sí aparece la interfaz.

El preferredSize se lo hemos dado al JPanel que hace de contenedor. Esta dimensión que le damos al JPanel, solo sirve si le pedimos al JFrame que calcule su propio tamaño. Y para eso invocamos a pack().

Citar
setLocationRelativeTo(null); creo que posiciona en el centro de la pantalla pero si lo comento me sale igual porque ya estamos ocupando toda la pantalla entonces entiendo que ¿aqui podriamos quitarlo sin perjuicio para el resultado?
Sí, podemos quitarlo.
Lo puse por costumbre, la verdad. Normalmente casi nunca hago ventanas que se ajusten a todo el ancho de pantalla, así que siempre pongo el setLocationRelativeTo().
Esta vez no caí en la cuenta de que no iba a ser necesario.

Citar
Otra duda es el por que declarar la clase PanelPrincipal como privada de la clase Main en lugar de hacerlo como clase independiente ¿Cual seria la ventaja?

Bueno, cuando son clases pequeñas que apenas superan las 20 líneas (PanelPrincipal es una decena de líneas) prefiero escribirlas dentro de la clase principal. No vale la pena crear un archivo .java separado para ellas.
Si fueran clases más extensas, con más elementos y funcionalidades que pudieran requerir mucho código, entonces si prefiero escribirlas como clases separadas.

De todos modos, sí tenemos una pequeña ventaja al escribirlas dentro de la clase principal.
Y la ventaja es que de esta manera comparten el mismo ámbito, y además lo comparten con los atributos de la clase Main principal.
Así hay total visibilidad entre ellas y los atributos y pueden combinarse facilmente.

Por ejemplo, fíjate en la clase PanelCampoTexto
Esta clase utiliza el objeto "campoTexto"
Citar
   
   private class PanelCampoTexto extends JPanel {
      
      public PanelCampoTexto() {
         campoTexto = new JTextArea();
         campoTexto.setFont(new Font("Verdana", Font.PLAIN, 44));
         setLayout(new GridLayout(1,1));
         JScrollPane scroll = new JScrollPane(campoTexto);
         add(scroll);
      }
   }

Pero este objeto, en realidad es un atributo de la clase Main:
Citar
public class Main extends JFrame {
   
   private JTextArea campoTexto;
   private JLabel etMensajes;
   private JButton btProcesar;
   private JButton btBorrar;
   

Como la clase PanelCampoTexto está declarada DENTRO de la clase Main, y lo mismo pasa con el atributo campoTexto, estos dos elementos son visibles entre ellos y por eso la clase PanelCampoTexto puede usarlo sin problemas.

Si esta clase la hubiéramos escrito como una clase separada, entonces estaría FUERA de la clase Main.
Cada clase tendría su propio ámbito individual y entonces PanelCampoTexto no podría usar los atributos de Main, porque no podría verlos.

En ese caso, tendríamos que declarar el JTextArea llamado campoTexto dentro de la clase PanelCampoTexto.
Pero entonces el botón "Borrar" no podría ver ese campo de texto para borrarlo.
Así que además a la clase PanelCampoTexto habría que darle también un método public que se encargue de borrar, método que ya sí podría ver el botón "Borrar" e invocarlo.


O bien, hacer que el  JTextArea de la clase Main llegue hasta la clase individual PanelCampoTexto mediante el constructor, o con un método set, algo como:
Código: [Seleccionar]
public void setCampoTexto(JTextArea campoDelMain) {
    campoTexto = campoDelMain;
}

Como ves, si se escriben por separado ya no comparten ámbito y hay que usar un poco más de código para hacer que las clases y elementos se comuniquen entre ellas.

Así que si son clases pequeñas, no pasa nada por escribirlas juntas dentro de la clase principal, y además se facilitan las cosas al compartir el mismo ámbito.

Pero si fuera un programa más grande y complejo, donde cada panel es tan complicado o más que este programa completo, entonces mejor escribirlas por separado. Aunque luego haya que andar pasando referencias por constructores o por setters para establecer comunicaciones entre las distintas clases.


Sobre esto:
Código: [Seleccionar]
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Main();
}
});
En programas sencillos como este, el 99% de las veces va funcionar igual si simplemente hacemos un new Main()
Código: [Seleccionar]
public static void main(String[] args) {
new Main();
}

Pero en programas Swing que sean un poco más complejos, pueden surgir problemas si no lo hacemos de la otra forma.

Todos los eventos Swing: eventos de ratón, de teclado, repintado de ventanas, etc... son gestionados por un hilo de ejecución (thread) separado que se llama EDT o Event dispatch Thread, o sea, el "despachador de eventos".

El problema es que el "hilo de ejecución principal" digamos que tiene preferencia sobre el EDT, el hilo de Swing.
Entonces, si en un momento dado ejecutamos una tarea que requiere de unos segundos, por ejemplo hacer una consulta a una base de datos que es muy grande, el hilo principal se mantendrá ocupado realizando esta tarea y el EDT no podrá hacer nada. Así que veremos cómo la interfaz se queda congelada durante unos segundos, sin responder ni el teclado, ni el ratón ni cualquier animación en la ventana.

Para evitar esto, con invokeLater() le estamos pidiendo que todos los procesos de la aplicación se ejecuten en el EDT. Así este hilo no se ve supeditado al principal y él solito ya se encarga de repartir los recursos para que los procesos de computación no afecten a los eventos de la interfaz.

Como digo, para programas sencillos nos va a dar igual ponerlo de una forma o de otra.
Pero aún así no está de más acostumbrarnos a ponerlo siempre
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

manuromero73

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 40
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #4 en: 02 de Octubre 2022, 20:57 »
Hola y gracias de nuevo. He mirado lo que dice el api de Java sobre SwingUtilities.invokeLater y veo que dice
Citar
public static void invokeLater(Runnable doRun)

Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread. This will happen after all pending AWT events have been processed. This method should be used when an application thread needs to update the GUI. In the following example the invokeLater call queues the Runnable object doHelloWorld on the event dispatching thread and then prints a message.

 Runnable doHelloWorld = new Runnable() {
     public void run() {
         System.out.println("Hello World on " + Thread.currentThread());
     }
 };

 SwingUtilities.invokeLater(doHelloWorld);
 System.out.println("This might well be displayed before the other message.");
 

If invokeLater is called from the event dispatching thread -- for example, from a JButton's ActionListener -- the doRun.run() will still be deferred until all pending events have been processed. Note that if the doRun.run() throws an uncaught exception the event dispatching thread will unwind (not the current thread).

Additional documentation and examples for this method can be found in Concurrency in Swing.

As of 1.3 this method is just a cover for java.awt.EventQueue.invokeLater().

Unlike the rest of Swing, this method can be invoked from any thread.

See Also:
    invokeAndWait(java.lang.Runnable)

Con lo que has indicado lo entenderia así: si lo creamos con

Código: [Seleccionar]
public static void main(String[] args) {
new Main();
}

La ejecución de las instrucciones de creación - gestión de la ventana gráfica quedan dentro del hilo principal de la aplicación y puede ocurrir lo que tú comentabas: que si en un momento dado es necesario un redibujado pero el hilo principal está entretenido en un proceso que lo ocupa, no se produce el redibujado sino que la interfaz gráfica se queda congelada hasta que se concluye lo que esta ocupando al hilo principal.

De la otra manera la interfaz grafica va dentro de un hilo independiente de despacho de eventos donde un posible redibujado se produciria despues de que todos los eventos en cola hayan sido gestionados pero de forma independiente respecto al hilo principal con lo cual si este esta entretenido los demas hilos asincronos no se quedan bloqueados.

Y me imagino que aun habria otra manera de plantear esto, que seria no tenerlo ni en el hilo principal ni en el hilo de despacho de eventos, sino en un nuevo hilo que podriamos crear independiente de estos dos.

Todo esto no lo veo sencillo, pero no se si podriamos decir que mas o menos la idea seria esta.

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #5 en: 02 de Octubre 2022, 22:45 »
Sí, esa es la idea.

Por otro lado, muchas veces el programador ya es capaz de prever que una determinada tarea puede ser lenta y requerir cierto tiempo de computación, así que intentará programarla de forma que se ejecute en un hilo separado para que no interfiera con el programa principal.

En cualquier caso, la cuestión es que siempre que hagamos una aplicación con GUI Swing, mejor ejecutarla en el hilo del despachador de eventos que no en el principal.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

manuromero73

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 40
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #6 en: 03 de Octubre 2022, 17:47 »
Lo agradezco al menos de forma aproximada es como pensaba. Para el código con las dos columnas creadas (paneles izquierdo y derecho) las dudas serian:

- No me compila sin importaciones adicionales supongo que es normal

Código: [Seleccionar]
import javax.swing.JPanel;
import java.awt.GridLayout;
import javax.swing.JScrollPane;

- Aparte hay una aproximacion que no veo muy clara

Como campo de main tenemos un atributo

Código: [Seleccionar]
public class Main extends JFrame {
   private JTextArea campoTexto;

¿No podria haber sido atributo de private class PanelCampoTexto extends JPanel en lugar de atributo de la clase Main?


Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #7 en: 04 de Octubre 2022, 00:45 »
Sí, pero ponerlo como atributo de Main tiene una ventaja.

Por ejemplo, la clase ActionListener para el botón de "Borrar", necesita tener acceso al campo de texto:

Citar
   private class AccionBorrar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         etMensajes.setText(null);
         campoTexto.setText(null);
      }
   }

Al ponerlo como atributo de Main, entonces es visible en todos los ámbitos del programa y este ActionListener puede acceder directamente a ese campo.

Si lo hubiéramos puesto como atributo de la clase PanelCampoTexto, entonces su ámbito se queda limitado al interior de esta clase.
El resto de clases ya no pueden acceder a él, porque no pueden "verlo" al ser un atributo privado de otra clase.
Aunque eso tendría otras soluciones:
- Declararlo como atributo public en lugar de private.
- Proporcionar a la clase PanelCampoTexto un gettter y un setter que de acceso a su atributo privado.
- O proporcionar a PanelCampoTexto un método que se encargue de borrar el campo, ya que en realidad es la única interacción que necesitamos hacer con él.
Este método sería publico y por tanto visible para otras clases.

Aunque para aplicar estas soluciones, tendremos que declarar a la propia clase PanelCampoTexto como atributo del Main.

Siempre hay distintas formas de hacer una misma cosa, ya cada programador decide cuál emplear.

Yo, cuando se trata de programas así sencillos como este, suelo declarar los campos de texto, etiquetas, botones, etc.. como atributos del Main. Al menos los que sé que otras clases van a necesitar poder acceder a ellos.

En un programa más complejo, donde fácilmente pueden haber 30 campos de texto, 12 botones, 40 etiquetas,.... hacerlo así puede resultar caótico y poco elegante tener medio centenar de atributos declarados en el Main.
En estos casos, ya sí prefiero que cada clase JPanel tenga sus propios atributos, con los setters/getters y métodos que hagan falta para que sus elementos puedan comunicarse con otras clases.
Y además, prefiero que cada una de estas clases estén escritas en su propio archivo .java.

Es curioso, pero cuánto más complejo es el programa, menos código acabo poniendo en el Main ;D
Porque prefiero "modularlo" en distintos archivos  .java.

Así es más fácil de desarrollar, comprobar y mantener el programa.
Si detecto un fallo en un panel en concreto, me voy a su archivo correspondiente a ver que está ocurriendo.
Es más cómodo ir mirando archivos sueltos de apenas un centenar de líneas, que no tener que revisar un único archivo kilométrico con miles y miles de líneas de código.
« Última modificación: 04 de Octubre 2022, 00:46 por Kabuto »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

manuromero73

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 40
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #8 en: 08 de Octubre 2022, 19:51 »
Gracias ahora en el código que incorpora el lado derecho con los labels y botones las importaciones me quedan así:

Código: [Seleccionar]
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.GridLayout;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;

JButton btProcesar entiendo que bt es botón pero no sé qué significado le aplicas a JLabel etMensajes, no sé qué se interpreta con et.

Al ejecutar el código me aparece el texto pero no se muestra entero, lo que me aparece es "Escriba y use bo..." Yo creo que se corta porque el tamaño de fuente excede el tamaño disponible en la pantalla. Pero supongo que a tí no te ocurre eso. Lo que quería preguntar es si podemos establecer un tamaño de fuente relativo de modo que se ajuste al tamaño de pantalla en que se visualice.

La otra cosa que me genera duda es la cantidad de JPanel que veo que creas. PanelDerecho ya es de por sí un JPanel. Dentro de ese JPanel veo que declaras otro JPanel pnMensajes = new JPanel(); otro más  JPanel pnBotonProcesar = new JPanel(); otro más JPanel pnBotonBorrar = new JPanel(); otro más JPanel pnBotones = new JPanel();

Luego creo que añades los JPanel de los botones al Jpanel de pnBotones y finalmente al JPanel PanelDerecho le añades el JLabel etMensajes y el JPanel pnBotones.

El JPanel pnBotones creo que tiene la utilidad de servir para montar los botones pero al JPanel pnMensajes no le veo utilidad ¿tiene uso?

Y la otra pregunta: ¿no podríamos haber montado tanto el JLabel etMensajes como los botones directamente sobre PanelDerecho ahorrándonos pnMensajes, pnBotonProcesar, pnBotonBorrar y pnBotones?

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #9 en: 09 de Octubre 2022, 01:30 »
et es "etiqueta" (label)
Son nomenclaturas mías que suelo usar. Cada uno usa las que le parece mejor, no hay ninguna "norma" o costumbre común respecto a esto.

Usar nomenclaturas es muy cómodo. Cuando por ejemplo llega el momento de escribir el código para que funcione el botón de borrar, me preguntaré ¿qué nombre le puse?
Pues en lugar de tener que desplazarme por el código buscando la línea donde lo declaré, puedo adivinar que probablemente lo habré llamado btBorrar ya que es mi costumbre habitual, así que no tengo que buscarlo.


Lo que mencionas sobre el tamaño de fuente, lo de decidir el tamaño según las características del ordenador donde se está ejecutando, es algo que yo mismo he pensado muchas veces pero no lo he investigado.
Sí se puede hacer, desde luego, pero...¿cómo decidir cuál es la fuente adecuada para cada caso?
No se si habrá un consenso sobre esto, sería interesante que algún profesional que se dedique a la programación de verdad nos comentara sobre este asunto.

Yo tengo un monitor de alta resolución, 2560x1440 px, y diría que NO ES COSTUMBRE adaptar el tamaño de fuentes, porque yo todos los programas que uso en mi día a día: navegadores web, Steam, Eclipse, Libre Office, Filmora...,, sea el que sea, me encuentro con que las fuentes son demasiado pequeñas para la resolución de mi pantalla.

Puedo configurar Windows para que automáticamente amplíe las fuentes un determinado porcentaje, pero no siempre consigue unos tamaños acertados.
Así que por lo general uso las opciones de configuración de cada programa (si las tiene) para ampliar fuentes, o bien acepto tener que dejarme la vista  :o

Pero NINGÚN programa hace una adaptación de fuentes apropiada a mi pantalla. Así que parece que no suele hacerse en el mundo profesional.
Supongo que no es fácil, ya que cada dispositivo es un mundo. Hay pantallas de móvil con la misma resolución que la de mi monitor, pero obviamente los tamaños de pantalla (mi monitor es 27") son muy distintos.

Así que los programas, si quisieran determinar una fuente de texto adecuada, tendrían que valorar la resolución en pixeles, el tamaño en pulgadas, la relación de aspecto (16:9, 4:3, 16:10,....), la orientación (vertical, apaisada..),....
Son demasiadas variables a tener en cuenta, demasiado difícil acertar..., y luego al final seguramente tendrá más peso las dioptrías 8) de cada persona que todo lo antes mencionado.
Así que mejor dejar una fuente única, y en todo caso, dar opciones para que el propio usuario elija un tamaño de fuente a su gusto.

Por otro lado, la fuente que puse para este programa es exageradamente grande.
Al tratarse de un formulario con tan pocos elementos, pero que ocupa toda la pantalla (y mi pantalla es muy grande), puse una fuente gigante que parece más un título que no un texto.


Sobre la cantidad de paneles, es para conseguir que los elementos queden lo mejor maquetados posibles.
Los elementos Swing, no siempre ocupan los espacios dentro de un panel de manera que queden centrados y/o repartidos de forma simétrica.
Combinando paneles y con los layout adecuados, se puede llegar a conseguir.

Por ejemplo, vamos a suponer que quiero dos botones que queden repartidos y centrados simétricamente en un formulario.
Si los añado en el contenedor base, con un FlowLayout

Código: [Seleccionar]
public class Prueba extends JFrame {

private JButton btUno;
private JButton btDos;

public Prueba() {
btUno = new JButton("Botón 1");
btDos = new JButton("Botón 2");

setLayout(new FlowLayout());

add(btUno);
add(btDos);

setTitle("Prueba");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 300);
setLocationRelativeTo(null);
setVisible(true);
}


public static void main(String[] args) {
new Prueba();
}

}

No queda como yo quiero, están ahí rejuntado en el centro, con un montón de panel vacío alrededor.
Además, están pegados arriba, no están centrados verticalmente.


¿Y si pruebo con un BoxLayout que ponga los elementos en el eje X(horizontal)?
Código: [Seleccionar]
public class Prueba extends JFrame {

private JButton btUno;
private JButton btDos;

public Prueba() {
btUno = new JButton("Botón 1");
btDos = new JButton("Botón 2");

setLayout(new BoxLayout(getContentPane(), BoxLayout.X_AXIS));

add(btUno);
add(btDos);

setTitle("Prueba");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 300);
setLocationRelativeTo(null);
setVisible(true);
}


public static void main(String[] args) {
new Prueba();
}

}

Vaya, ahora están centrados en la vertical, pero no la horizontal. Y siguen pegados el uno al otro...


¿Probamos a darle paneles propios a cada botón?
Código: [Seleccionar]
public class Prueba extends JFrame {

private JButton btUno;
private JButton btDos;

public Prueba() {
btUno = new JButton("Botón 1");
btDos = new JButton("Botón 2");

setLayout(new BoxLayout(getContentPane(), BoxLayout.X_AXIS));
JPanel pnUno = new JPanel();
pnUno.add(btUno);
JPanel pnDos = new JPanel();
pnDos.add(btDos);
add(pnUno);
add(pnDos);

setTitle("Prueba");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 300);
setLocationRelativeTo(null);
setVisible(true);
}


public static void main(String[] args) {
new Prueba();
}

}

Humm. se parece un poco más a lo que busco. El espacio horizontal está bien repartido.
Pero no el vertical, están pegados arriba, yo los quisiera en el centro.




A ver.., vamos a recurrir a la clase Box, la cuál nos permite crear una "caja" y añadir elementos "invisibles" para que ocupen espacios y así situar nuestro elemento "visible".
Haremos dos "cajas", con dos objetos invisibles verticales y entre ellos, nuestro panel con botón.
Código: [Seleccionar]
public class Prueba extends JFrame {

private JButton btUno;
private JButton btDos;

public Prueba() {
btUno = new JButton("Botón 1");
btDos = new JButton("Botón 2");

setLayout(new BoxLayout(getContentPane(), BoxLayout.X_AXIS));

JPanel pnUno = new JPanel();
pnUno.add(btUno);
Box cajaVertical1 = Box.createVerticalBox();
cajaVertical1.add(Box.createVerticalGlue());
cajaVertical1.add(pnUno);
cajaVertical1.add(Box.createVerticalGlue());
JPanel pnDos = new JPanel();
pnDos.add(btDos);
Box cajaVertical2 = Box.createVerticalBox();
cajaVertical2.add(Box.createVerticalGlue());
cajaVertical2.add(pnDos);
cajaVertical2.add(Box.createVerticalGlue());

add(cajaVertical1);
add(cajaVertical2);

setTitle("Prueba");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 300);
setLocationRelativeTo(null);
setVisible(true);
}


public static void main(String[] args) {
new Prueba();
}

}

Ahora sí, esto sería lo que busco.
Parece que por abajo hay más espacio que por arriba, pero yo lo daría por bueno.


Como ves, si nos ponemos caprichosos con las posiciones que queremos que ocupen los elementos, incluso para una interfaz simplona compuesta de solo dos botones, pues es muy posible que necesitemos "envolver" algunos elementos en su propio JPanel y así además poder combinar distintos layouts.


Hay un layout que nos permite evitar tener que usar tanto JPanel para situar los componentes a nuestros gusto. Es el GridBagLayout, tan útil y sofisticado... como complejo y enfarragoso de utilizar.

Si tienes curiosidad busca tutoriales por Google, cualquiera que encuentres seguro que sabe explicarlo mejor que yo  :P

Un saludo.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

manuromero73

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 40
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #10 en: 14 de Enero 2023, 15:20 »
He retomado un poco esto y he hecho un pequeño cambio.

La línea

Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();

me la he llevado como atributo de la clase Main para que pueda ser accesible desde cualquier lugar.

Como en mi pantalla no se ve el texto completo "Escriba y use botones" sino que se ve "Escriba y use boto..." debido a que el tamaño de fuente resulta excesivo para mi pantalla he cambiado

etMensajes.setFont(new Font("Verdana", Font.BOLD, 54));

Por etMensajes.setFont(new Font("Verdana", Font.BOLD, dim.width * 3 / 100));

Del mismo modo he cambiado el tamaño del texto de los botones.

         btProcesar.setFont(new Font("Verdana", Font.PLAIN, 34));
         btBorrar.setFont(new Font("Verdana", Font.PLAIN, 34));

Quedan como

         btProcesar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
         btBorrar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));

Para hacerlo todo igual he cambiado en la clase PanelCampoTexto

         campoTexto.setFont(new Font("Verdana", Font.PLAIN, 44));

por          campoTexto.setFont(new Font("Verdana", Font.PLAIN, dim.width * 2 / 100));

Estos valores de 3/100 y de (3/2)/100 que he escrito así para evitar un warning y no es más que 1.5/100 y 2/100 etc. son valores que he ido probando y que imagino irán bien en casi todas las pantallas, incluso en las muy grandes o muy pequeñas, aunque no estoy seguro.

Esto me parece que puede ser una solución aceptable para evitar que en unas pantallas se vean bien las cosas y en otras no, al quedar relativo a la pantalla parece que en general deberá verse bien, o eso creo. ¿Puede ser una buena estrategia?

El código (sin gestión de eventos) es:

Código: [Seleccionar]
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.GridLayout;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;

public class Main extends JFrame {

    private JTextArea campoTexto;
    private JLabel etMensajes;
    private JButton btProcesar;
    private JButton btBorrar;
    private Dimension dim;

    public Main() {
        dim = Toolkit.getDefaultToolkit().getScreenSize();
        setTitle("Marco Swing");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(new PanelPrincipal());
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private class PanelPrincipal extends JPanel {

        public PanelPrincipal() {
            setPreferredSize(dim);
            int bordeAncho = dim.width * 5 / 100;
            int bordeAlto = dim.height * 5 / 100;
            setBorder(BorderFactory.createEmptyBorder(bordeAlto, bordeAncho, bordeAlto, bordeAncho));

            setLayout(new GridLayout(1,2));
            add(new PanelCampoTexto()); //Panel que va a la izquierda
            add(new PanelDerecho());//Panel que va a la derecha
        }
    }

    private class PanelCampoTexto extends JPanel {

        public PanelCampoTexto() {
            campoTexto = new JTextArea();
            campoTexto.setFont(new Font("Verdana", Font.PLAIN, dim.width * 2 / 100));
            setLayout(new GridLayout(1,1));
            JScrollPane scroll = new JScrollPane(campoTexto);
            add(scroll);
        }
    }

    private class PanelDerecho extends JPanel {

        public PanelDerecho() {

            etMensajes = new JLabel("Escriba y use botones", SwingConstants.CENTER);
            etMensajes.setFont(new Font("Verdana", Font.BOLD, dim.width * 3 / 100));

            JPanel pnMensajes = new JPanel();
            pnMensajes.add(etMensajes);

            btProcesar = new JButton("Procesar");
            btProcesar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
            btBorrar = new JButton("Borrar");
            btBorrar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));

            JPanel pnBotonProcesar = new JPanel();
            pnBotonProcesar.add(btProcesar);
            JPanel pnBotonBorrar = new JPanel();
            pnBotonBorrar.add(btBorrar);
            JPanel pnBotones = new JPanel();
            pnBotones.setLayout(new GridLayout(1,2));
            pnBotones.add(pnBotonProcesar);
            pnBotones.add(pnBotonBorrar);

            setLayout(new GridLayout(2,1));
            add(etMensajes);
            add(pnBotones);

        }
    }

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

Hay una cosa que no me queda muy clara de este código, y es dentro de la clase PanelDerecho

Tenemos
            JPanel pnMensajes = new JPanel();
            pnMensajes.add(etMensajes);

Y tambien JPanel pnBotonProcesar = new JPanel(); que es donde se añaden los botones.

Ahora en el panel derecho se establece un layout con 2 filas, arriba el panel que muestra "Escriba y use botones" y abajo el panel con los propios botones.

            setLayout(new GridLayout(2,1));
            add(etMensajes);
            add(pnBotones);

Pero aquí en lugar de añadir los dos subpaneles (pnMensajes y pnBotones) lo que veo es que se añade el JLabel etMensajes y el panel pnBotones.

¿Por qué no se añaden los dos paneles? Aquí parece que pnMensajes quedara sin uso. ¿Por qué?


Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #11 en: 15 de Enero 2023, 12:30 »

Ahora en el panel derecho se establece un layout con 2 filas, arriba el panel que muestra "Escriba y use botones" y abajo el panel con los propios botones.

            setLayout(new GridLayout(2,1));
            add(etMensajes);
            add(pnBotones);

Pero aquí en lugar de añadir los dos subpaneles (pnMensajes y pnBotones) lo que veo es que se añade el JLabel etMensajes y el panel pnBotones.

¿Por qué no se añaden los dos paneles? Aquí parece que pnMensajes quedara sin uso. ¿Por qué?

Pues ni más ni menos..., que porque me equivoqué  :o

O me equivoqué, o tal vez olvidé eliminar las líneas donde creamos el panel pnMensajes.

Quizás en su momento estuve probando distintas maquetaciones hasta elegir la que más me gustaba.
Si te fijas, si en lugar de añadir directamente la etiqueta al GridLayout, añadimos el panel que contiene la etiqueta..., el texto de la etiqueta aparece en una posición distinta. Sale más elevada respecto a los botones.

Seguramente probé ambas posibilidades y me gustó más como quedaba al añadir directamente la etiqueta, sin envolverla con un panel.
Pero luego olvidé borrar las líneas donde la envolvía con el panel.

Así que tienes razón, el panel pnMensajes no se está usando. Así que puedes elegir eliminarlo, o bien darle uso y agregarlo al GridLayout en lugar de la etiqueta.
Prueba ambas posibilidades y elige la que más te guste.

Bien observado. ;)

Un saludo.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

manuromero73

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 40
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #12 en: 21 de Enero 2023, 21:28 »
Hola, probando alternativamente con

 setLayout(new GridLayout(2,1));
            pnMensajes.setBackground(Color.green); // Para poder ver el elemento gráfico ponemos color verde
            add(pnMensajes);
            add(pnBotones);

y con

 setLayout(new GridLayout(2,1));
            etMensajes.setBackground(Color.green);
            etMensajes.setOpaque(true); //Añadido porque si no no se ve el color
            add(etMensajes); 
            add(pnBotones);

El resultado que obtengo es similar pero como has comentado añadiendo el panel pnMensajes el texto se va arriba, mientras que añadiendo el label el texto aparece centrado (y así se ve mejor).

Lo que comentaba en el mensaje anterior relativo a fijar los tamaños de letra como una proporción de dim.width crees que puede ser una buena solución para evitar malas visualizaciones según el tamaño de pantalla?


Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #13 en: 22 de Enero 2023, 11:54 »
He probado las medidas relativas que has puesto con mi pantalla, que imagino será distinta que la tuya, y funciona perfectamente.

Así que sí parece buena estrategia, al menos para que desde un primer momento no aparezcan texto cortados en pantallas pequeñas ni fuentes demasiado pequeñas en las grandes.

Como dije en otro mensaje, con tanta variedad de pantallas, dispositivos y grados de dioptría, al final lo ideal es crear un menú donde el usuario personalice las fuentes.
Pero bueno, eso es muy trabajoso, los que estamos aprendiendo a programar no vamos a meternos en esos "embolaos" para cada programita que escribamos.
Con usar dimensiones relativas, ya es más que suficiente.

Un saludo.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

manuromero73

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 40
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #14 en: 04 de Marzo 2023, 18:00 »
Hola al ejecutar este código, que creo coincide con el propuesto aproximadamente, no me hace nada, se muestra la ventana y los botones, pero si escribo algo y pulso "Procesar" no veo que haga nada. Si pulso el botón "Borrar" tampoco veo que haga nada, y tampoco aparece ningún error. ¿Alguna idea de por qué no responde? Gracias

Código: [Seleccionar]
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.GridLayout;
import java.awt.Font;
import java.awt.Color;
import java.awt.event.*;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;

public class Main extends JFrame {

    private JTextArea campoTexto;
    private JLabel etMensajes;
    private JButton btProcesar;
    private JButton btBorrar;
    private Dimension dim;

    public Main() {
        dim = Toolkit.getDefaultToolkit().getScreenSize();
        setTitle("Marco Swing");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(new PanelPrincipal());
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private class PanelPrincipal extends JPanel {

        public PanelPrincipal() {
            setPreferredSize(dim);
            int bordeAncho = dim.width * 5 / 100;
            int bordeAlto = dim.height * 5 / 100;
            setBorder(BorderFactory.createEmptyBorder(bordeAlto, bordeAncho, bordeAlto, bordeAncho));

            setLayout(new GridLayout(1,2));
            add(new PanelCampoTexto()); //Panel que va a la izquierda
            add(new PanelDerecho());//Panel que va a la derecha
        }
    }

    private class PanelCampoTexto extends JPanel {

        public PanelCampoTexto() {
            campoTexto = new JTextArea();
            campoTexto.setFont(new Font("Verdana", Font.PLAIN, dim.width * 2 / 100));
            setLayout(new GridLayout(1,1));
            JScrollPane scroll = new JScrollPane(campoTexto);
            add(scroll);
        }
    }

    private class PanelDerecho extends JPanel {

        public PanelDerecho() {

            etMensajes = new JLabel("Escriba y use botones", SwingConstants.CENTER);
            etMensajes.setFont(new Font("Verdana", Font.BOLD, dim.width * 3 / 100));

            //JPanel pnMensajes = new JPanel();
            //pnMensajes.add(etMensajes);

            btProcesar = new JButton("Procesar");
            btProcesar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
            btBorrar = new JButton("Borrar");
            btBorrar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));

            JPanel pnBotonProcesar = new JPanel();
            pnBotonProcesar.add(btProcesar);
            JPanel pnBotonBorrar = new JPanel();
            pnBotonBorrar.add(btBorrar);
            JPanel pnBotones = new JPanel();
            pnBotones.setLayout(new GridLayout(1,2));
            pnBotones.add(pnBotonProcesar);
            pnBotones.add(pnBotonBorrar);

            setLayout(new GridLayout(2,1));
            add(etMensajes);
            add(pnBotones);

        }
    }

    private class AccionProcesar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         etMensajes.setText("Ha pulsado el botón procesar");
      }
   }
   
   private class AccionBorrar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         etMensajes.setText(null);
         campoTexto.setText(null);
      }
   }
   
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Main();
                }
            });
    }
}

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #15 en: 04 de Marzo 2023, 23:18 »
Hola.
Falta un detalle.
Los ActionListener de "procesar" y "borrar" están escritos, pero no están agregados a sus correspondientes botones.
Hay que añadir esta par de líneas:

Citar
    }

    private class PanelDerecho extends JPanel {

        public PanelDerecho() {

            etMensajes = new JLabel("Escriba y use botones", SwingConstants.CENTER);
            etMensajes.setFont(new Font("Verdana", Font.BOLD, dim.width * 3 / 100));

            //JPanel pnMensajes = new JPanel();
            //pnMensajes.add(etMensajes);

            btProcesar = new JButton("Procesar");
            btProcesar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
            btProcesar.addActionListener(new AccionProcesar());
            btBorrar = new JButton("Borrar");
            btBorrar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
            btBorrar.addActionListener(new AccionBorrar());
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

manuromero73

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 40
    • Ver Perfil
Re: java swing ventana gráfica
« Respuesta #16 en: 27 de Marzo 2023, 19:55 »
Hola, he introducido los cambios indicados y he modificado un tamaño de texto que cuando cambiaba salía demasiado grande y le he añadido que cuando se pulse borrar se siga mostrando el mensaje inicial de "Escriba y use botones". Muchas gracias por toda la ayuda.

El código en esta última versión:

Código: [Seleccionar]
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.GridLayout;
import java.awt.Font;
import java.awt.Color;
import java.awt.event.*;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;

public class Main extends JFrame {

    private JTextArea campoTexto;
    private JLabel etMensajes;
    private JButton btProcesar;
    private JButton btBorrar;
    private Dimension dim;

    public Main() {
        dim = Toolkit.getDefaultToolkit().getScreenSize();
        setTitle("Marco Swing");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(new PanelPrincipal());
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private class PanelPrincipal extends JPanel {

        public PanelPrincipal() {
            setPreferredSize(dim);
            int bordeAncho = dim.width * 5 / 100;
            int bordeAlto = dim.height * 5 / 100;
            setBorder(BorderFactory.createEmptyBorder(bordeAlto, bordeAncho, bordeAlto, bordeAncho));

            setLayout(new GridLayout(1,2));
            add(new PanelCampoTexto()); //Panel que va a la izquierda
            add(new PanelDerecho());//Panel que va a la derecha
        }
    }

    private class PanelCampoTexto extends JPanel {

        public PanelCampoTexto() {
            campoTexto = new JTextArea();
            campoTexto.setFont(new Font("Verdana", Font.PLAIN, dim.width * 2 / 100));
            setLayout(new GridLayout(1,1));
            JScrollPane scroll = new JScrollPane(campoTexto);
            add(scroll);
        }
    }

    private class PanelDerecho extends JPanel {

        public PanelDerecho() {

            etMensajes = new JLabel("Escriba y use botones", SwingConstants.CENTER);
            etMensajes.setFont(new Font("Verdana", Font.BOLD, dim.width * 2 / 100));

            //JPanel pnMensajes = new JPanel();
            //pnMensajes.add(etMensajes);

            btProcesar = new JButton("Procesar");
            btProcesar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
            btProcesar.addActionListener(new AccionProcesar());
            btBorrar = new JButton("Borrar");
            btBorrar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
            btBorrar.addActionListener(new AccionBorrar());

            JPanel pnBotonProcesar = new JPanel();
            pnBotonProcesar.add(btProcesar);
            JPanel pnBotonBorrar = new JPanel();
            pnBotonBorrar.add(btBorrar);
            JPanel pnBotones = new JPanel();
            pnBotones.setLayout(new GridLayout(1,2));
            pnBotones.add(pnBotonProcesar);
            pnBotones.add(pnBotonBorrar);

            setLayout(new GridLayout(2,1));
            add(etMensajes);
            add(pnBotones);

        }
    }

    private class AccionProcesar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
   
         etMensajes.setText("Ha pulsado el botón procesar");
      }
   }
   
   private class AccionBorrar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {

         etMensajes.setText("Escriba y use botones");
         campoTexto.setText(null);
      }
   }
   
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Main();
                }
            });
    }
}


 

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".