2015-10-26 36 views
1

我想在用作JComboBox的默認編輯器組件的文本字段中使用JLayer繪製一些附加信息。爲此,我需要將圖層設置爲組合框的編輯器,通過JComboBox.setEditor(ComboBoxEditor)但這似乎不可能,因爲JLayer是最終的,因此無法實現ComboBoxEditor接口。用JLayer裝飾JComboBox編輯器組件

有沒有辦法用JLayer來修飾JComboBox編輯器組件?

P.S。:我想漆的信息是在文本字段,這是微不足道用於JTextFieldJTextArea但不爲可編輯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; 
     } 

    } 
} 

回答

3

我想畫的文本字段,這是平凡的一個JTextField

你可以設置自己的編輯器內的某些文本偏移量光標般的線條中的信息組合框使用setEditor(...)方法。

因此,您可以擴展BasicComboBoxEditor並覆蓋createEditorComponent()方法以返回執行自定義繪製的自定義JTextField的實例。

1

或者更簡單的選項來完成是覆蓋的BasicComboBoxEditorgetEditorComponent()方法:

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

我讀camickr的答案後嘗試這樣做,但結果不是我所期待。由於某種原因,組合框邊框缺失。您的代碼也會發生同樣的情況。 – predi