Como incluir efeitos em texto como sombreamento e outline em um JLabel?

Minha dúvida surgiu porquê tenho criado interfaces SWING com fundos mais coloridos e atraentes, aplicando texturas e/ou efeitos como gradiente - como fundo do JFrame.

O problema agora está sendo justamente deixar os componentes da tela - principalmente os JLabels da vida - mais visíveis e contrastando melhor com as cores do fundo. Atualmente, mesmo com diversos esforços, tenho tidos resultados frustrantes: Percebi que nem sempre adianta mudar a cor do texto do JLabel, porquê em fundos de tela com muitas variações de cor, o texto aparece em certas partes e em outras se confunde com o fundo da tela.

Ao ver programas como o Firefox, que utilizam temas como fundo do navegador, percebi que quando se aplicam fundos com cores mais fortes e escuras, não somente os labels ficam claros (para contrastar com a cor escura do fundo) como têm efeitos de sombreamento, outline, etc - com o intuito claro de contrastar mais ainda com o fundo e evitar problemas como a variação de cores ao longo da imagem de fundo. Funciona! Eles ficam bem visíveis e nitídos.

Minha dúvida é no sentido de saber se é possível aplicar efeitos de texto mais elaborados em um Jlabel e em outros componentes também… O java.awt.Font permite essas capacidades? Que saída vocês buscam nesses casos?

Diego, acho que o mais sofisticado que vc irá conseguir é usando um pouco de HTML no seu JLabel (veja mais em: http://java.sun.com/docs/books/tutorial/uiswing/components/html.html ) para dar algum efeito, mas níveis de sombreamento e texturas?Se suas apps chegaram a tal nível de detalhamento, recomendo usar um editor de imagens da vida(Photoshop,Corel Draw…) e construir seus rótulos lá e usar dentro dos JLabels.Um amigo fazia isso.(IMHO: acho um “pain in the ass” principalmente por eu não ter nenhuma habilidade para design gráfico…) :wink:

IronLynx, percebi mesmo que a tarefa não é nada fácil…

Mas buscando, pelo menos, uma medida paliativa - que seria o texto com sombreamento - encontrei algo legal no Fórum da Sun e fiz umas adaptações.

Pelo menos o sombreamento eu consegui e com isso, resolvi a maioria dos meus problemas com contraste entre os Jlabels e a textura.

Fiz as adaptações para JLabel, JRadioButton e JCheckBox. Os campos de offset determinam o distanciamento da sombra.

Quem quiser, sinta-se a vontade para fuçar e fazer melhorias.

Estou postando o código aqui para consultas. Têm alguns screenshots de testes que fiz no final

JLabel com sombreamento
O JLabel abaixo é para ser usado especificamente para texto sombreado.

import java.awt.*;
import java.awt.font.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;

public class JLabelShadow extends JLabel {

    private Color shadowColor;

    private final void setInitialBackgroundColor() {
        setShadowColor(Color.BLACK);
    }

    public JLabelShadow() {
        setInitialBackgroundColor();

    }

    public JLabelShadow(Icon image) {
        super(image);
        setInitialBackgroundColor();


    }

    public JLabelShadow(Icon image, int horizontalAlignment, Font fonte) {
        super(image, horizontalAlignment);
        setInitialBackgroundColor();

    }

    public JLabelShadow(String text, Font fonte) {
        super(text);
        setInitialBackgroundColor();

    }

    public JLabelShadow(String text, int horizontalAlignment, Font fonte) {
        super(text, horizontalAlignment);
        setInitialBackgroundColor();

    }

    public JLabelShadow(String text, Icon icon, int horizontalAlignment, Font fonte) {
        super(text, icon, horizontalAlignment);
        setInitialBackgroundColor();

    }

    public Color getShadowColor() {
        return shadowColor;
    }

    public void setShadowColor(Color shadowColor) {
        this.shadowColor = shadowColor;
    }

    @Override
    protected void paintComponent(Graphics g) {

        final Graphics2D graphics = (Graphics2D) g;


// Remember current graphics parameters
        final Object oldTextAntialiasingHint = graphics.getRenderingHint(
                RenderingHints.KEY_TEXT_ANTIALIASING);
        final Color oldForeground = getForeground();

// Set rendering quality
        graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        {// Paint the shadow
            final Graphics2D shadowGraphics = (Graphics2D) graphics.create();

            shadowGraphics.translate(getShadowOFFSET_X(), getShadowOFFSET_Y());
            shadowGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                    0.7f));
            setForeground(this.getShadowColor());

            super.paintComponent(shadowGraphics);

            shadowGraphics.dispose();
        }

// Paint the text
        setForeground(oldForeground);
        super.paintComponent(graphics);


// Restore rendering quality
        if (null != oldTextAntialiasingHint) {
            graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                    oldTextAntialiasingHint);
        } else {
// do nothing
        }
    }

    private int shadowOFFSET_X = 1;
    private int shadowOFFSET_Y = 2;

    public int getShadowOFFSET_X() {
        return shadowOFFSET_X;
    }

    public void setShadowOFFSET_X(int shadowOFFSET_X) {
        this.shadowOFFSET_X = shadowOFFSET_X;
    }

    public int getShadowOFFSET_Y() {
        return shadowOFFSET_Y;
    }

    public void setShadowOFFSET_Y(int shadowOFFSET_Y) {
        this.shadowOFFSET_Y = shadowOFFSET_Y;
    }
}

JRadioButton com sombreamento

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.Action;
import javax.swing.Icon;


public class JRadioButtonShadow extends javax.swing.JRadioButton {

