How to put icon on Joptionpane buttons?

Asked

Viewed 749 times

8

How do I place an icon in the "Continue" and "Cancel" buttons that appear in the JOptionPane?

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:

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

But I don’t know how to do this with the components of JOptionPane.

2 answers

5


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

It is worth remembering that, because it is a fully customized window, you will need to implement System for the buttons as well, according to the option selected by the user.

Already this answer from Soen demonstrates that it is possible to pass an array of buttons with their respective icons to the method 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
 );
  • I think he wants to put icons on buttons, not the little screen icon.

  • @Victorstafusa I suppose is duplicate of this one here, in this case, because he needs to create a custom version of Joptionpane agree? https://answall.com/a/199687/28595

  • So that’s what he said here in the comment. I need to change the Button icon

  • Thank you very much I managed to solve thanks to you.

  • @Viniciussilva which of the forms used? I could not test the example of the answer because I am without IDE at the moment.

  • This last one was only missing the 2 parameters I passed.

  • @Victorstafusa pq erased? Your answer exploring the class rewrite was great. I was even voting for it when I received an error.

  • @Okay, I restored it. I don’t know, I got the impression that I was reinventing the square wheel.

  • The solution worked well to add icons , however these buttons do not close Joptionpane by default. Is there a method that does this so I can call in Jbutton Action? like a . Dispose() ??

  • @Viniciussilva then Oce needs to make the first hint, implement his own dialog screen, comforted explained at the beginning of the answer, or can implement the solution given by Ictor in the other answer.

Show 5 more comments

4

Digging into the inner details of the classes javax.swing.JOptionPane and javax.swing.plaf.basic.BasicOptionPaneUI, I managed to do with it:

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);
    }
}

That is the result:

JOptionPane

This code is complicated, but I’ll explain:

  • The methods imagem1() and imagem2() are responsible for creating the icons. One of them makes the blue icon and the other the red icon.

  • The class JOptionPane delegates to OptionPaneUI the creation of buttons. However OptionPaneUI is an abstract class, and the concrete subclass used is BasicOptionPaneUI.

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

  • Therefore, the solution consists in injecting instances of ButtonFactory within the JOptionPane. As this class is private, I urge it through Reflection.

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

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

  • The method escolherOpcao returns the text of the selected button or null if and user click on ícone x.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.