I've implemented a zooming feature for all of my applications. But it does not work if I use setFont on a component. There are labels and text areas where I want a specific type (italic and/or bold) or a specific font family (i.e. san serif). If I use setFont() when creating these components, the zoom feature does not work. I've tried catching setFont for the components but they are never called. Any ideas why? My zoom class/component is attached (thank you Stack Overflow for the base code!)
public final class ZoomControl extends JPanel implements ActionListener {
// --------------------------------------------------------------------------
// variables
// --------------------------------------------------------------------------
private final Frame mFrame;
private final JLabel mText = new JLabel(" Zoom ");
private final JMenuItem mIncrease = new JMenuItem(" + ");
private final JMenuItem mDecrease = new JMenuItem(" - ");
// --------------------------------------------------------------------------
// constructor
// --------------------------------------------------------------------------
/**
* @param frame Specifies the frame upon which to update after changing
* the fonts.
*/
public ZoomControl(final Frame frame) {
super(new FlowLayout());
CommonUtils.checkParameterNull("frame", frame);
mFrame = frame;
add(mIncrease);
add(mText);
add(mDecrease);
mIncrease.addActionListener(this);
mIncrease.setBorder(BorderFactory.createEmptyBorder());
mDecrease.addActionListener(this);
mDecrease.setBorder(BorderFactory.createEmptyBorder());
}
// --------------------------------------------------------------------------
// methods
// --------------------------------------------------------------------------
/**
* @see ActionListener#actionPerformed(ActionEvent)
*/
@Override
public void actionPerformed(final ActionEvent evt) {
Object obj = evt.getSource();
if (obj == mIncrease) {
changeUIFonts(1);
} else if (obj == mDecrease) {
changeUIFonts(-1);
}
}
/** Change all the fonts for the application as specified by the size.
* @param size
*/
private void changeUIFonts(final int size) {
UIDefaults myDefaults = UIManager.getDefaults();
for (Enumeration<?> e = myDefaults.keys(); e.hasMoreElements(); ) {
final Object key = e.nextElement();
final Object value = myDefaults.get(key);
if (value instanceof Font) {
final Font font = (Font) value;
final int newSize = Math.round(font.getSize() + size);
if (value instanceof FontUIResource) {
myDefaults.put(key, new FontUIResource(font.getName(),
font.getStyle(), newSize));
} else {
myDefaults.put(key, new Font(font.getName(),
font.getStyle(), newSize));
}
}
}
SwingUtilities.updateComponentTreeUI(mFrame);
mFrame.pack();
}
} ```
You're iterating over UIManager.getDefaults()
. This is important if you ever plan to adding new components later in your session. (If your UI never changes: then you can avoid iterating over UIManager at all.)
But you'll need to also iterate over all existing the JComponents.
I recommend this approach:
private void changeUIFonts(final int size) {
UIDefaults myDefaults = UIManager.getDefaults();
for (Enumeration<?> e = myDefaults.keys(); e.hasMoreElements(); ) {
final Object key = e.nextElement();
final Object value = myDefaults.get(key);
if (value instanceof Font) {
final Font font = (Font) value;
final int newSize = Math.round(font.getSize() + size);
if (value instanceof FontUIResource) {
myDefaults.put(key, new FontUIResource(font.getName(),
font.getStyle(), newSize));
} else {
myDefaults.put(key, new Font(font.getName(),
font.getStyle(), newSize));
}
}
}
changeUIFontsForComponent(mFrame, size);
SwingUtilities.updateComponentTreeUI(mFrame);
mFrame.pack();
}
private void changeUIFontsForComponent(Component c, int fontSizeDelta) {
Font f = c.getFont();
if (!(f instanceof FontUIResource)) {
f = new Font(f.getName(), f.getStyle(), Math.round(f.getSize() + fontSizeDelta));
c.setFont(f);
}
if (c instanceof Container container) {
for (Component child : container.getComponents()) {
changeUIFontsForComponent(child, fontSizeDelta);
}
}
}
I tested this by adding this main method to your code sample:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame();
JPanel p = new JPanel(new FlowLayout());
ZoomControl c = new ZoomControl(f);
p.add(c);
JLabel label = new JLabel("Extra label");
label.setFont(new Font("dialog", Font.BOLD, 18));
p.add(label);
f.getContentPane().add(p);
f.pack();
f.setVisible(true);
}
});
}