JTable中可编辑JComboBox的占位符

时间:2019-02-22 01:22:09

标签: java swing jtable jcombobox

我有一个JTable,其中一个列(第1列)是一个JComboBox,它允许从列表中进行选项,并可以在其中输入新的选项。 MWE:

import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableColumn;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.HashSet;

public class ComboTableDemo extends JPanel {

    public ComboTableDemo() {
        super(new GridLayout(1,0));
        final String[] headings = {"Name", "Option"};
        final String string1 = "Foo";
        final String string2 = "Bar";
        Object[][] data = {
                {"Albert", string1},
                {"Bob", null},
                {"Clare", null},
                {"David", null}
        };

        final JTable table = new JTable(data, headings);
        table.setPreferredScrollableViewportSize(new Dimension(300, 100));
        table.setFillsViewportHeight(true);

        final String[] optionsInit = new String[] {string1, string2};
        HashSet<String> options = new HashSet<String>(Arrays.asList(optionsInit));
        JComboBox<String> optionsCombo = new JComboBox<String>(optionsInit);

        optionsCombo.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ev) {
                String newSelection = (String)optionsCombo.getSelectedItem();
                if(!options.contains(newSelection)) {
                    options.add(newSelection);
                    optionsCombo.addItem(newSelection);
                }
            }

        });
        optionsCombo.setEditable(true);
        TableColumn column = table.getColumnModel().getColumn(1);
        column.setCellEditor(new DefaultCellEditor(optionsCombo));

        add(new JScrollPane(table));
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("ComboTableDemo");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                ComboTableDemo pane = new ComboTableDemo();
                pane.setOpaque(true);
                frame.setContentPane(pane);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

在表中,用户可以并且应该为空条目输入值并不明显,因此我想添加占位符文本以使其清楚。我已经elsewhere看到,ListCellRenderer可以为自定义setRenderer提供ComboBoxEditor,如果组合是不可编辑的,则组合为可编辑的(如tutorial中所述),看来必须使用setEditor提供{{1}}。为此是否有一个简单的实现,或者甚至是达到相同目的的更好方法?

1 个答案:

答案 0 :(得分:0)

实际上,JTable中的输入组件具有特殊情况,因为它们仅在单元格被编辑时才处于活动状态。因此,除了设置编辑器以控制值的编辑方式外,还需要更改渲染器以控制如何显示所选值,

    // As before:
    TableColumn column = table.getColumnModel().getColumn(1);
    column.setCellEditor(new DefaultCellEditor(optionsCombo));
    // Additional line to set renderer:
    column.setCellRenderer(new PlaceholderRenderer("<choose or add option>"));

此处PlaceholderRenderer应该是TableCellRenderer的实现,当未选择任何值时,该实现将显示占位符字符串。例如:

import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;

public class PlaceholderRenderer extends DefaultTableCellRenderer {

    final private String placeholder;

    public PlaceholderRenderer(String placeholder) {
        super();
        this.placeholder = placeholder;
    }

    @Override
    public Component getTableCellRendererComponent(JTable table,
            Object value,
            boolean isSelected,
            boolean hasFocus,
            int row,
            int column) {
        if ((value == null) || (value.equals(""))) { 
            return super.getTableCellRendererComponent(table, this.placeholder, isSelected, hasFocus, row, column);  
        } else { 
            return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);  
        }
    }

}