Swing: Resizing RadioButton
Asked Answered
H

3

1

I need to implement font size switching in my app. But when I increase font's size RadioButtons remain same size and on small screen with high resolution my customer just can't hit it easily. Is there a way to resize RadioButton's round thing programmatically without diging into L&F and redrawing Icons manually (it's complicated since app targets multiple platforms with different UIs and each of them must have 7 icons).

Perfect solution could look like this:

  1. Extraction of native UI icon.
  2. Resizing it
  3. Setting resized icon as component's icon.

How to implement step 1? Is it possible?

EDIT: this is what i tried so far

public class IconImageSaver extends JFrame{

    public IconImageSaver() {

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setBounds(0,0,100,100);
        setVisible(true);

        JRadioButton rad1 = new JRadioButton();
        rad1.setBounds(10,10,40,40);
        add(rad1);

        Icon icon = UIManager.getIcon("RadioButton.icon");//(1) trying to get icon

        int w = icon.getIconWidth(),h = icon.getIconHeight();
        Image i = rad1.createImage(w, h);
        Image i2 = rad1.createImage(w,h);
        Graphics g = i.getGraphics();
        Graphics g2 = i2.getGraphics();


        g.setColor(Color.CYAN);
        g.fillRect(0, 0, w, h);
        rad1.setIcon(new ImageIcon(i));//setting icons
        g2.setColor(Color.RED);
        g2.fillRect(0, 0, w, h);
        rad1.setPressedIcon(new ImageIcon(i2));//setting icons
    }

    public static void main(String[] args) {
        new IconImageSaver();
    }

}

At position (1) i'm trying to get icon image, but it returns only background color. Can't understand why. Setting icons for various states works as intended.

Holey answered 18/10, 2012 at 11:7 Comment(7)
where do yu have to extract the icon from??Meredeth
From native resources. RadioButton's images are belong to OS resources, if I understand correct.Holey
Implement your own RadioButton here, with custom painting.Override the paintComponent() method to paint your icon however you want.Meredeth
This is solution, but where will i get native icons from?Holey
From AWT instead of Swing. AWT draws native widgets.Meredeth
AFAIK only with Nimbus L&F you can getIcon, for rest (in JDK) is there XxxFactory, paint own IconGridley
To paint own icon i must get original images from different systems. Then i could draw them myself and app's UI would be consistent with native L&F at the same time. Maybe someone knows how to get those icons from Winddows' & Mac OS X libraries or wherever they are stored?Holey
S
3

Some L&Fs (e.g. Nimbus, Aqua) support a large JComponent.sizeVariant, as discussed in Resizing a Component and Using Client Properties.

Addendum: I must use pure native L&F.

The rendering of a JRadioButton is determined by its associated ButtonUI delegate. The internals of delegates supplied by the native L&F are generally inaccessible and rely on host platform APIs. You have to use the available feature(s) of the user's chosen L&F or supply your own. If you can explain more about the underlying problem, it may help to suggest better alternatives.

Addendum: Absent developing a complete L&F, it may be possible to work with the radio button's parent, JToggleButton. Such buttons work well in a ButtonGroup, as shown here, and they can be decorated arbitrarily, as outlined here.

