每行具有不同 JCombobox 的 JTable

JTable with different JCombobox for each line

我有一个 table 正在 运行 加载行。加载后,用户需要从每一行第一列的 JComboBox 中选择一个项目。然后他需要在每一行的同一行上从另一个 JComboBox 中选择一个项目。第二个JComboBox的含量取决于第一个JComboBox的select离子。

我现在的编码方式是更改整个第二列的组合框内容。

columnProfile.setCellEditor(new DefaultCellEditor(comboBoxProf))

有没有办法让每行的组合框对象都不同,这样我每次 select 第一个组合框中的值时都可以处理它?

直到用户点击提交,行数才固定。他可以添加和删除行。

我使用了来自 Oracle 的基本 Table 示例并进行了更改以反映我当前正在做的事情

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.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;


import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;


public class TableRenderDemo extends JPanel {
    private boolean DEBUG = false;
    JComboBox comboBox2;
    JComboBox comboBox1;
    public TableRenderDemo() {
        super(new GridLayout(1,0));

        JTable table = new JTable(new MyTableModel());
        table.setPreferredScrollableViewportSize(new Dimension(500, 70));
        table.setFillsViewportHeight(true);
        JScrollPane scrollPane = new JScrollPane(table);
        initColumnSizes(table);

        setUpSportColumn(table, table.getColumnModel().getColumn(2));
        setUpYearsColumn(table, table.getColumnModel().getColumn(3));

        add(scrollPane);
        table.getModel().addTableModelListener(new TableModelListener() {

            public void tableChanged(TableModelEvent e) {

                if (e.getColumn() == 2){
                    comboBox2.removeAllItems();
                    /*REFILL COMBOBOX WITH WHAT I NEED FOR THIS ROW ONLY*/
                }


            }
                  }); 
    }

    private void initColumnSizes(JTable table) {
        MyTableModel model = (MyTableModel)table.getModel();
        TableColumn column = null;
        Component comp = null;
        int headerWidth = 0;
        int cellWidth = 0;
        Object[] longValues = model.longValues;
        TableCellRenderer headerRenderer =
            table.getTableHeader().getDefaultRenderer();

        for (int i = 0; i < 5; i++) {
            column = table.getColumnModel().getColumn(i);

            comp = headerRenderer.getTableCellRendererComponent(
                                 null, column.getHeaderValue(),
                                 false, false, 0, 0);
            headerWidth = comp.getPreferredSize().width;

            comp = table.getDefaultRenderer(model.getColumnClass(i)).
                             getTableCellRendererComponent(
                                 table, longValues[i],
                                 false, false, 0, i);
            cellWidth = comp.getPreferredSize().width;

            if (DEBUG) {
                System.out.println("Initializing width of column "
                                   + i + ". "
                                   + "headerWidth = " + headerWidth
                                   + "; cellWidth = " + cellWidth);
            }

            column.setPreferredWidth(Math.max(headerWidth, cellWidth));
        }
    }

    public void setUpSportColumn(JTable table,
                                 TableColumn sportColumn) {
        //Set up the editor for the sport cells.
        comboBox1 = new JComboBox();
        comboBox1.addItem("Snowboarding");
        comboBox1.addItem("Rowing");
        comboBox1.addItem("Knitting");
        comboBox1.addItem("Speed reading");
        comboBox1.addItem("Pool");
        comboBox1.addItem("None of the above");
        sportColumn.setCellEditor(new DefaultCellEditor(comboBox1));


        DefaultTableCellRenderer renderer =
                new DefaultTableCellRenderer();
        renderer.setToolTipText("Click for combo box");
        sportColumn.setCellRenderer(renderer);
    }
    public void setUpYearsColumn(JTable table,
            TableColumn yearColumn) {

comboBox2 = new JComboBox();
comboBox2.addItem("1");
comboBox2.addItem("2");
comboBox2.addItem("3");
comboBox2.addItem("4");
comboBox2.addItem("5");
comboBox2.addItem("6");
yearColumn.setCellEditor(new DefaultCellEditor(comboBox2));

//Set up tool tips for the sport cells.
DefaultTableCellRenderer renderer =
new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
yearColumn.setCellRenderer(renderer);
}

    class MyTableModel extends AbstractTableModel {
        private String[] columnNames = {"First Name",
                                        "Last Name",
                                        "Sport",
                                        "# of Years",
                                        "Vegetarian"};
        private Object[][] data = {
        {"Kathy", "Smith",
         "Snowboarding", "1", new Boolean(false)},
        {"John", "Doe",
         "Rowing", "1", new Boolean(true)},
        {"Sue", "Black",
         "Knitting", "1", new Boolean(false)},
        {"Jane", "White",
         "Speed reading", "1", new Boolean(true)},
        {"Joe", "Brown",
         "Pool", "1", new Boolean(false)}
        };

        public final Object[] longValues = {"Jane", "Kathy",
                                            "None of the above",
                                            new Integer(20), Boolean.TRUE};

        public int getColumnCount() {
            return columnNames.length;
        }

        public int getRowCount() {
            return data.length;
        }

        public String getColumnName(int col) {
            return columnNames[col];
        }

        public Object getValueAt(int row, int col) {
            return data[row][col];
        }


        public Class getColumnClass(int c) {
            return getValueAt(0, c).getClass();
        }


        public boolean isCellEditable(int row, int col) {

            if (col < 2) {
                return false;
            } else {
                return true;
            }
        }


