[英]Decorate a JComboBox editor component with a JLayer
我想使用JLayer
在用作JComboBox
的默認編輯器組件的文本字段中繪制一些其他信息。 為此,我需要通過JComboBox.setEditor(ComboBoxEditor)
將圖層設置為組合框的編輯器,但這似乎是不可能的,因為JLayer
是最終版本,因此無法實現ComboBoxEditor
接口。
有沒有辦法用JLayer
裝飾JComboBox
編輯器組件?
PS:我要繪制的信息是文本字段內某些文本偏移處的類似光標的行,這對於JTextField
或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;
}
}
}
我要繪制的信息是在文本字段內某些文本偏移處的類似光標的行,這對於JTextField是微不足道的
您可以使用setEditor(...)
方法為組合框設置自己的編輯器。
因此,您可以擴展BasicComboBoxEditor
並重寫createEditorComponent()
方法以返回執行自定義繪制的自定義JTextField的實例。
或更簡單的選擇是重寫BasicComboBoxEditor
的getEditorComponent()
方法:
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
import javax.swing.plaf.basic.BasicComboBoxEditor;
//import javax.swing.plaf.metal.MetalComboBoxEditor;
import javax.swing.text.*;
public class ComboEditorJLayerTest {
public JComponent makeUI() {
JComboBox<String> comboBox = new JComboBox<>(new String[] {"aaaaaaa", "bbb"});
comboBox.setEditable(true);
comboBox.setEditor(new BasicComboBoxEditor() {
private Component editorComponent;
//@see javax/swing/plaf/synth/SynthComboBoxUI.java
@Override public JTextField createEditorComponent() {
JTextField f = new JTextField("", 9);
f.setName("ComboBox.textField");
return f;
}
@Override public Component getEditorComponent() {
if (editorComponent == null) {
JTextComponent tc = (JTextComponent) super.getEditorComponent();
editorComponent = new JLayer<JTextComponent>(tc, new ValidationLayerUI());
}
return editorComponent;
}
});
JPanel p = new JPanel();
p.add(comboBox);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
try {
for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(laf.getName())) {
UIManager.setLookAndFeel(laf.getClassName());
}
}
}catch(Exception e) {
e.printStackTrace();
}
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new ComboEditorJLayerTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
//@see http://docs.oracle.com/javase/tutorial/uiswing/examples/misc/FieldValidatorProject/src/FieldValidator.java
class ValidationLayerUI extends LayerUI<JTextComponent> {
@Override public void paint(Graphics g, JComponent c) {
super.paint(g, c);
JLayer jlayer = (JLayer) c;
JTextComponent tc = (JTextComponent) jlayer.getView();
if (tc.getText().length() > 6) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int w = c.getWidth();
int h = c.getHeight();
int s = 8;
int pad = 4;
int x = w - pad - s;
int y = (h - s) / 2;
g2.setPaint(Color.RED);
g2.fillRect(x, y, s + 1, s + 1);
g2.setPaint(Color.WHITE);
g2.drawLine(x, y, x + s, y + s);
g2.drawLine(x, y + s, x + s, y);
g2.dispose();
}
}
}
可能可以通過擴展CellRenderer來完成
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.