    private Color shadowColor;

    public JRadioButtonShadow(String text, Icon icon, Color shadowColor) {
        super(text, icon);
        this.shadowColor = shadowColor;
    }

    public JRadioButtonShadow(String text, boolean selected, Color shadowColor) {
        super(text, selected);
        this.shadowColor = shadowColor;
    }

    public JRadioButtonShadow(String text, Color shadowColor) {
        super(text);
        this.shadowColor = shadowColor;
    }

    public JRadioButtonShadow(Color shadowColor) {
        this.shadowColor = shadowColor;
    }

    public JRadioButtonShadow(String text, Icon icon, boolean selected) {
        super(text, icon, selected);
        setInitialBackgroundColor();
    }

    public JRadioButtonShadow(String text, Icon icon) {
        super(text, icon);
        setInitialBackgroundColor();
    }

    public JRadioButtonShadow(String text, boolean selected) {
        super(text, selected);
        setInitialBackgroundColor();
    }

    public JRadioButtonShadow(String text) {
        super(text);
        setInitialBackgroundColor();
    }

    public JRadioButtonShadow(Icon icon, boolean selected) {
        super(icon, selected);
        setInitialBackgroundColor();
    }

    public JRadioButtonShadow(Action a) {
        super(a);
        setInitialBackgroundColor();
    }

    public JRadioButtonShadow(Icon icon) {
        super(icon);
        setInitialBackgroundColor();
    }

    public JRadioButtonShadow() {
        setInitialBackgroundColor();
    }

    

    private final void setInitialBackgroundColor() {
        setShadowColor(Color.BLACK);
    }

    public Color getShadowColor() {
        return shadowColor;
    }

    public void setShadowColor(Color shadowColor) {
        this.shadowColor = shadowColor;
    }

    @Override
    protected void paintComponent(Graphics g) {

        final Graphics2D graphics = (Graphics2D) g;


// Remember current graphics parameters
        final Object oldTextAntialiasingHint = graphics.getRenderingHint(
                RenderingHints.KEY_TEXT_ANTIALIASING);
        final Color oldForeground = getForeground();

// Set rendering quality
        graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        {// Paint the shadow
            final Graphics2D shadowGraphics = (Graphics2D) graphics.create();

            shadowGraphics.translate(getShadowOFFSET_X(), getShadowOFFSET_Y());
            shadowGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                    0.7f));
            setForeground(this.getShadowColor());

            super.paintComponent(shadowGraphics);

            shadowGraphics.dispose();
        }

// Paint the text
        setForeground(oldForeground);
        super.paintComponent(graphics);


// Restore rendering quality
        if (null != oldTextAntialiasingHint) {
            graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                    oldTextAntialiasingHint);
        } else {
// do nothing
        }
    }
    private int shadowOFFSET_X = 1;
    private int shadowOFFSET_Y = 2;

    public int getShadowOFFSET_X() {
        return shadowOFFSET_X;
    }

    public void setShadowOFFSET_X(int shadowOFFSET_X) {
        this.shadowOFFSET_X = shadowOFFSET_X;
    }

    public int getShadowOFFSET_Y() {
        return shadowOFFSET_Y;
    }

    public void setShadowOFFSET_Y(int shadowOFFSET_Y) {
        this.shadowOFFSET_Y = shadowOFFSET_Y;
    }

    

}

JCheckBox com sombreamento

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.Icon;


public class JCheckBoxShadow extends javax.swing.JCheckBox {

    private Color shadowColor;

     public JCheckBoxShadow(String text) {
        super(text);
        setInitialBackgroundColor();
    }

    public JCheckBoxShadow(Icon icon) {
        super(icon);
        setInitialBackgroundColor();
    }

    public JCheckBoxShadow() {
        setInitialBackgroundColor();
    }

    private final void setInitialBackgroundColor() {
        setShadowColor(Color.BLACK);
    }

    public Color getShadowColor() {
        return shadowColor;
    }

    public void setShadowColor(Color shadowColor) {
        this.shadowColor = shadowColor;
    }

    @Override
    protected void paintComponent(Graphics g) {

        final Graphics2D graphics = (Graphics2D) g;


// Remember current graphics parameters
        final Object oldTextAntialiasingHint = graphics.getRenderingHint(
                RenderingHints.KEY_TEXT_ANTIALIASING);
        final Color oldForeground = getForeground();

// Set rendering quality
        graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        {// Paint the shadow
            final Graphics2D shadowGraphics = (Graphics2D) graphics.create();

            shadowGraphics.translate(getShadowOFFSET_X(), getShadowOFFSET_Y());
            shadowGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                    0.7f));
            setForeground(this.getShadowColor());

            super.paintComponent(shadowGraphics);

            shadowGraphics.dispose();
        }

// Paint the text
        setForeground(oldForeground);
        super.paintComponent(graphics);


// Restore rendering quality
        if (null != oldTextAntialiasingHint) {
            graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                    oldTextAntialiasingHint);
        } else {
// do nothing
        }
    }

    private int shadowOFFSET_X = 1;
    private int shadowOFFSET_Y = 2;

    public int getShadowOFFSET_X() {
        return shadowOFFSET_X;
    }

    public void setShadowOFFSET_X(int shadowOFFSET_X) {
        this.shadowOFFSET_X = shadowOFFSET_X;
    }

    public int getShadowOFFSET_Y() {
        return shadowOFFSET_Y;
    }

    public void setShadowOFFSET_Y(int shadowOFFSET_Y) {
        this.shadowOFFSET_Y = shadowOFFSET_Y;
    }


}