Create a Swing component based on another but with different API

前端 未结 4 1501
礼貌的吻别
礼貌的吻别 2021-01-24 10:36

I would like to create a new Swing JComponent based on an existing one, but with a different API. In other words, I don\'t want to extend the existing component, because I don\'

相关标签:
4条回答
  • 2021-01-24 10:50

    Based on this picture of JCommandButtonStrip:

    enter image description here

    I think you are looking for JToggleButton as @trashgod suggested, but I'm not sure about buttons group given the current description of your "problem". If you need buttons group then use it.

    Anyway my answer points to this line:

    This could be based on a pre-configured JCommandButtonStrip (some info here) but exposing exactly the same API of JCheckBox.

    Once again it's not clear if you're trying to do a buttons bar such as JCommandButtonStrip or you want to do something else. However you can make your own component extending from JComponent and delegate only those methods that are needed from the outside. For example let's say you want to do a buttons bar such as JCommandButtonStrip. Then you can have:

    • One class extending from JComponent: your buttons bar.
    • Another one providing an API to add "commands" to the buttons bar.

    Note: There's already a JToolBar component which can perfectly be used without reinvent the wheel. The example below is just to show you that you can control the API offered to the developers.

    MyCommandBar.java

    import java.awt.FlowLayout;
    import java.awt.Graphics;
    import java.awt.GridLayout;
    import java.awt.event.ActionListener;
    import java.util.HashMap;
    import java.util.Map;
    import javax.swing.AbstractButton;
    import javax.swing.Action;
    import javax.swing.Icon;
    import javax.swing.JButton;
    import javax.swing.JCheckBox;
    import javax.swing.JComponent;
    import javax.swing.JPanel;
    import javax.swing.JToggleButton;
    import javax.swing.event.ChangeListener;
    
    public class MyCommandBar extends JComponent {
    
        private final JPanel content;
        private final Map<String, CommandItem> map = new HashMap<>();
    
        public MyCommandBar() {
            super();
            content = new JPanel(new GridLayout(1, 0));
            content.setOpaque(false);
            setLayout(new FlowLayout());
            add(content);
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
    
            Graphics graphics = g.create();
            graphics.setColor(getBackground());
            graphics.fillRect(0, 0, getWidth(), getHeight());
            graphics.dispose();
        }
    
        public void addCommandItem(String actionCommand, CommandItem commandItem) {
            if(map.get(actionCommand) != null) {
                removeCommandItem(actionCommand);
            }
            content.add(commandItem.getComponent());
            map.put(actionCommand, commandItem);
        }
    
        public void removeCommandItem(String actionCommand) {
            CommandItem commandItem = map.get(actionCommand);
            if(commandItem != null) {
                content.remove(commandItem.getComponent());
                content.revalidate();
                content.repaint();
                map.remove(actionCommand);
            }
        }
    
        public CommandItem getCommandItem(String actionCommand) {
            return map.get(actionCommand);
        }
    
        public static class CommandItem {
    
            public static final int TOGGLE_BUTTON_STYLE = 0;
            public static final int CHECK_BOX_STYLE = 1;
            public static final int DEFAULT_BUTTON_STYLE = 2;
    
            private final AbstractButton component;
    
            public CommandItem(String text, boolean state, Icon icon, int style) {
                switch(style) {
                    case TOGGLE_BUTTON_STYLE : component = new JToggleButton(text, icon, state); break;
                    case CHECK_BOX_STYLE : component = new JCheckBox(text, icon, state); break;
                        default: component = new JButton(text, icon);
                }
            }
    
            protected AbstractButton getComponent() {
                return component;
            }
    
            public void addActionListener(ActionListener listener) {
                component.addActionListener(listener);
            }
    
            public void addChangeListener(ChangeListener listener) {
                component.addChangeListener(listener);
            }
    
            public void setAction(Action action) {
                component.setAction(action);
            }
        }
    }
    

    Example of use

    This code snippet shows how MyCommandBar class should be used:

    MyCommandBar commandBar = new MyCommandBar();
    commandBar.setBorder(BorderFactory.createLineBorder(Color.black, 1));
    commandBar.addCommandItem("BOLD", new MyCommandBar.CommandItem("<html><b>Bold</b></html>", true, null, MyCommandBar.CommandItem.TOGGLE_BUTTON_STYLE));
    commandBar.addCommandItem("ITALICS", new MyCommandBar.CommandItem("<html><i>Italics</i></html>", false, null, MyCommandBar.CommandItem.CHECK_BOX_STYLE));
    commandBar.addCommandItem("UNDERLINE", new MyCommandBar.CommandItem("<html><u>Underline</u></html>", false, null, MyCommandBar.CommandItem.DEFAULT_BUTTON_STYLE));
    

    And you'll see something like this:

    enter image description here

    0 讨论(0)
  • 2021-01-24 11:04

    As shown here, you can use two instances of JToggleButton in a ButtonGroup to "show two buttons ON / OFF." The ButtonGroup causes only one button in the group to be selected at a time. The following change is illustrated:

    private final JLabel label = new JLabel(" \u2713 ");
    

    image

    0 讨论(0)
  • 2021-01-24 11:08

    You can create a new class which extends JComponent then inside the constructor insert a checkbox into itself.

    public class MyCoolCheckbox extends JComponent{
        private JCheckBox checkbox;
        public MyCoolCheckbox(String label) {
            checkbox= new JCheckBox(label);
            this.setLayout(new BorderLayout());
            this.add(checkbox, BorderLayout.CENTER);
        }
    }
    

    This is obviously incomplete and you may need to delegate certain methods to the child. It might get messy. IDEs like IntelliJ IDEA will generate all this for you if you hit alt-ins (by default) then delegate, then select the checkbox member and pick the entries you want to delegate. For example:

    public void setForeground(Color fg) {
        checkbox.setForeground(fg);
    }
    
    public void setBackground(Color bg) {
        checkbox.setBackground(bg);
    }
    public Color getForeground() {
        return checkbox.getForeground();
    }
    
    public Color getBackground() {
        return checkbox.getBackground();
    }
    

    Keep in mind that because the child is within the Swing component tree, other code will have access to the children even though they are marked private.

    ((JCheckBox)myCoolCheckbox.getComponents()[0]).setSelected(true);
    
    0 讨论(0)
  • 2021-01-24 11:12

    You can create MyJComponent subclass of JComponent with a private field that references a forwarding class for ExistingComponent.
    The interactions with ExistingComponent are done with the forwarding class through methods of MyJComponent, and you are free to add more methods to MyJComponent.
    Please see Effective Java item 16, for the delegation pattern used with the forwarding class.

    0 讨论(0)
提交回复
热议问题