繁体   English   中英

无法使用 TableModel 在 JTable 中显示 JComboBox

[英]Cannot display JComboBox in JTable with TableModel

下面的代码显示一个JTable有 3 列,分别包含一个JComboBox ,一个String和一个double ,应该显示黄色。 问题是我无法让第一列中的JComboBox显示为...一个组合框; 相反,我得到一个String说“ javax.swing.JComboBox... ”。 我究竟做错了什么?

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableModel;
import java.awt.*;

public class BadDialog extends JDialog {
    //Instantiate the data for the table, which is 2 rows x 3 cols
    private final JComboBox col0ComboBox = new JComboBox(new String[]{"aaa", "bbb"}); //Goes in all rows of Col 0
    private final String[] col1Data = {"Mickey", "Mouse"};
    private final double[] col2Data = {111, 222};

    public BadDialog() {
        //Instantiate table
        JTable badTable = new JTable();

        //Assign a tableModel to the table, put the table in a scroller, add it to this dialog, and sort out the renderer
        TableModel badTableModel = new BadTableModel();
        badTable.setModel(badTableModel);
        JScrollPane scroller = new JScrollPane(badTable);
        add(scroller);
        BadTableCellRenderer badTableCellRenderer = new BadTableCellRenderer();
        badTable.setDefaultRenderer(JComboBox.class, badTableCellRenderer); //Col 0
        badTable.setDefaultRenderer(String.class, badTableCellRenderer); //Col 1
        badTable.setDefaultRenderer(Double.class, badTableCellRenderer); //Col 2

        //Assign col0ComboBox to Col 0
        badTable.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(col0ComboBox));

        //Show the dialog
        setPreferredSize(new Dimension(300, 470));
        pack();
        setModal(true);
        setLocation(10, 10);
        setVisible(true);
    }

    private final class BadTableModel extends AbstractTableModel {
        @Override
        public int getRowCount() {
            return 2;
        }

        @Override
        public int getColumnCount() {
            return 3;
        }

        @Override
        public Object getValueAt(int rowIndex, int colIndex) {
            if (colIndex == 0) return col0ComboBox;
            if (colIndex == 1) return col1Data[rowIndex];
            return col2Data[rowIndex];
        }

        @Override
        public Class<?> getColumnClass(int colIndex) {
            if (colIndex == 0) return JComboBox.class;
            if (colIndex == 1) return String.class;
            return Double.class;
        }
    }

    private static class BadTableCellRenderer extends DefaultTableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
            Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);

            //Make all columns yellow
            c.setBackground(Color.YELLOW);
            c.setForeground(Color.RED);
            c.setFont(new Font("Dialog", Font.PLAIN, 12));
            return c;
        }
    }

    public static void main(String[] args) {
        new BadDialog();
    }
}

永远不要在 TableModel 中返回组件。 拥有一个单独的 model 和视图的全部意义在于 model 仅包含数据,不包含组件。 模型的工作是提供数据; 视图的工作是确定如何显示该数据。

您的 TableModel 的 getColumnClass 方法应如下所示:

public Class<?> getColumnClass(int colIndex) {
    if (colIndex == 0) return String.class; // String, not JComboBox
    if (colIndex == 1) return String.class;
    return Double.class;
}

并且您的 getValueAt 方法需要返回该行的实际数据值

public Object getValueAt(int rowIndex, int colIndex) {
    if (colIndex == 0) return (rowIndex % 1 == 0 ? "aaa" : "bbb");
    if (colIndex == 1) return col1Data[rowIndex];
    return col2Data[rowIndex];
}

单元格渲染器是视图的一部分,而不是 model,因此它可以使用 JComboBox。 您的渲染需要使用value参数来修改您的 JComboBox:

private static class BadTableCellRenderer extends DefaultTableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
        if (row != 0) {
            return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
        }

        JComboBox c = col0ComboBox;
        c.setSelectedItem(value);

        //Make all columns yellow
        c.setBackground(Color.YELLOW);
        c.setForeground(Color.RED);
        c.setFont(new Font("Dialog", Font.PLAIN, 12));

        return c;
    }
}

您的 TableModel 完全错误。

TableModel 的数据必须存储在 TableModel 中,而不是作为 model 外部的 Array。

不要扩展 AbstractTableModel。 而是扩展 DefaultTableModel。 DefaultTableModel 已经提供了数据存储和方法来更新每个单元格的数据。 然后,您需要覆盖的唯一方法是getColumnClass(...)方法,以确保为每一列使用适当的渲染器/编辑器。

请参阅: 以编程方式对 JTable 进行排序,以获取显示如何将初始数据添加到 JTable 的基本示例。 该示例中的getColumnClass(...)方法更通用。

您可以按如下方式简化 getColumnClass(...) 方法:

@Override
public Class getColumnClass(int column)
{
    switch (column)
    {
        case 2: return Double.class;
        default: return super.getColumnClass(column);
    }
}

然后,如果您希望第一列的编辑器是 combobox,您可以使用:

badTable.getColumnModel().getColumn(0).setCellEditor( new DefaultCellEditor(col0ComboBox));

您不应该对所有 3 列使用相同的渲染器,因为通常数字在列中右对齐显示。

应该不需要自定义渲染器。 相反,您更改表的属性:

table.setBackground(...);
table.setForeground(...);
table.setFont(...);

然后,每个默认列渲染器将使用这些值。

暂无
暂无

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

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