        public void setValueAt(Object value, int row, int col) {
            if (DEBUG) {
                System.out.println("Setting value at " + row + "," + col
                                   + " to " + value
                                   + " (an instance of "
                                   + value.getClass() + ")");
            }

            data[row][col] = value;
            fireTableCellUpdated(row, col);

            if (DEBUG) {
                System.out.println("New value of data:");
                printDebugData();
            }
        }

        private void printDebugData() {
            int numRows = getRowCount();
            int numCols = getColumnCount();

            for (int i=0; i < numRows; i++) {
                System.out.print("    row " + i + ":");
                for (int j=0; j < numCols; j++) {
                    System.out.print("  " + data[i][j]);
                }
                System.out.println();
            }
            System.out.println("--------------------------");
        }
    }


    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("TableRenderDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


        TableRenderDemo newContentPane = new TableRenderDemo();
        newContentPane.setOpaque(true); 
        frame.setContentPane(newContentPane);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {

        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

假设您将数据保存在 Map<String, List<String>> 中,地图的键表示第一个 JComboBox 保存的值,地图的值表示第二列的 JComboBox 保存的变化值(数据不需要以这种方式设置,但对于 MCVE/demonstration 目的来说很容易),并将此地图命名为 dataMap,那么您的列编辑器可能类似于:

    column1.setCellEditor(new DefaultCellEditor(combo1) {
        @SuppressWarnings("unchecked")
        @Override
        public Component getTableCellEditorComponent(JTable table, Object value,
                boolean isSelected, int row, int column) {

            // the items that will fill our JComboBox. Initially its empty
            Object[] items = new Object[]{};

            // get the value in the column to the left
            Object column0Value = table.getValueAt(row, column - 1);
            if (column0Value != null) {
                // if the value is not null, then get the map's values
                // and use it to fill our items array
                items = dataMap.get(column0Value).toArray();
            } 

            // get the super component, the JComboBox that is being used
            // as an editor:
            JComboBox<Object> superCombo = (JComboBox<Object>) super.getTableCellEditorComponent(table, value, isSelected,
                    row, column);

            // create a model and fill with items
            DefaultComboBoxModel<Object> comboModel = new DefaultComboBoxModel<>(items);

            // set the cell editor's model and return
            superCombo.setModel(comboModel);
            return superCombo;
        }
    });

例如,请检查此 MCVE 作为使用上述单元格编辑器的示例,并作为 MCVE 的示例在您以后的问题中运行良好

import java.awt.Component;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

@SuppressWarnings("serial")
public class TableWithMultCombos extends JPanel {
    private static final String[] COLUMN_NAMES = { "Day of Week", "Number" };
    private Map<String, List<String>> dataMap = new LinkedHashMap<>();
    private DefaultTableModel tblModel = new DefaultTableModel(COLUMN_NAMES, 5);
    private JTable table = new JTable(tblModel);
    private DefaultComboBoxModel<Object> combo2Model = new DefaultComboBoxModel<>();
    private JComboBox<Object> combo0 = null;
    private JComboBox<Object> combo1 = new JComboBox<>(combo2Model);

    public TableWithMultCombos() {
        dataMap.put("Monday", Arrays.asList(new String[] { "Mon - 1", "Mon - 2", "Mon - 3", "Mon - 4" }));
        dataMap.put("Tuesday", Arrays.asList(new String[] { "Tues - 1", "Tues - 2", "Tues - 3", "Tues - 4" }));
        dataMap.put("Wednesday", Arrays.asList(new String[] { "Wed - 1", "Wed - 2", "Wed - 3", "Wed - 4" }));
        dataMap.put("Thursday", Arrays.asList(new String[] { "Thurs - 1", "Thurs - 2", "Thurs - 3", "Thurs - 4" }));
        dataMap.put("Friday", Arrays.asList(new String[] { "Fri - 1", "Fri - 2", "Fri - 3", "Fri - 4" }));
        combo0 = new JComboBox<>(dataMap.keySet().toArray());

        TableColumn column0 = table.getColumnModel().getColumn(0);
        column0.setCellEditor(new DefaultCellEditor(combo0));

        TableColumn column1 = table.getColumnModel().getColumn(1);
        column1.setCellEditor(new DefaultCellEditor(combo1) {
            @SuppressWarnings("unchecked")
            @Override
            public Component getTableCellEditorComponent(JTable table, Object value,
                    boolean isSelected, int row, int column) {

                // the items that will fill our JComboBox. Initially its empty
                Object[] items = new Object[]{};

                // get the value in the column to the left
                Object column0Value = table.getValueAt(row, column - 1);
                if (column0Value != null) {
                    // if the value is not null, then get the map's values
                    // and use it to fill our items array
                    items = dataMap.get(column0Value).toArray();
                } 

                // get the super component, the JComboBox that is being used
                // as an editor:
                JComboBox<Object> superCombo = (JComboBox<Object>) super.getTableCellEditorComponent(table, value, isSelected,
                        row, column);

                // create a model and fill with items
                DefaultComboBoxModel<Object> comboModel = new DefaultComboBoxModel<>(items);

                // set the cell editor's model and return
                superCombo.setModel(comboModel);
                return superCombo;
            }
        });

        table.setFillsViewportHeight(true);
        add(new JScrollPane(table));
    }

    private static void createAndShowGui() {
        TableWithMultCombos mainPanel = new TableWithMultCombos();

        JFrame frame = new JFrame("TableWithMultCombos");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}