无法使用 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();
}
}
从不 return 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 方法需要 return 该行的 实际数据值 :
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;
}
}
您的 TableModel 完全错误。
TableModel 的数据必须存储在 TableModel 中,而不是作为模型外部的数组。
不要扩展 AbstractTableModel。而是扩展 DefaultTableModel。 DefaultTableModel 已经提供了数据存储和更新每个单元格数据的方法。然后,您需要覆盖的唯一方法是 getColumnClass(...)
方法,以确保为每一列使用适当的 renderer/editor。
有关显示如何将初始数据添加到 JTable 的基本示例,请参阅:Sorting JTable programmatically。该示例中的 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:
的属性
table.setBackground(...);
table.setForeground(...);
table.setFont(...);
这些值将被每个默认的列渲染器使用。
下面的代码显示一个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();
}
}
从不 return 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 方法需要 return 该行的 实际数据值 :
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;
}
}
您的 TableModel 完全错误。
TableModel 的数据必须存储在 TableModel 中,而不是作为模型外部的数组。
不要扩展 AbstractTableModel。而是扩展 DefaultTableModel。 DefaultTableModel 已经提供了数据存储和更新每个单元格数据的方法。然后,您需要覆盖的唯一方法是 getColumnClass(...)
方法,以确保为每一列使用适当的 renderer/editor。
有关显示如何将初始数据添加到 JTable 的基本示例,请参阅:Sorting JTable programmatically。该示例中的 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:
的属性table.setBackground(...);
table.setForeground(...);
table.setFont(...);
这些值将被每个默认的列渲染器使用。