【问题标题】:Cannot display JComboBox in JTable with TableModel无法使用 TableModel 在 JTable 中显示 JComboBox
【发布时间】:2021-01-19 00:20:53
【问题描述】:

下面的代码显示JTable 3 列,分别包含JComboBoxStringdouble,应该显示为黄色。问题是我无法让第一列中的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();
    }
}

【问题讨论】:

  • 你需要在 getTableCellRendererComponent() 中返回你想要渲染的组合框,而不是 super 方法提供的默认值
  • 你还没有“接受”一个答案。
  • 我该怎么做?
  • @mkemper 我给了你上面的链接:“当有人回答我的问题时我该怎么办”。

标签: java swing jtable


【解决方案1】:

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

您的 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];
}

单元格渲染器是视图的一部分,而不是模型的一部分,因此它可以使用 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;
    }
}

【讨论】:

  • 谢谢!它现在基本上可以工作了,但是现在第 0 列中的两个 ComboBox 已经“死”了。例如,当我单击第一个(显示“aaa”)时,什么也没有发生 - 我无法选择第二个“bbb”选项。我该如何解决这个问题?谢谢!
  • 我建议为编辑器制作一个单独的 JComboBox,而不是尝试在渲染器和编辑器之间共享一个 JComboBox。请记住,您的 TableModel 必须覆盖其 isCellEditable 方法。
【解决方案2】:

您的 TableModel 完全错误。

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

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

请参阅:Sorting JTable programmatically 了解如何将初始数据添加到 JTable 的基本示例。该示例中的getColumnClass(...) 方法更通用。

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

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

然后,如果您希望第一列的编辑器成为您可以使用的组合框:

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

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

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

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

这些值将被每个默认列渲染器使用。

【讨论】:

  • 感谢您的建议,虽然我不同意所有建议。例如,TableModel 可以使用外部数组。现在扩展 AbstractTableModel 对我来说也很好。我唯一需要更改的是第一响应者的两个第一建议:(1)TableModel 的 getColumnClass 方法不应返回 JComboBox.class 和(2)tableModel 的
  • (抱歉)TableModel 的 getValueAt 方法不应返回 JComboBox,而是返回由该 JComboBox 显示的字符串。我不同意第一响应者的第三个建议。我只做了两个改变,对我来说一切正常。再次感谢所有回复此问题的人。
  • 例如,TableModel 可以使用外部数组。 - 当然代码会编译,但这是完全错误的。这完全打破了 Swing 组件的模型-视图-控制器设计。模型的工作是 a) 存储数据,b) 更新数据,c) 每当数据发生变化时通知视图。 虽然我不同意所有的观点 - 你不明白 Swing 是如何设计的,所以你不能真正做出明智的决定。我们不会花时间给出糟糕的建议。我们努力推广正确的设计实践。
  • 我的误解。当您写“TableModel 的数据必须存储在 TableModel 中”时,我理解这意味着如果您不这样做,它将无法工作。显然不是这样。您当然的意思是(我现在知道)您不应该将数据存储在数据模型之外。现在我明白了,将不得不相应地重新开始。对不起!
猜你喜欢
  • 1970-01-01
  • 2016-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多