How to put icon in JOptionPane buttons?

8

How do I put an icon in the "Continue" and "Cancel" Buttons that appear in the JOptionPane ?? window

The case is represented below:

 public void metodo(){    
    JPanel panel = new JPanel();
                    JLabel label = new JLabel("qualquer texto");
                    JPasswordField pass = new JPasswordField(20);
                    panel.add(label);
                    panel.add(new JLabel(" "));
                    panel.add(pass);
                    String[] options = new String[]{"Continuar", "Cancelar"};
                    int option = JOptionPane.showOptionDialog(null, panel, "Aviso",
                            JOptionPane.NO_OPTION, JOptionPane.WARNING_MESSAGE,
                            null, options, options[1]);
    }

If it was an ordinary button it was very simple just to do it like this:

JButon.setIcon(new javax.swing.ImageIcon(getClass().getResource("/img/logo-mini.png"))); // 

But I do not know how to do this with the components of JOptionPane .

    
asked by anonymous 19.04.2018 / 20:35

2 answers

5

You can create a custom version of a modal window (use the JDialog is a viable option for this). In this other answer there is an example of a custom modal window, just create a similar one, add your custom buttons as you wish. In the documentation there are also some examples and other guidelines.

Note that because it is a fully customized window, you will need to implement a listener for the buttons as well, depending on the option selected by the user.

Already this SOEn response demonstrates that it is possible to pass an array of buttons with your respective icons for the showOptionDialog() ":

JOptionPane.showOptionDialog( parent, question, title,
   JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,null,
   new Component[]{ new JButton("OK", myIcon), 
                    new JButton("cancel", myOtherIcon) 
                  },null
 );
    
19.04.2018 / 20:43
4

Fighting in the inner details of classes javax.swing.JOptionPane and javax.swing.plaf.basic.BasicOptionPaneUI , I managed to do this:

import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.IntFunction;
import java.util.stream.Stream;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JOptionPane;

/**
 * @author Victor Stafusa
 */
public class TesteJOptionPane {
    private static final Constructor<?> BUTTON_CONSTRUCTOR;
    private static final IntFunction<Object[]> BUTTON_ARRAY_CONSTRUCTOR;

    static {
        Class<?> buttonClass;
        try {
            buttonClass = Class.forName("javax.swing.plaf.basic.BasicOptionPaneUI$ButtonFactory");
            BUTTON_CONSTRUCTOR = buttonClass.getDeclaredConstructor(String.class, int.class, Icon.class, int.class);
            BUTTON_CONSTRUCTOR.setAccessible(true);
        } catch (ClassNotFoundException x) {
            throw new NoClassDefFoundError(x.getMessage());
        } catch (NoSuchMethodException x) {
            throw new AssertionError(x);
        }
        BUTTON_ARRAY_CONSTRUCTOR = n -> (Object[]) Array.newInstance(buttonClass, n);
    }

    private static Icon imagem1() {
        BufferedImage image = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
        for (int i = 0; i < 50; i++) {
            for (int j = 0; j < 50; j++) {
                image.setRGB(i, j, 0xFF336699);
            }
        }
        return new ImageIcon(image);
    }

    private static Icon imagem2() {
        BufferedImage image = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
        for (int i = 0; i < 50; i++) {
            for (int j = 0; j < 50; j++) {
                image.setRGB(i, j, 0xFF993366);
            }
        }
        return new ImageIcon(image);
    }

    public static void main(String[] args) throws InterruptedException, InvocationTargetException {
        AtomicReference<String> x = new AtomicReference<>();
        EventQueue.invokeAndWait(() -> {
            String resposta = escolherOpcao(
                    "Mensagem de texto",
                    "Aviso",
                    "Cancelar",
                    new Opcao("Continuar", imagem1()),
                    new Opcao("Cancelar", imagem2()));
            x.set(resposta);
        });
        System.out.println(x.get());
    }

    public static final class Opcao {
        private final String texto;
        private final Icon imagem;
        private final Object buttonFactory;

        public Opcao(String texto, Icon imagem) {
            this.texto = texto;
            this.imagem = imagem;
            try {
                this.buttonFactory = BUTTON_CONSTRUCTOR.newInstance(texto, 0, imagem, -1);
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException x) {
                throw new AssertionError(x);
            }
        }

        public String getTexto() {
            return texto;
        }

        public Icon getImagem() {
            return imagem;
        }

        public Object getButton() {
            return buttonFactory;
        }
    }

    public static String escolherOpcao(String message, String title, String defaultOption, Opcao... options) {
        String[] nomes = Stream.of(options).map(Opcao::getTexto).toArray(String[]::new);
        JOptionPane pane = new JOptionPane(
                message,
                JOptionPane.WARNING_MESSAGE,
                JOptionPane.NO_OPTION,
                null,
                nomes,
                defaultOption);
        pane.setOptions(Stream.of(options).map(Opcao::getButton).toArray(BUTTON_ARRAY_CONSTRUCTOR));
        JDialog dialog = pane.createDialog(null, title);
        dialog.show();
        Object selectedValue = pane.getValue();
        dialog.dispose();
        return Stream.of(options).filter(o -> o.getButton() == selectedValue).findFirst().map(Opcao::getTexto).orElse(null);
    }
}

Here's the result:

Thiscodeiscomplicated,butI'llexplain:

  • Theimagem1()andimagem2()methodsareresponsibleforcreatingtheicons.Oneofthemmakestheblueiconandtheothertheredicon.

  • TheclassJOptionPanedelegatestoOptionPaneUIthecreationofthebuttons.HoweverOptionPaneUIisanabstractclass,andtheconcretesubclassusedisBasicOptionPaneUI.

  • The BasicOptionPaneUI class calls the getOptions() method of JOptionPane to decide whether to create the buttons. The buttons are created using the inner private class ButtonFactory , which accepts icons.

  • So the solution is to inject instances of ButtonFactory into JOptionPane . Since this class is private, I instantiate it by means of reflection.

  • The class Opcao corresponds to the buttons that will be passed. Each one with a name and an icon.

  • The escolherOpcao(String, String, String, Opcao...) method is used to display the message box. The parameters are: window message, title, default option and the buttons of the chosen options.

  • The escolherOpcao method returns the text of the selected button or null if user clicks the .

19.04.2018 / 21:55