我想基于现有的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
示例的替代方案。我对这种问题的一般方法感兴趣。
答案 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 ");
答案 2 :(得分:1)
基于JCommandButtonStrip
:
我认为你正在寻找JToggleButton作为@trashgod的建议,但我不确定按钮组给出了你的“问题”的当前描述。如果您需要按钮组,请使用它。
无论如何,我的回答指向这一行:
这可以基于预先配置的
JCommandButtonStrip
(一些信息 这里)但是公开了JCheckBox
的完全相同的API。
再次不清楚你是否想尝试JCommandButtonStrip
之类的按钮栏,或者你想做其他事情。但是,您可以使自己的组件从JComponent扩展,并仅委托外部需要的那些方法。例如,假设您要执行JCommandButtonStrip
等按钮栏。然后你可以:
JComponent
延伸的一个课程:您的按钮栏。注意 :已经有一个JToolBar组件可以完美地使用而无需重新发明轮子。下面的示例只是为了向您展示您可以控制提供给开发人员的API。
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));
你会看到这样的事情:
答案 3 :(得分:1)
您可以使用引用MyJComponent
的转发类的私有字段创建JComponent
ExistingComponent
的子类。
与ExistingComponent
的交互是通过MyJComponent
方法与转发类完成的,您可以自由地向MyJComponent
添加更多方法。
有关转发类使用的委托模式,请参阅 Effective Java 第16项。