Un problema que he observado al utilizar el look & feel 'Nimbus' de Java 6 es que las JTextArea mantenien el color de fondo blanco a pesar de que se ha invocado el método setOpaque(false).
Por lo que he leído, el problema se debe al diseño original de Swing. El metodo setOpaque() tiene el efecto de que el componente pueda no pintar alguno o todos sus pixeles, y en clases que extiendan a JComponent esto depende del look & feel.
En el caso de Nimbus, este look and feel requiere transparencia en los componentes para dibujar los bordes redondeados, por lo que los pixeles del componente deben ser pintados.
La solucion es utilizar un color de fondo transparente (alfa=0) y tambien un borde transparente a fin de que el efecto final sea un componente 100% transparente:
textArea.setBorder(BorderFactory.createEmptyBorder());
textArea.setBackground(new Color(0, 0, 0, 0));
Con esta simple operación, el componente será completamente transparente, no sólo omitiendo el dibujado de pixeles, sino haciendo que los pixeles que se dibujan sean realmente transparentes.
Asuntos de java, motos, musica, informática... y cualquier otra cosa que se me venga a la mente.
Acerca de mí
Mostrando las entradas con la etiqueta swing. Mostrar todas las entradas
Mostrando las entradas con la etiqueta swing. Mostrar todas las entradas
02 febrero, 2012
13 agosto, 2009
Control de Look and Feel en Swing
Un problema recurrente de los usuarios de aplicaciones
creadas en Java es el del look an feel. "No se ve como
si fuera windows" es el tipico comentario de quien usa
una aplicacion Swing en este sistema operativo. Los
usuarios de *nix estan mas acostumbrados a las diferencias
de l&f segun el toolkit de la aplicacion (gtk+, qt, motif.. etc)
y no suelen quejarse tanto.
Personalmente encuentro horrible el l&f por defecto (metal)
asi que tengo a mano un codigo que selecciona automaticamente
el l&f dependiendo del sistema:
----------
String jVersion = System.getProperty("java.version");
String os = System.getProperty("os.name");
String[] ver = jVersion.split("_");
if (ver.length > 0) {
String vMajor = ver[0];
Double update = Double.parseDouble(ver[1]);
try {
if ((vMajor.compareTo("1.6.0") > -1 && update >= 10) || (vMajor.compareTo("1.7.0") > -1)) {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} else {
if (os.toLowerCase().contains("windows")) {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} else if (os.toLowerCase().contains("linux")) {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
}
} catch (ClassNotFoundException ex) {
Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);
} catch (InstantiationException ex) {
Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);
} catch (UnsupportedLookAndFeelException ex) {
Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);
}
}
----------
El codigo en si es bastante simple:
- Obtengo la version de la VM de java.
- Obtengo el nombre del sistema operativo.
- Obtengo el numero de actualizacion de la VM.
Desde el update 10 de la JVM 1.6 se encuentra disponible
el l&f "Nimbus", asi que si nuestra version de JVM es
1.6_10 o superior se selecciona este L&F para la
aplicacion. En caso contrario si el sistema es Windows
se selecciona el L&F de Windows, si el OS es Linux
se selecciona el L&F GTK (como quisiera un l&f QT!!!).
Si no es posible seleccionar alguno de estos L&F se
mantendra el por defecto (metal).
Bastara con que este codigo se inserte en el main() de
nuestra aplicacion Swing, antes que se dibuje el primer
JFrame y lo demas sera coser y cantar.
Esta solucion es muy simple y utiliza las bibliotecas
estandar de la JVM. No obstante podemos extender
las capacidades de L&F de nuestra aplicacion utilizando
la completisima biblioteca substance.
bytes!!
creadas en Java es el del look an feel. "No se ve como
si fuera windows" es el tipico comentario de quien usa
una aplicacion Swing en este sistema operativo. Los
usuarios de *nix estan mas acostumbrados a las diferencias
de l&f segun el toolkit de la aplicacion (gtk+, qt, motif.. etc)
y no suelen quejarse tanto.
Personalmente encuentro horrible el l&f por defecto (metal)
asi que tengo a mano un codigo que selecciona automaticamente
el l&f dependiendo del sistema:
----------
String jVersion = System.getProperty("java.version");
String os = System.getProperty("os.name");
String[] ver = jVersion.split("_");
if (ver.length > 0) {
String vMajor = ver[0];
Double update = Double.parseDouble(ver[1]);
try {
if ((vMajor.compareTo("1.6.0") > -1 && update >= 10) || (vMajor.compareTo("1.7.0") > -1)) {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} else {
if (os.toLowerCase().contains("windows")) {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} else if (os.toLowerCase().contains("linux")) {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
}
} catch (ClassNotFoundException ex) {
Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);
} catch (InstantiationException ex) {
Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);
} catch (UnsupportedLookAndFeelException ex) {
Logger.getLogger(Main.class.getName()).log(Level.WARNING, bundle.getString("error.lf"), ex);
}
}
----------
El codigo en si es bastante simple:
- Obtengo la version de la VM de java.
- Obtengo el nombre del sistema operativo.
- Obtengo el numero de actualizacion de la VM.
Desde el update 10 de la JVM 1.6 se encuentra disponible
el l&f "Nimbus", asi que si nuestra version de JVM es
1.6_10 o superior se selecciona este L&F para la
aplicacion. En caso contrario si el sistema es Windows
se selecciona el L&F de Windows, si el OS es Linux
se selecciona el L&F GTK (como quisiera un l&f QT!!!).
Si no es posible seleccionar alguno de estos L&F se
mantendra el por defecto (metal).
Bastara con que este codigo se inserte en el main() de
nuestra aplicacion Swing, antes que se dibuje el primer
JFrame y lo demas sera coser y cantar.
Esta solucion es muy simple y utiliza las bibliotecas
estandar de la JVM. No obstante podemos extender
las capacidades de L&F de nuestra aplicacion utilizando
la completisima biblioteca substance.
bytes!!
12 agosto, 2009
Moviendo un JScrollPane de forma automatica
Uno de los problemas clasicos al tener un JPanel dentro
de un JScrollPane es como mover automaticamente la
barra de Scroll del JScrollPane. Para ello existe el metodo
scrollRectToVisible(Rectangle r) que hara que el o los
ScrollBar se desplazen para hacer que el rectangulo indicado
sea visible.
Hasta aqui la cosa no es muy complicada, pero ¿que ocurre
si dentro de nuestro JPanel tenemos uno o mas JPanel
anidados? La cosa tiende a complicarse un poco ya
que la posicion final de nuestro componente es desconocida
para el JScrollPane.
Consideremos el siguiente ejemplo:
--------------------
JScrollPane scrPane = new JScrollPane();
JPanel panelPrincipal = new JPanel();
JPanel panelAnidado1 = new JPanel();
JPanel panelAnidado2 = new JPanel();
JLabel label = new JLabel("....");
JTextField txt = new JTextField("......")M
panelAnidado2.add(txt);
panelAnidado2.add(label)
panelAnidado1.add(panelAnidado2);
panelPrincipal.add(panelAnidado1)
scrPane.setViewportView(panelPrincipal);
----------------------
Si queremos desplazar el JScrollPane hasta la posicion del
label o el txt, la primera idea que se nos viene a la cabeza
seria:
-------
scrPane.scrollRectToVisible(label.getBounds());
-------
Lamentablemente esto no funcionara ya que scrPane solo
"sabe de la existencia" de panelPrincipal e ignora su contenido.
Por lo tanto lo que debemos hacer es calcular la posicion
relativa de label con respecto a panelPrincipal.
Para ello, el siguiente codigo de ejemplo puede ser util;
-------------
//obtengo el padre del label (panelAnidado2)
JPanel padre = (JPanel) label.getParent();
//Obtengo la posicion del padre
Point posPadre = padre.getLocation();
//Obtengo el 'padre del padre' (panelAnidado1) y su posicion
JPanel padre2 = (JPanel)
Point posPadre2 = padre2.getLocation();
//Conociendo las posiciones, puedo hacer el calculo
Double y = posPadre2.getY() + posPadre1.getY() + label.getLocation.getY();
/*
* la variable y contiene la distancia desde el borde del
* panelAnidado1 hasta el borde del label
*/
//Creo un punto en la posicon relativa del Label
Point relativo = new Point(new Double(posPadre2.getX()).intValue(), y.intValue());
//Con este punto relativo puedo crear un rectangulo y desplazar el JScrollPane
Rectangle moverA = new Rectangle(relativo, label.getPreferredSize());
scrPane.scrollRectToVisible(moverA);
---------------
Resumen:
Como 'panelPrincipal' desconoce la presencia y posicon
de label, calculamos la posicion relativa de label con
respecto a 'panelPrincipal' en base a la posicion de su padre
y cualquier panel previo. Una vez conocida esta posicion
relativa, basta desplazar el scrPane hasta un rectangulo
ubicado en esta posicion relativa con el tamaño del
componente que queremos enfocar.
Agregando este codigo a un FocusListener, es facil
hacer que el JScrollPane se desplace hasta la posicion
del componente que obtiene el foco:
Ejemplo:
--------------
private JScrollPane scroll;
private Jpanel panel;
private FocusListener focoDesplazamiento = new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
Point posicionScroll = scroll.getLocation();
Container parent = e.getComponent().getParent();
int y = posicionOpcional.y + parent.getLocation().y;
Point moverA = new Point(posicionScroll.x, y + parent.getHeight());
panel.scrollRectToVisible(new Rectangle(moverA, parent.getPreferredSize()));
}
};
....
{
/*
* En alguna parte del codigo, hacemos que el JPanel panel este contenido
* dentro del JScrollPane scroll
*
*/
panel = new JPanel();
scroll = new JScrollPane(panel);
/*
* Luego, a todos los componentes que se agregan a panel se les agrega
* nuestro FocusListener
*/
JTextField txt1 = new JTextField();
txt1.addFocusListener(focoDesplazamiento);
panel.add(txt1);
...
//y asi sucesivamente.
}
--------------
bytes!
de un JScrollPane es como mover automaticamente la
barra de Scroll del JScrollPane. Para ello existe el metodo
scrollRectToVisible(Rectangle r) que hara que el o los
ScrollBar se desplazen para hacer que el rectangulo indicado
sea visible.
Hasta aqui la cosa no es muy complicada, pero ¿que ocurre
si dentro de nuestro JPanel tenemos uno o mas JPanel
anidados? La cosa tiende a complicarse un poco ya
que la posicion final de nuestro componente es desconocida
para el JScrollPane.
Consideremos el siguiente ejemplo:
--------------------
JScrollPane scrPane = new JScrollPane();
JPanel panelPrincipal = new JPanel();
JPanel panelAnidado1 = new JPanel();
JPanel panelAnidado2 = new JPanel();
JLabel label = new JLabel("....");
JTextField txt = new JTextField("......")M
panelAnidado2.add(txt);
panelAnidado2.add(label)
panelAnidado1.add(panelAnidado2);
panelPrincipal.add(panelAnidado1)
scrPane.setViewportView(panelPrincipal);
----------------------
Si queremos desplazar el JScrollPane hasta la posicion del
label o el txt, la primera idea que se nos viene a la cabeza
seria:
-------
scrPane.scrollRectToVisible(label.getBounds());
-------
Lamentablemente esto no funcionara ya que scrPane solo
"sabe de la existencia" de panelPrincipal e ignora su contenido.
Por lo tanto lo que debemos hacer es calcular la posicion
relativa de label con respecto a panelPrincipal.
Para ello, el siguiente codigo de ejemplo puede ser util;
-------------
//obtengo el padre del label (panelAnidado2)
JPanel padre = (JPanel) label.getParent();
//Obtengo la posicion del padre
Point posPadre = padre.getLocation();
//Obtengo el 'padre del padre' (panelAnidado1) y su posicion
JPanel padre2 = (JPanel)
Point posPadre2 = padre2.getLocation();
//Conociendo las posiciones, puedo hacer el calculo
Double y = posPadre2.getY() + posPadre1.getY() + label.getLocation.getY();
/*
* la variable y contiene la distancia desde el borde del
* panelAnidado1 hasta el borde del label
*/
//Creo un punto en la posicon relativa del Label
Point relativo = new Point(new Double(posPadre2.getX()).intValue(), y.intValue());
//Con este punto relativo puedo crear un rectangulo y desplazar el JScrollPane
Rectangle moverA = new Rectangle(relativo, label.getPreferredSize());
scrPane.scrollRectToVisible(moverA);
---------------
Resumen:
Como 'panelPrincipal' desconoce la presencia y posicon
de label, calculamos la posicion relativa de label con
respecto a 'panelPrincipal' en base a la posicion de su padre
y cualquier panel previo. Una vez conocida esta posicion
relativa, basta desplazar el scrPane hasta un rectangulo
ubicado en esta posicion relativa con el tamaño del
componente que queremos enfocar.
Agregando este codigo a un FocusListener, es facil
hacer que el JScrollPane se desplace hasta la posicion
del componente que obtiene el foco:
Ejemplo:
--------------
private JScrollPane scroll;
private Jpanel panel;
private FocusListener focoDesplazamiento = new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
Point posicionScroll = scroll.getLocation();
Container parent = e.getComponent().getParent();
int y = posicionOpcional.y + parent.getLocation().y;
Point moverA = new Point(posicionScroll.x, y + parent.getHeight());
panel.scrollRectToVisible(new Rectangle(moverA, parent.getPreferredSize()));
}
};
....
{
/*
* En alguna parte del codigo, hacemos que el JPanel panel este contenido
* dentro del JScrollPane scroll
*
*/
panel = new JPanel();
scroll = new JScrollPane(panel);
/*
* Luego, a todos los componentes que se agregan a panel se les agrega
* nuestro FocusListener
*/
JTextField txt1 = new JTextField();
txt1.addFocusListener(focoDesplazamiento);
panel.add(txt1);
...
//y asi sucesivamente.
}
--------------
bytes!
Suscribirse a:
Entradas (Atom)