Change selected dot color of JRadioButtonMenuItem
Asked Answered
C

4

5

I'm working on my personal Java chat client whose one feature is setting user's status (Available, Invisible, Busy). To make it user-friendly, I put those statuses into a JMenu with JRadioButtonMenuItem.

The problem is I want each status RadioButton to have its own radio-dot color (or dot-icon). For example:

  • [Green-Dot] Available
  • [Red-Dot] Busy
  • [Gray-Dot] Invisible.

I thought of extending the JRadioButtonMenuItem with three different custom RadioButtonMenuItem, but couldn't understand how JRadioButtonMenuItem is painted.

Could anyone help me to solve this problem?

Edit 1
Thanks for your suggestions to use Icon together with setIcon() and setSelectedIcon() methods.
However since my question is about changing the radio-dot, could you also help me to hide the radio-dot from a RadioButton?

Edit 2
Here's the current screenshot of my app.
MyIM menubar screenshot
As you can see the dot before that RadioButtonMenuItem is somehow ridiculously nonsense. That's why I want to get rid of the dot, or change it to my custom icon :)

Curvaceous answered 19/8, 2012 at 7:4 Comment(1)
See also How can I customize the render of JRadioButton?Puttergill
P
5

The radio button's dot is rendered by the UI delegate for each Look & Feel. You can supply your own BasicRadioButtonUI, but the effort is not trivial. As an alternative, implement the Icon interface, as shown here in ColorIcon.

Puttergill answered 19/8, 2012 at 7:9 Comment(4)
I think what you meant is set the icon of RadioButtonMenuItem to some custom icon? I think this will set the icon next to the text of that RadioButton, not the dot itself.Curvaceous
Exactly, as shown here; I also wanted to emphasize how easy it is to implement the interface.Puttergill
Please refer to my updated screenshot. To me having the black-dot is really annoying :PCurvaceous
I'd make it a single JMenuItem; change both the icon and text when the corresponding state changes.Puttergill
G
3

I suggest you use the Icon property of Swing Components. Here is example which sets an icon to the JRadioButtonMenuItem. Whenever there is a change in status use seticon method to change the icon. Instead of colors use icons

Here's an Example http://www.java2s.com/Code/Java/Swing-JFC/Anexampleofradiobuttonmenuitemsinaction.htm

Gallstone answered 19/8, 2012 at 7:27 Comment(4)
Thank you :) Could you refer to my updated screenshot? The black-dot before RadioButton really bothers me somehow :)Curvaceous
try using JMenuItem instead of JRadioButtonMenuItem docs.oracle.com/javase/1.4.2/docs/api/javax/swing/…, javax.swing.Icon)Gallstone
+1 I don't know an easier way than switching to JMenuItem, but you lose the visual feedback.Puttergill
@LuanNguyen With regular JCheckBoxes and JRadioButtons, setting the icon/selected icon is the method for actually changing the check box/button. Not sure why it doesn't work for menu items, I guess they did not add that functionality. As Sunny/trashgod have suggested I think you will have to switch to regular JMenuItem. I think you should be able to subclass it and keep track of a selected state yourself, setting icons appropriately. Also as a side note, along with setIcon/setSelectedIcon there are also setDisabledIcon/setDisabledSelectedIcon if you are disabling them ever.Embowed
S
1

My thought was, the behavior of the JRadioButtonMenuItem is fine, it's just its painting is a little goofy. But I don't want to have to extend it or override paint or any of those shenanigans. So I concluded, just steal its behavior and leave its painting behind.

You'll notice that ButtonGroup accepts AbstractButtons, so I like dungeon Hunter's solution: use regular JMenuItems. I'd append to that, steal the JToggleButton's ButtonModel and send in an ItemListener that will do the image swapping (as Ramesh John suggested).

import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JToggleButton;

public class TestRadioCustomIcon {

    public static void main(String[] args){
        new TestRadioCustomIcon().go();
    }

    private void go(){
        JFrame frame = new JFrame("Foo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JMenuBar jmb = new JMenuBar();
        JMenu menu = new JMenu("Menu");

        JMenuItem i1 = makeFauxRadioMenuItem("Item 1");
        JMenuItem i2= makeFauxRadioMenuItem("Item 2");
        JMenuItem i3= makeFauxRadioMenuItem("Item 3");
        i1.setSelected(true);

        ButtonGroup bg = new ButtonGroup();
        bg.add(i1);
        bg.add(i2);
        bg.add(i3);

        menu.add(i1);
        menu.add(i2);
        menu.add(i3);
        jmb.add(menu);
        frame.add(jmb);
        frame.pack();
        frame.setVisible(true);
    }

    private ImageIcon selected = loadImage("C:\\path\\to\\image1.bmp");
    private ImageIcon deselected = loadImage("C:\\path\\to\\image2.bmp");
    private ItemListener il = new ItemListener(){
        @Override
        public void itemStateChanged(ItemEvent e){
            AbstractButton ab = (AbstractButton) e.getSource();
            switch(e.getStateChange()){
                case ItemEvent.SELECTED:
                    ab.setIcon(selected);
                    break;
                case ItemEvent.DESELECTED:
                    ab.setIcon(deselected);
                    break;
            }
        }
    }

    private ImageIcon loadImage(String filePath){
        try{
            BufferedImage bi = ImageIO.read(new File(filePath));
            return new ImageIcon(bi);
        } catch (IOException e){
            //sad day
            return null;
        }
    }

    private JMenuItem makeFauxRadioMenuItem(String label){
        JMenuItem item = new JMenuItem(label);
        //Make it think it's a RadioButton
        item.setModel(new JToggleButton.ToggleButtonModel());
        //When selection changes occur, swap icons
        item.addItemListener(il);
        //Assume deselected
        item.setIcon(deselected);
        return item;
    }
}

And this'll work for any old icon, not just changing the button's color.

Schriever answered 26/2, 2014 at 18:31 Comment(0)
E
0

Add a new class to customize the RadioButtonMenuItem by extending JRadioButtonMenuItem.

Add inner class to update status Icon by implementing Icon inteface. Override all the methods update the paintIcon() method with current status icon.

Call super class by passing status icon.

super(theMenuText, new StatusIcon(theStudyIcon, getUserStatus(UserId)));

Add listner to get the latest event to update the Icon using setIcon() method.

Erde answered 29/10, 2013 at 13:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.