2016-05-11 15 views
0

TL: DR Ich möchte eine JComboBox erstellen, die JCheckboxes anstelle von JLabels überall, aber in der Haupt-Label hat - an dieser Stelle möchte ich Zeichenfolge, die Werte aller aktivierten Kästchen darstellen. Ich habe es geschafft, es funktioniert, aber ich habe ein paar Probleme mit dem Öffnen des Menüs auf Mausklick. Ich möchte auch, dass Pfeiltasten nur durch die Box navigieren, ohne die Elemente und die Leertaste auszuwählen.Erstellen von JComboBox mit Kontrollkästchen

Egal was ich tue, nach meinem ActionListener Fängen per Mausklick und ein Element wählt das Menü durch einen anderen Zuhörer in den JComboBox und Verfahren setPopupVisible verschachtelt schließt - es mit meiner hässlichen Problemumgehung funktioniert, aber es hat doch ein besserer Weg zu sein, um dies zu tun ..

Ich glaube, ich brauche Maushörer auf listBox in Klasse BasicComboBoxUI aber wie komme ich dorthin?

so wenig Menge an Code, wie ich es verengen könnte:

ComboCheckBoxModel:

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.ItemListener; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.stream.Collectors; 

public class ComboCheckBoxModel extends DefaultListModel implements ComboBoxModel, ItemSelectable { 


    private List<String> items = new ArrayList<>(); 
    private List<String> checkedItems = new ArrayList<>(); 
    private String selectedItem; 

    public ComboCheckBoxModel(List<String> items) { 
     if(!items.isEmpty()) { 
      selectedItem = items.get(0); 
     } 
     this.items = items; 
    } 

    public void check(Object item) { 
     String itemAsString = item.toString(); 
     if(checkedItems.contains(itemAsString)) { 
      checkedItems.remove(itemAsString); 
     } else { 
      checkedItems.add(itemAsString); 
     } 
     fireContentsChanged(this, items.indexOf(item), items.indexOf(item)); 
    } 

    public String getDataStringRepresentation() { 
     return checkedItems.stream().sorted().collect(Collectors.joining(", ")); 
    } 

    @Override 
    public void setSelectedItem(Object anItem) { 
     selectedItem = anItem.toString(); 
    } 

    @Override 
    public Object getSelectedItem() { 
     return selectedItem; 
    } 

    @Override 
    public int getSize() { 
     return items.size(); 
    } 

    @Override 
    public Object getElementAt(int index) { 
     return items.get(index); 
    } 

    public boolean isChecked(String stringValue) { 
     return checkedItems.contains(stringValue); 
    } 

    @Override 
    public Object[] getSelectedObjects() { 
     return items.toArray(); 
    } 

    @Override 
    public void addItemListener(ItemListener l) { 

    } 

    @Override 
    public void removeItemListener(ItemListener l) { 

    } 
} 

JComboBox:

import javax.swing.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.InputEvent; 
import java.awt.event.KeyEvent; 
import java.util.stream.Stream; 

import static java.util.stream.Collectors.toList; 

public class JComboCheckBox extends JComboBox { 

    private final ComboCheckBoxModel model = new ComboCheckBoxModel(Stream.of("bum", "kabum", "dabum").collect(toList())); 
    private boolean shouldntClose; 

    public JComboCheckBox() { 
     super(); 
     setRenderer(new CheckBoxCellRenderer()); 
     setModel(model); 

     addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       if (e.getModifiers() == InputEvent.BUTTON1_MASK) { 
        System.out.println("LPM MASK"); 
        model.check(model.getSelectedItem()); 
        shouldntClose = true; 
       } 
      } 
     }); 
    } 

    @Override 
    protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { 
     if (ks.getKeyCode() == KeyEvent.VK_SPACE && isPopupVisible()) { 
      if (ks.getKeyCode() == KeyEvent.VK_SPACE && condition == WHEN_FOCUSED && ks.isOnKeyRelease()) { 
       System.out.println("ks = [" + ks + "], e = [" + e + "], condition = [" + condition + "], pressed = [" + pressed + "]"); 
       model.check(model.getSelectedItem()); 
      } 
      return true; 
     } 
     return super.processKeyBinding(ks, e, condition, pressed); 
    } 


    @Override 
    public void setPopupVisible(boolean v) { 
     if (shouldntClose) { 
      shouldntClose = false; 
      return; 
     } else { 
      super.setPopupVisible(v); 
     } 

    } 

    @Override 
    public Object getSelectedItem() { 
     return model.getSelectedItem(); 
    } 
} 

Zelle Renderer:

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

public class CheckBoxCellRenderer extends JCheckBox implements ListCellRenderer { 
    @Override 
    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 

     ComboCheckBoxModel model = (ComboCheckBoxModel) list.getModel(); 
     if (index != -1) { 
      String stringValue = value == null ? "null" : value.toString(); 
      setText(stringValue); 

      boolean checked = model.isChecked(stringValue); 
      setSelected(checked); 

      if (isSelected) { 
       setBackground(list.getSelectionBackground()); 
       setForeground(list.getSelectionForeground()); 
      } else { 
       setBackground(list.getBackground()); 
       setForeground(list.getForeground()); 
      } 

      return this; 
     } else { 
      String stringValue = model.getDataStringRepresentation(); 
      return new JLabel(stringValue); 
     } 
    } 
} 

Launcher:

import javax.swing.*; 

