2008-09-26 16 views
10

JComboBox var ve öğeler listesinde bir ayırıcı olması istiyorum. Bunu Java'da nasıl yaparım?Java'da JComboBox'a nasıl ayırıcı ekleyebilirim?

Bunun kullanışlı olacağı bir örnek senaryo, yazı tipi-aile seçimi için bir açılır kutu oluştururken; Word ve Excel'de font-aile-seçim-kontrolüne benzer. Bu durumda, en çok kullanılan yazı tiplerini en üstte, sonra ayırıcıyı ve son olarak yazı tipi altındaki tüm yazı tipi ailelerini alfabetik sırayla göstermek istiyorum.

Bunun nasıl yapılacağı konusunda bana yardımcı olan veya Java'da bu mümkün değil mi?

cevap

7

Eğer ListCellRenderer sen Yer tutucu tespit ederken liste modelinde bilinen bir yer tutucu ekleyerek http://www.java2s.com/Code/Java/Swing-Components/BlockComboBoxExample.htm

Temel olarak içeren java2s bir özel ListCellRenderer kullanmak ve nasıl gösteren bir örnek ile oldukça kısa bir öğretici var yazdığım ve kod aşağıda test Zamanla 'yeni JSeparator (JSeparator.HORIZONTAL)'

+2

'BlockComboBoxExample' örneğin imleç tuşu ve birinci keser harf tuşuyla gezinme. Santhosh Kumar'ın [örnek] (http://www.jroller.com/santhosh/entry/jcombobox%5Fitems%5Fwith%5Fseparators) daha iyi çalışıyor gibi görünüyor. – bobndrew

2

Ayraç öğelerini farklı şekilde çizen özel bir ListCellRenderer kullanabilirsiniz. docs ve küçük bir tutorial.

4

bir örneğini döndürür, muhtemelen ben denemeyi zevk olarak
umrumda değil ... daha iyi cevaplar sürü var/öğrenme (Swing cephesinde hala biraz yeşil).

[EDIT] Üç yıl sonra, biraz daha az yeşilim ve bobndrew'un geçerli sözlerini dikkate aldım. Çalıştığım önemli navigasyonla ilgili bir sorunum yok (belki de JVM sürümü sorunu muydu?). Yine de, göstericiyi vurgulamak için geliştirdim. Ve daha iyi bir demo kodu kullanıyorum. Kabul edilen yanıt muhtemelen daha iyidir (daha standart), eğer özel bir ayırıcıyı isterseniz benimki muhtemelen daha esnektir ...

Temel fikir, açılan kutudaki öğeler için bir oluşturucu kullanmaktır. Çoğu öğe için, öğenin metni ile basit bir JLabel. Son kullanılan/en çok kullanılan ürün için JLabel'i alt kısmında bir çizgi çizen özel bir kenarlıkla dekore ediyorum.

import java.awt.*; 
import javax.swing.*; 


@SuppressWarnings("serial") 
public class TwoPartsComboBox extends JComboBox 
{ 
    private int m_lastFirstPartIndex; 

    public TwoPartsComboBox(String[] itemsFirstPart, String[] itemsSecondPart) 
    { 
    super(itemsFirstPart); 
    m_lastFirstPartIndex = itemsFirstPart.length - 1; 
    for (int i = 0; i < itemsSecondPart.length; i++) 
    { 
     insertItemAt(itemsSecondPart[i], i); 
    } 

    setRenderer(new JLRenderer()); 
    } 

    protected class JLRenderer extends JLabel implements ListCellRenderer 
    { 
    private JLabel m_lastFirstPart; 

    public JLRenderer() 
    { 
     m_lastFirstPart = new JLabel(); 
     m_lastFirstPart.setBorder(new BottomLineBorder()); 
//  m_lastFirstPart.setBorder(new BottomLineBorder(10, Color.BLUE)); 
    } 

    @Override 
    public Component getListCellRendererComponent(
     JList list, 
     Object value, 
     int index, 
     boolean isSelected, 
     boolean cellHasFocus) 
    { 
     if (value == null) 
     { 
     value = "Select an option"; 
     } 
     JLabel label = this; 
     if (index == m_lastFirstPartIndex) 
     { 
     label = m_lastFirstPart; 
     } 
     label.setText(value.toString()); 
     label.setBackground(isSelected ? list.getSelectionBackground() : list.getBackground()); 
     label.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground()); 
     label.setOpaque(true); 

     return label; 
    } 
    } 
} 

Ayırıcı sınıfı, vb özel bir renk ile, bir kalınlığa sahip olabilir

test sınıfı
import java.awt.*; 
import javax.swing.border.AbstractBorder; 

