简体   繁体   English

JTable和自定义JComboBox

[英]JTable and custom JComboBox

I want to implement a custom JComboBox as an CellEditor for a JTable. 我想实现一个自定义JComboBox作为JTable的CellEditor。 I took the original Java Example and modified it by implementing a Sports class 我采用了原始的Java示例并通过实现Sports类对其进行了修改

Please run the source code, click on the JComboBox and you will note that the selected item is not selected anymore when the ComboBox opens. 请运行源代码,单击JComboBox,您会注意到在打开ComboBox时不再选择选定的项目。 I want to keep the renderered item in the combobox selection. 我想将渲染的项目保留在组合框选择中。

Original: http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#combobox 原文: http : //docs.oracle.com/javase/tutorial/uiswing/components/table.html#combobox

public class Sport {
    private Integer id;
    private String name;

    public Sport(String name){
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

     public String toString() {
        return this.name;
    }
}



public class TableRenderDemo extends JPanel {
    private boolean DEBUG = false;

public TableRenderDemo() {
    super(new GridLayout(1,0));

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

    //Create the scroll pane and add the table to it.
    JScrollPane scrollPane = new JScrollPane(table);

    //Set up column sizes.
    initColumnSizes(table);

    //Fiddle with the Sport column's cell editors/renderers.
    setUpSportColumn(table, table.getColumnModel().getColumn(2));

    //Add the scroll pane to this panel.
    add(scrollPane);
}

/*
 * This method picks good column sizes.
 * If all column heads are wider than the column's cells'
 * contents, then you can just use column.sizeWidthToFit().
 */
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.
    JComboBox comboBox = new JComboBox();
    comboBox.addItem("Snowboarding");
    comboBox.addItem("Rowing");
    comboBox.addItem("Knitting");
    comboBox.addItem("Speed reading");
    comboBox.addItem("Pool");
    comboBox.addItem("None of the above");
    sportColumn.setCellEditor(new DefaultCellEditor(comboBox));

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

class MyTableModel extends AbstractTableModel {
    private String[] columnNames = {"First Name",
                                    "Last Name",
                                    "Sport",
                                    "# of Years",
                                    "Vegetarian"};
    private Object[][] data = {
    {"Kathy", "Smith",new Sport("Snowboarding"),
            new Integer(5), new Boolean(false)},
    {"John", "Doe",
     new Sport("Rowing"), new Integer(3), new Boolean(true)},
    {"Sue", "Black",
     new Sport("Knitting"), new Integer(2), new Boolean(false)},
    {"Jane", "White",
     new Sport("Speed reading"), new Integer(20), new Boolean(true)},
    {"Joe", "Brown",
     new Sport("Pool"), new Integer(10), 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];
    }

    /*
     * JTable uses this method to determine the default renderer/
     * editor for each cell.  If we didn't implement this method,
     * then the last column would contain text ("true"/"false"),
     * rather than a check box.
     */
    public Class getColumnClass(int c) {
        return getValueAt(0, c).getClass();
    }

    /*
     * Don't need to implement this method unless your table's
     * editable.
     */
    public boolean isCellEditable(int row, int col) {
        //Note that the data/cell address is constant,
        //no matter where the cell appears onscreen.
        if (col < 2) {
            return false;
        } else {
            return true;
        }
    }

    /*
     * Don't need to implement this method unless your table's
     * data can change.
     */
    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("--------------------------");
    }
}

/**
 * Create the GUI and show it.  For thread safety,
 * this method should be invoked from the
 * event-dispatching thread.
 */
private static void createAndShowGUI() {
    //Create and set up the window.
    JFrame frame = new JFrame("TableRenderDemo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //Create and set up the content pane.
    TableRenderDemo newContentPane = new TableRenderDemo();
    newContentPane.setOpaque(true); //content panes must be opaque
    frame.setContentPane(newContentPane);

    //Display the window.
    frame.pack();
    frame.setVisible(true);
}

public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
}
}

Ok I included the following, but still the same problem: 好的,我包括以下内容,但仍然是相同的问题:

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

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

Your model contains instances of Sport class but the JCombobox contains strings. 您的模型包含Sport类的实例,但JCombobox包含字符串。 That's why set selection can't find proper value. 这就是为什么集合选择找不到合适的值。

Try to add sports like this 尝试像这样添加运动

 comboBox.addItem(new Sport("Rowing"));

And either override toString() method of Sport class to return the name (easier way). 并且可以重写Sport类的toString()方法以返回名称(更简便的方法)。 Or add a custom renderer to the sports combo box. 或向运动组合框添加自定义渲染器。

You also need to override the equals(...) and hashcode(...) methods of the Sport class. 您还需要重写Sport类的equals(...)hashcode(...)方法。 Java Collection methods rely on these methods to determine equality of a object instance when doing searches. Java Collection方法在进行搜索时依靠这些方法来确定对象实例的相等性。

@Override
public boolean equals(Object object)
{
    Sport sport = (Sport)object;
    return this.name.equals( sport.getName() );
}

@Override
public int hashCode()
{
    return name.hashCode();
}

Also, read the Object API for more information on these methods. 另外,请阅读Object API,以获取有关这些方法的更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM