基于另一个但具有不同API的Swing组件创建

时间:2014-03-25 17:03:43

标签: java swing

我想基于现有的Swing JComponent创建一个新的Swing JComponent,但是使用不同的API。换句话说,我不想扩展现有组件,因为我不希望它的API可以访问。

这是一个澄清我需求的例子:

替换显示两个按钮ON / OFF的JCheckBox。这可以基于预先配置的 JCommandButtonStrip(某些信息here),但公开的JCheckBox API完全相同。 <{1}}的配置不得更改。

解决此类问题的最佳方法是什么?

澄清:

有人指出,我写的关于API的内容并不清楚。

当然JCommandButtonStrip有许多公共字段和方法可供每个子类使用。然后JComponent的每个子类都可以添加自己的公共字段和方法。例如,JComponent添加AbstractButton方法,而isSelected()添加JCommandButtonStrip方法。

所以,我的意思是:我想创建一个新的getButtonCount()子类JComponent,它基于现有的MyJComponent。我不希望我的班级ExistingJComponent公开ExistingJComponent的公共方法({1}}除外)。然后我想向JComponent添加一些公共方法。

请注意,我并未寻找MyJComponent / MyJComponent示例的替代方案。我对这种问题的一般方法感兴趣。

4 个答案:

答案 0 :(得分:3)

您可以创建一个扩展JComponent的新类,然后在构造函数中插入一个复选框。

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

这显然是不完整的,您可能需要将某些方法委托给孩子。它可能会变得混乱。像IntelliJ IDEA这样的IDE会为你生成所有这些,如果你点击alt-ins(默认情况下)然后委托,然后选择复选框成员并选择你想要委托的条目。例如:

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

请记住,因为孩子在Swing组件树中,所以即使他们被标记为私有,其他代码也可以访问孩子。

((JCheckBox)myCoolCheckbox.getComponents()[0]).setSelected(true);

答案 1 :(得分:3)

如图here所示,您可以在JToggleButton中使用ButtonGroup的两个实例来显示两个按钮 ON / OFF &#34。 ButtonGroup一次只能选择组中的一个按钮。说明了以下变化:

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

image

答案 2 :(得分:1)

基于JCommandButtonStrip

的图片

enter image description here

我认为你正在寻找JToggleButton作为@trashgod的建议,但我不确定按钮组给出了你的“问题”的当前描述。如果您需要按钮组,请使用它。

无论如何,我的回答指向这一行:

  

这可以基于预先配置的JCommandButtonStrip(一些信息   这里)但是公开了JCheckBox的完全相同的API。

再次不清楚你是否想尝试JCommandButtonStrip之类的按钮栏,或者你想做其他事情。但是,您可以使自己的组件从JComponent扩展,并仅委托外部需要的那些方法。例如,假设您要执行JCommandButtonStrip等按钮栏。然后你可以:

  • JComponent延伸的一个课程:您的按钮栏。
  • 另一个提供API以向按钮栏添加“命令”。

注意 :已经有一个JToolBar组件可以完美地使用而无需重新发明轮子。下面的示例只是为了向您展示您可以控制提供给开发人员的API。

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

使用示例

此代码段显示了应如何使用MyCommandBar类:

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

你会看到这样的事情:

enter image description here

答案 3 :(得分:1)

您可以使用引用MyJComponent的转发类的私有字段创建JComponent ExistingComponent的子类。
ExistingComponent的交互是通过MyJComponent方法与转发类完成的,您可以自由地向MyJComponent添加更多方法。
有关转发类使用的委托模式,请参阅 Effective Java 第16项。