我想在用作 a 的默认编辑器组件的文本字段中绘制一些附加信息,JComboBox
使用JLayer
. 为此,我需要将图层设置为组合框的编辑器,JComboBox.setEditor(ComboBoxEditor)
但这似乎是不可能的,因为JLayer
它是最终的,因此无法实现ComboBoxEditor
接口。
有没有办法用 装饰JComboBox
编辑器组件JLayer
?
PS:我想绘制的信息是文本字段内某些文本偏移处的类似光标的行,这对于 aJTextField
或 a来说是微不足道的,JTextArea
但对于可编辑JComboBox
(其编辑器)来说却不是。
编辑:这是我最接近的,在阅读@camickr 的答案后,但对它不满意。相关部分正在扩展BasicComboBoxEditor
。
import java.awt.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import javax.swing.text.*;
public class GenericDecorateWithJLayer extends JFrame {
private static final String SAMPLE_TEXT = "Hello, world!";
private final Map<JComponent, List<Integer>> componentToPositions;
public GenericDecorateWithJLayer() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new GridBagLayout());
componentToPositions = new HashMap<JComponent, List<Integer>>();
GridBagConstraints gbc;
JLabel label1 = new JLabel("label1:");
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
add(label1, gbc);
JTextField textfield1 = new JTextField(20);
textfield1.setText(SAMPLE_TEXT);
componentToPositions.put(textfield1, Arrays.asList(new Integer[]{5}));
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
add(textfield1, gbc);
JLabel label2 = new JLabel("label2:");
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 1;
add(label2, gbc);
JTextField textfield2 = new JTextField(20);
textfield2.setText(SAMPLE_TEXT);
componentToPositions.put(textfield2, Arrays.asList(new Integer[]{6}));
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 1;
add(textfield2, gbc);
JLabel label3 = new JLabel("label3:");
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 2;
add(label3, gbc);
JTextArea textarea1 = new JTextArea(5, 20);
textarea1.setText(SAMPLE_TEXT);
componentToPositions.put(textarea1, Arrays.asList(new Integer[]{7}));
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 2;
JScrollPane scroll1 = new JScrollPane(textarea1);
add(scroll1, gbc);
JLabel label4 = new JLabel("label4:");
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 3;
add(label4, gbc);
JComboBox combobox1 = new JComboBox(new Object[]{SAMPLE_TEXT, "one", "two", "three"});
combobox1.setEditable(true);
combobox1.setSelectedItem(SAMPLE_TEXT);
componentToPositions.put(combobox1, Arrays.asList(new Integer[]{8}));
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 3;
gbc.fill = GridBagConstraints.HORIZONTAL;
add(combobox1, gbc);
pack();
setLocationRelativeTo(null);
replaceWithJLayer(textfield1);
replaceWithJLayer(textfield2);
replaceWithJLayer(textarea1);
replaceWithJLayer(combobox1);
}
/**
* Intended to decorate legacy components.
*
* @param component
*/
private void replaceWithJLayer(JComponent component) {
Container parent = component.getParent();
if (component instanceof JComboBox) {
JComboBox cbb = (JComboBox) component;
cbb.setEditor(new MyComboBoxEditor(componentToPositions.get(cbb)));
} else if (parent.getLayout() instanceof GridBagLayout) {
GridBagLayout layout = (GridBagLayout) parent.getLayout();
for (int i = 0; i < parent.getComponentCount(); i++) {
Component candidate = parent.getComponent(i);
if (candidate == component) {
GridBagConstraints gbc = layout.getConstraints(component);
parent.remove(i);
JLayer<JComponent> layer = new JLayer<JComponent>(
component,
new MyLayerUI(
component,
componentToPositions.get(component)));
parent.add(layer, gbc, i);
break;
}
}
} else if (parent instanceof JViewport) {
JViewport viewport = (JViewport) parent;
JLayer<JComponent> layer = new JLayer<JComponent>(
component,
new MyLayerUI(
component, componentToPositions.get(component)));
viewport.setView(layer);
}
}
public static void main(String[] args)
throws ClassNotFoundException, InstantiationException,
IllegalAccessException, UnsupportedLookAndFeelException {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
}
System.out.println(info.getName());
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GenericDecorateWithJLayer().setVisible(true);
}
});
}
private static class MyLayerUI extends LayerUI<JComponent> {
private final JComponent component;
private final List<Integer> positions;
public MyLayerUI(JComponent component, List<Integer> positions) {
this.component = component;
this.positions = positions;
}
@Override
public void paint(Graphics g, JComponent c) {
// paint the layer as is
super.paint(g, c);
// fill it with the translucent green
g.setColor(new Color(0, 128, 0, 128));
// paint positions
JTextComponent textComponent = (JTextComponent) component;
for (Integer position : positions) {
try {
Rectangle rect = textComponent.modelToView(position);
g.fillRect(rect.x, rect.y, rect.width, rect.height);
} catch (BadLocationException ex) {
// no-op
}
}
}
}
private static class MyComboBoxEditor extends BasicComboBoxEditor {
private final JLayer<JComponent> layer;
public MyComboBoxEditor(List<Integer> positions) {
super();
layer = new JLayer<JComponent>(editor, new MyLayerUI(editor, positions));
}
@Override
public Component getEditorComponent() {
return layer;
}
}
}