最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Zooming feature does not work if I use setFont with on a labeltext area - Stack Overflow

programmeradmin0浏览0评论

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

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();
    }
} ```
Share Improve this question asked Feb 5 at 20:27 Lori CookLori Cook 2091 gold badge2 silver badges11 bronze badges 2
  • 1 Why are you using a java.awt.Frame instead of a javax.swing.JFrame? AWT components and Swing components don't play well together. – Gilbert Le Blanc Commented Feb 5 at 22:41
  • That's weird...My apps use javax.swing.JFrame. I think it is because when I copied the code from another answer, it was using java.awt.Frame. Passing in a JFrame did not flag a problem. I just changed it but we'll see if anything happens. – Lori Cook Commented Feb 6 at 2:23
Add a comment  | 

1 Answer 1

Reset to default 1

Solution

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

Testing

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);
            }
        });
    }
发布评论

评论列表(0)

  1. 暂无评论