Schumann answered 18/10, 2012 at 17:14 Comment(4)
It's true, but as I said in comment to mKorbel's answer, I must use pure native L&F, i.e. Sun's implementation. A quote from provided link: Nimbus is currently the only Sun look and feel that supports size variants. Windows L&F doesn't support that.Holey
agreed and (AFAIK) there no way to add Icon (true is there is used paintIcon()) to UIManager but to override JCheckBox with paintIcon() or delegate own UI to UIManager (never to tried, don't know if is possible, but for Nimbus could be usefull)Gridley
This didn't reoslve my problem, but it's been a while since question was asked, so i gues there's no solution. I'm accepting an answer with highest upvotes count.Holey
I've outlined a less onerous approach above; sorry I missed the update to your question.Schumann
G
1

is very L&F sensitive, by default you can

  • use proper L&F (only Nimbus has implemented auto_whatever) but we talking about Custom L&F

  • to override keys in UIManager, but these keys can, could (be presented or with value) or missing in compare with another L&F

  • create own (J)Component, to overide important methods and

    a) put to the UIManger (one def. valid for whole JVM instace)

    b) add to the selected, desired or part of (J)Components, e.i. .... in the visible GUI

  • notice for (I need to implement font size switching in my app) there is very important to test if is required to change (we'll talking about) Font or FontUIResources, part of implemented methods for part of (J)Components to pretty ignore Font and required FontUIResources, now not sure if vice versa too

Gridley answered 18/10, 2012 at 11:18 Comment(1)
My customers wouldn't appreciate using non-native L&F. That's why i can't change L&F so app could have same look in different OS. So we are talking about completely native L&F with modified icons for some controls.Holey
S
1

IMPORTANT NOTE: This was only tested with the default 'Metal' look and feel. I do not guarantee that this will work for any other look and feel. Also I am not entirely sure how it works because it is admittedly a bit of a hack.

I was able to solve this a little bit differently.

I Was scaling my font globally using the UIManager defaults and so I wanted my radio buttons to scale with the font.

I found I could do this by extracting the Icon for the radio button from the UIManager, buffering them, re-sizing them and then deriving a new icon from the graphics of the buffered icons.

I ended up with this function:

public static void scaleRadioButtonIcon(JRadioButton rb){
    boolean previousState = rb.isSelected();
    rb.setSelected(false);
    FontMetrics boxFontMetrics =  rb.getFontMetrics(rb.getFont());
    Icon radioIcon = UIManager.getIcon("RadioButton.icon");
    BufferedImage radioImage = new BufferedImage(
        radioIcon.getIconWidth(), radioIcon.getIconHeight(),BufferedImage.TYPE_INT_ARGB
    );
    Graphics graphics = radioImage.createGraphics();
    try{
        radioIcon.paintIcon(rb, graphics, 0, 0);
    }finally{
        graphics.dispose();
    }
    ImageIcon newRadioImage = new ImageIcon(radioImage);
    Image finalRadioImage = newRadioImage.getImage().getScaledInstance(
        boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
    );

    rb.setSelected(true);
    Icon selectedRadioIcon = UIManager.getIcon("RadioButton.icon");
    BufferedImage selectedRadioImage = new BufferedImage(
            selectedRadioIcon.getIconWidth(), selectedRadioIcon.getIconHeight(),BufferedImage.TYPE_INT_ARGB
    );
    Graphics selectedGraphics = selectedRadioImage.createGraphics();
    try{
        selectedRadioIcon.paintIcon(rb, selectedGraphics, 0, 0);
    }finally{
        selectedGraphics.dispose();
    }
    ImageIcon newSelectedRadioImage = new ImageIcon(selectedRadioImage);
    Image selectedFinalRadioImage = newSelectedRadioImage.getImage().getScaledInstance(
        boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
    );
    rb.setSelected(previousState);
    rb.setIcon(new ImageIcon(finalRadioImage));
    rb.setSelectedIcon(new ImageIcon(selectedFinalRadioImage));
}

What it does is get the size of the font from the radiobuttons's font metrics. Using those metrics, it derives a new icon based on the icon found in the 'Look and Feel' and sizing it to the font's height.

One thing that I am not able to explain is how the icon for the radiobutton coming out of the UIManager changes to the 'selected' icon when I am accessing the same property to get both icons.

I start by saving the state of the control so I can restore it at the end. This is done because in order for the icons to be set properly, the state needs to be unchecked when you first request the icon from the UIManager and then it will need to be checked when you request the icon the second time to get the 'selected' icon.

Again, I am not entirely sure how the UIManager works or why the icon changes when we call the same property just by setting the 'selected' value of a single radiobutton, but that is what is required in order to get both the necessary icons.

If you did not want to use the font to size the controls, you could easily just pass in the height and width as parameters and use them instead of the font's height when setting the buffered image size.

I might mention that this same methodology works with checkboxes

Staff answered 18/11, 2014 at 13:9 Comment(3)
I tried this code and all it did for me was to change the radio button circle to a light red square AND reduce the displayed font size....Roseleeroselia
I am sorry it is not working for you. I failed to mention originally that I was using the default swing L&F and I never tested it with any other L&F. Almost this exact code is in a production application and works with the Metal Look and Feel.Staff
I tried it on MacOSX, probably the reason... I did not have another explicit L&F selected thoughRoseleeroselia

© 2022 - 2024 — McMap. All rights reserved.