public class Launcher { 
    public JFrame create() { 
     JFrame f=new JFrame("Type the name of frame"); 
     f.add(new JComboCheckBox()); 
     f.setSize(400,400); 
     return f; 
    } 

    public static void main(String[] args) { 
     Launcher launcher = new Launcher(); 
     launcher.create().setVisible(true); 
    } 
} 

Antwort

0

List-Box in der Klasse BasicComboBoxUI aber wie komme ich dorthin?

der ListBox (? JList) ist möglich, von der BasicComboPopup zu bekommen:

Accessible a = getAccessibleContext().getAccessibleChild(0); 
if (a instanceof BasicComboPopup) { 
    BasicComboPopup pop = (BasicComboPopup) a; 
    int index = pop.getList().getSelectedIndex(); 
    //... 
} 

ComboCheckBoxTest.java

import java.awt.*; 
import java.awt.event.*; 
import java.util.*; 
import java.util.List; 
import java.util.stream.Collectors; 
import javax.accessibility.*; 
import javax.swing.*; 
import javax.swing.plaf.basic.*; 

public class ComboCheckBoxTest { 
    public JComponent makeUI() { 
    CheckableItem[] m = { 
     new CheckableItem("bum", false), 
     new CheckableItem("kabum", false), 
     new CheckableItem("dabum", false) 
    }; 
    JPanel p = new JPanel(); 
    p.add(new JComboCheckBox<CheckableItem>(m)); 
    return p; 
    } 
    public static void main(String[] args) { 
    EventQueue.invokeLater(() -> { 
     JFrame f = new JFrame("Type the name of frame"); 
     f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     f.getContentPane().add(new ComboCheckBoxTest().makeUI()); 
     f.setSize(320, 240); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    }); 
    } 
} 

class CheckableItem { 
    public final String text; 
    public boolean selected; 
    protected CheckableItem(String text, boolean selected) { 
    this.text = text; 
    this.selected = selected; 
    } 
    @Override public String toString() { 
    return text; 
    } 
} 

class CheckBoxCellRenderer<E extends CheckableItem> implements ListCellRenderer<E> { 
    private final JLabel label = new JLabel(" "); 
    private final JCheckBox check = new JCheckBox(" "); 
    @Override public Component getListCellRendererComponent(
     JList list, CheckableItem value, int index, 
     boolean isSelected, boolean cellHasFocus) { 
    ListModel model = list.getModel(); 
    if (index < 0) { 
     label.setText(getDataStringRepresentation(model)); 
     return label; 
    } else { 
     check.setText(Objects.toString(value, "null")); 
     check.setSelected(value.selected); 
     if (isSelected) { 
     check.setBackground(list.getSelectionBackground()); 
     check.setForeground(list.getSelectionForeground()); 
     } else { 
     check.setBackground(list.getBackground()); 
     check.setForeground(list.getForeground()); 
     } 
     return check; 
    } 
    } 
    private String getDataStringRepresentation(ListModel model) { 
    List<String> sl = new ArrayList<>(); 
    for (int i = 0; i < model.getSize(); i++) { 
     Object o = model.getElementAt(i); 
     if (o instanceof CheckableItem && ((CheckableItem) o).selected) { 
     sl.add(o.toString()); 
     } 
    } 
    return sl.stream().sorted().collect(Collectors.joining(", ")); 
    } 
} 

class JComboCheckBox<E extends CheckableItem> extends JComboBox<E> { 
    private boolean shouldntClose; 
    private transient ActionListener listener; 

    public JComboCheckBox() { 
    super(); 
    } 

    public JComboCheckBox(E[] m) { 
    super(m); 
    } 

    @Override public Dimension getPreferredSize() { 
    return new Dimension(200, 20); 
    } 

    @Override public void updateUI() { 
    setRenderer(null); 
    removeActionListener(listener); 
    super.updateUI(); 
    listener = e -> { 
     if (e.getModifiers() == InputEvent.BUTTON1_MASK) { 
     System.out.println("LPM MASK: " + getSelectedIndex()); 
     updateItem(getSelectedIndex()); 
     shouldntClose = true; 
     } 
    }; 
    setRenderer(new CheckBoxCellRenderer<CheckableItem>()); 
    addActionListener(listener); 
    getInputMap(JComponent.WHEN_FOCUSED).put(
     KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "space-key-select"); 
    getActionMap().put("space-key-select", new AbstractAction() { 
     @Override public void actionPerformed(ActionEvent e) { 
     System.out.println("JComboBox#getSelectedIndex()" + getSelectedIndex()); 
     Accessible a = getAccessibleContext().getAccessibleChild(0); 
     if (a instanceof BasicComboPopup) { 
      BasicComboPopup pop = (BasicComboPopup) a; 
      int i = pop.getList().getSelectedIndex(); 
      System.out.println("JList#getSelectedIndex() " + i); 
      updateItem(i); 
     } 
     } 
    }); 
    } 

    private void updateItem(int index) { 
    if (isPopupVisible()) { 
     E item = getItemAt(index); 
     item.selected ^= true; 
     removeItemAt(index); 
     insertItemAt(item, index); 
     setSelectedItem(item); 
    } 
    } 

    @Override 
    public void setPopupVisible(boolean v) { 
    if (shouldntClose) { 
     shouldntClose = false; 
     return; 
    } else { 
     super.setPopupVisible(v); 
    } 
    } 
}