Change cursor for all buttons on Swing app

2019-04-10 05:34发布

问题:

I have a Swing app with a main frame and some other forms loaded inside it. I Need to implement a general method to set the hand cursor for all buttons on any form.

This is similar of what we do with css on web pages (input[type=button] { cursor:pointer; })

回答1:

Walking the tree like @Madprogrammer suggested is the method if you want to change the cursor dynamically and/or on a particular form.

Just for fun (and to show-off SwingX again :) - if you want to install that cursor globally and then don't care about, install a ui-delegate which takes care of it. In SwingX, it's as simple as implementing and plugging a custom button addon. The side-effect is the same as in the other answer (though can't be solved as in that). The usual drawback (as always when installing custom ui delegates) is the need to subclass and plug-in delegates for all LAFs.

public class ButtonCursorAddon extends AbstractComponentAddon {

    /**
     * @param name
     */
    protected ButtonCursorAddon() {
        super("RolloverCursor");
    }

    @Override
    protected void addBasicDefaults(LookAndFeelAddons addon,
            DefaultsList defaults) {
        UIManager.getDefaults().remove("ButtonUI");
        defaults.add("ButtonUI", "org.jdesktop.swingx.plaf.ButtonCursorAddon$BasicButtonCursorUI");
    }

    @Override
    protected void addMetalDefaults(LookAndFeelAddons addon,
            DefaultsList defaults) {
        UIManager.getDefaults().remove("ButtonUI");
        defaults.add("ButtonUI", "org.jdesktop.swingx.plaf.ButtonCursorAddon$MetalButtonCursorUI");
    }

    @Override
    protected void addWindowsDefaults(LookAndFeelAddons addon,
            DefaultsList defaults) {
        UIManager.getDefaults().remove("ButtonUI");
        defaults.add("ButtonUI", "org.jdesktop.swingx.plaf.ButtonCursorAddon$WindowsButtonCursorUI");
    }


    @Override
    protected void addNimbusDefaults(LookAndFeelAddons addon,
            DefaultsList defaults) {
        UIManager.getDefaults().remove("ButtonUI");
        defaults.add("ButtonUI", "org.jdesktop.swingx.plaf.ButtonCursorAddon$SynthButtonCursorUI");
    }


    public static class BasicButtonCursorUI extends BasicButtonUI {

        public static ComponentUI createUI(JComponent c) {
            return new BasicButtonCursorUI();
        }

        @Override
        protected BasicButtonListener createButtonListener(AbstractButton b) {
            return new BasicHyperlinkListener(b);
        }

    }

    public static class SynthButtonCursorUI extends SynthButtonUI {

        public static ComponentUI createUI(JComponent c) {
            return new SynthButtonCursorUI();
        }

        @Override
        protected BasicButtonListener createButtonListener(AbstractButton b) {
            return new BasicHyperlinkListener(b);
        }

    }

    public static class MetalButtonCursorUI extends MetalButtonUI {

        public static ComponentUI createUI(JComponent c) {
            return new MetalButtonCursorUI();
        }

        @Override
        protected BasicButtonListener createButtonListener(AbstractButton b) {
            return new BasicHyperlinkListener(b);
        }

    }

    public static class WindowsButtonCursorUI extends WindowsButtonUI {

        public static ComponentUI createUI(JComponent c) {
            return new WindowsButtonCursorUI();
        }

        @Override
        protected BasicButtonListener createButtonListener(AbstractButton b) {
            return new BasicHyperlinkListener(b);
        }

    }

}

// usage: plug-in once in your application code (before creating any buttons)
static {
    LookAndFeelAddons.contribute(new ButtonCursorAddon());
}

I get this error: UIDefaults.getUI() failed: no ComponentUI class

Works for me - when registering the ui class with the UIManager, it needs the fully qualified class name to instantiate the delegate from:

// here the ButtonCursorUI is in package
// org.jdesktop.swingx.plaf
defaults.add("ButtonUI", "org.jdesktop.swingx.plaf.ButtonCursorAddon$WindowsButtonCursorUI");
// in another package that would be
defaults.add("ButtonUI", myPackageName + ".ButtonCursorAddon$WindowsButtonCursorUI");

Typically, you would have the different delegates in LAF specific subpackages of something.plaf (instead of in the addon itself) But then, it's an example :-)



回答2:

Basically, you'll have to walk the container and sub containers...

Be careful though, you'll be surprised by what is a button

public static void setButtonCursor(JComponent component, Cursor cursor) {

    for (Component comp : component.getComponents()) {

        if (comp instanceof JButton) {

            comp.setCursor(cursor);

        } else if (comp instanceof JComponent) {

            setButtonCursor((JComponent)comp, cursor);

        }

    }

}

This has the nice side effect of walking into JComboBoxs (among other components) and changing the cursor for their drop buttons, so be careful ;)