/** 
* Draws a line at the bottom only. 
* Useful for making a separator in combo box, for example. 
*/ 
@SuppressWarnings("serial") 
class BottomLineBorder extends AbstractBorder 
{ 
    private int m_thickness; 
    private Color m_color; 

    BottomLineBorder() 
    { 
    this(1, Color.BLACK); 
    } 

    BottomLineBorder(Color color) 
    { 
    this(1, color); 
    } 

    BottomLineBorder(int thickness, Color color) 
    { 
    m_thickness = thickness; 
    m_color = color; 
    } 

    @Override 
    public void paintBorder(Component c, Graphics g, 
     int x, int y, int width, int height) 
    { 
    Graphics copy = g.create(); 
    if (copy != null) 
    { 
     try 
     { 
     copy.translate(x, y); 
     copy.setColor(m_color); 
     copy.fillRect(0, height - m_thickness, width - 1, height - 1); 
     } 
     finally 
     { 
     copy.dispose(); 
     } 
    } 
    } 

    @Override 
    public boolean isBorderOpaque() 
    { 
    return true; 
    } 
    @Override 
    public Insets getBorderInsets(Component c) 
    { 
    return new Insets(0, 0, m_thickness, 0); 
    } 
    @Override 
    public Insets getBorderInsets(Component c, Insets i) 
    { 
    i.left = i.top = i.right = 0; 
    i.bottom = m_thickness; 
    return i; 
    } 
} 

:

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 


@SuppressWarnings("serial") 
public class TwoPartsComboBoxDemo extends JFrame 
{ 
    private TwoPartsComboBox m_combo; 

    public TwoPartsComboBoxDemo() 
    { 
    Container cont = getContentPane(); 
    cont.setLayout(new FlowLayout()); 

    cont.add(new JLabel("Data: ")) ; 

    String[] itemsRecent = new String[] { "ichi", "ni", "san" }; 
    String[] itemsOther = new String[] { "one", "two", "three" }; 
    m_combo = new TwoPartsComboBox(itemsRecent, itemsOther); 

    m_combo.setSelectedIndex(-1); 
    cont.add(m_combo); 
    m_combo.addActionListener(new ActionListener() 
    { 
     public void actionPerformed(ActionEvent ae) 
     { 
     String si = (String) m_combo.getSelectedItem(); 
     System.out.println(si == null ? "No item selected" : si.toString()); 
     } 
    }); 

    // Reference, to check we have similar behavior to standard combo 
    JComboBox combo = new JComboBox(itemsRecent); 
    cont.add(combo); 
    } 

    /** 
    * Start the demo. 
    * 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) 
    { 
    // turn bold fonts off in metal 
    UIManager.put("swing.boldMetal", Boolean.FALSE); 

    SwingUtilities.invokeLater(new Runnable() 
    { 
     public void run() 
     { 
     JFrame demoFrame = new TwoPartsComboBoxDemo(); 
     demoFrame.setTitle("Test GUI"); 
     demoFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     demoFrame.setSize(400, 100); 
     demoFrame.setVisible(true); 
     } 
    }); 
    } 
} 
+0

Değişken adlandırma, burada en kötü durum değil: Tüm açılan liste öğesi seçimini kırıyorsunuz: seçim artık boyanmadı ve ilk harf-anahtar atlamaları bozuk. Ve mümkün olan en küçük kapsamda 'm_combo' ve' m_renderer'ı tanımlamanız gerekir (public TestGui() 'de). Ve Renderer ** ve ** 'TestGui' sınıfı için bir glooooobal 'm_lastRecentIndex' kullanılmamalıdır (ki bu bir 'JFrame' alt sınıfı değil, yalnız bir ana sınıf olmalıdır). Ama diş teli tarzını severim! – bobndrew

+0

@bobndrew: hey! Yazdığım gibi, o sırada bir acemi oldum (3 yıl oldu!). Söylemediğiniz günahlar arasında, muhtemelen bulduğum bir Swing test şablonu kullandım ve daha da kötüsü, SwingUtilities.invokeLater kullanmamıştım! Şu anda kullandığım kod, en azından (ama yine de JFrame alt sınıfı ...). Ve m_lastRecentIndex daha yerel ... Ama eleştirilerinizin çoğu, gerçekten üretim kodu olmayan hızlı bir test dersi hakkında.Bugün, bu tür kodlara daha fazla dikkat gösteriyorum, çünkü yeni başlayanlar bundan ilham alabiliyorlar ... :-) Ayrıca, kestirilen öğeleri ve seçimi vurgulamak konusunda da haklısınız. TODO – PhiLho

+0

Not: Daha modern/doğru bir sürüm için yukarıdaki kodu düzenledim. Benim yaklaşımımın bir avantajı, JSeparator'dan daha esnek (en azından) ve bir yuva almamasıdır. – PhiLho