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.

Aleksandr Kravets
  • 5,750
  • 7
  • 53
  • 72

3 Answers3

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.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • 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. – Aleksandr Kravets Oct 19 '12 at 07:28
  • 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) – mKorbel Oct 19 '12 at 12:09
  • 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. – Aleksandr Kravets Dec 07 '12 at 09:22
  • I've outlined a less onerous approach above; sorry I missed the update to your question. – trashgod Dec 07 '12 at 11:46
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

mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • 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. – Aleksandr Kravets Oct 18 '12 at 11:39
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

Community
  • 1
  • 1
Pow-Ian
  • 3,607
  • 1
  • 22
  • 31
  • 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.... – JoeG Jun 07 '16 at 11:37
  • 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. – Pow-Ian Jun 10 '16 at 13:35
  • I tried it on MacOSX, probably the reason... I did not have another explicit L&F selected though – JoeG Jun 10 '16 at 19:54