问题描述
目前在用jtable做一个 属性编辑器,table就二列,一列属性名,一列属性值。 需要根据属性值动态生成编辑器(JComboBox、JCheckBox、JTextArea)。 基本功能已实现 现在存在如下问题: 1.JCheckBox显示没问题,但是点击时位置不正确(会跑到单元格最左边)。2.JTextArea显示有问题,没有一开始就换行显示,要编辑的时候才换行显示。 请大家帮忙看一下,谢谢大家了! import java.awt.BorderLayout;import java.awt.Component;import java.awt.Dimension;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.util.Vector;import javax.swing.AbstractCellEditor;import javax.swing.DefaultCellEditor;import javax.swing.DefaultListSelectionModel;import javax.swing.JButton;import javax.swing.JCheckBox;import javax.swing.JComboBox;import javax.swing.JFrame;import javax.swing.JScrollPane;import javax.swing.JTable;import javax.swing.JTextArea;import javax.swing.ListSelectionModel;import javax.swing.WindowConstants;import javax.swing.table.DefaultTableModel;import javax.swing.table.TableCellEditor;import javax.swing.table.TableCellRenderer;import javax.swing.table.TableColumnModel;public class PropertyJtable extends JTable {public PropertyJtable(Vector rowData, Vector columnNames) {super(rowData, columnNames);}public JComboBox getJComboBox() {JComboBox comboBox = new JComboBox();comboBox.addItem("red");comboBox.addItem("green");comboBox.addItem("blue");return comboBox;}public static void main(String[] args) {JFrame frame = new JFrame("属性编辑器");frame.setSize(250, 200);frame.setPreferredSize(new Dimension(250, 200));frame.setLayout(new BorderLayout());frame.setLocationRelativeTo(null);Vector title = new Vector();title.add("Property");title.add("Value");JTable jtable = new PropertyJtable(new Vector(), title);JScrollPane scrollPane = new JScrollPane(jtable);DefaultTableModel model = (DefaultTableModel) jtable.getModel();model.addRow(new Object[] { "name", "阿呆" });model.addRow(new Object[] { "是否显示", new Boolean(true) });model.addRow(new Object[] { "颜色1", "red" });model.addRow(new Object[] { "颜色2", "blue" });model.addRow(new Object[] { "年龄", "24" });model.addRow(new Object[] { "备注", "山东分n舵是否公司的n故事啊发放" });jtable.getColumnModel().getColumn(0).setPreferredWidth(50);jtable.getColumnModel().getColumn(1).setPreferredWidth(150);frame.add(scrollPane, BorderLayout.CENTER);JButton printButton = new JButton("关闭");frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);printButton.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent event) {System.exit(0);}});frame.add(printButton, BorderLayout.SOUTH);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);}// 根据值来设置单元格类型public TableCellEditor getCellEditor(int row, int col) {TableCellEditor editor = super.getCellEditor(row, col);// JCheckBoxif ("true".equals(getValueAt(row, col).toString())|| "false".equals(getValueAt(row, col).toString())) {// editor=super.getDefaultEditor(JCheckBox.class);editor = new DefaultCellEditor(new JCheckBox());}// JComboBoxif ("red".equals(getValueAt(row, col).toString())|| "green".equals(getValueAt(row, col).toString())|| "blue".equals(getValueAt(row, col).toString())) {editor = new DefaultCellEditor(getJComboBox());}// 字数大于10 使用JTextAreaif (getValueAt(row, col).toString().length() > 10) {editor = new JTextAreaEditor();}return editor;}// 单元格渲染public TableCellRenderer getCellRenderer(int row, int col) {TableCellRenderer renderer = super.getCellRenderer(row, col);if ("true".equals(getValueAt(row, col).toString())|| "false".equals(getValueAt(row, col).toString())) {renderer = super.getDefaultRenderer(Boolean.class);}return renderer;}// 第一行不可编辑public boolean isCellEditable(int row, int col) {return (col != 0);}/* * 重写方法 单选模式 (non-Javadoc) * * @see javax.swing.JTable#createDefaultSelectionModel() */protected ListSelectionModel createDefaultSelectionModel() {DefaultListSelectionModel defaultListSelectionModel = new DefaultListSelectionModel();defaultListSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);return defaultListSelectionModel;}class JTextAreaEditor extends AbstractCellEditor implements TableCellEditor {protected JTextArea myEditor;public Component getTableCellEditorComponent(JTable table,Object value, boolean isSelected, int row, int column) {if (null == myEditor) {myEditor = new JTextArea();}myEditor.setText((String) value);TableColumnModel columnModel = table.getColumnModel();myEditor.setSize(columnModel.getColumn(column).getWidth(), 5);int heightWanted = (int) myEditor.getPreferredSize().getHeight();if (heightWanted != table.getRowHeight(row)) {table.setRowHeight(row, heightWanted);}return myEditor;}@Overridepublic Object getCellEditorValue() {return myEditor.getText();}}} 问题补充:多谢huahuashijie888 的帮助!<br /><br /> JTextArea显示问题已解决,单独写了个渲染器。<br /><br /><br />2.关于jcheckbox跳到左边的问题,我以前也遇到到,好像只要该列值为boolean型,就不需要另写个render或者editor了。。会默认用jcheckbox展示 <br /><br />你说的这个问题 只能针对一列都是jcheckbox情况,我这要的是针对某个单元格来渲染。<br /><pre name="code" class="java">public Class getColumnClass(int c) {return getValueAt(0, c).getClass();}</pre><br /><br />现在我单独写了jcheckbox的Editor和Renderer,显示还是有问题:初始化正常,点击时也正常,不过一选择其他行jcheckbox直接就不见了,貌似变成 JTextField了 还可以录入东西。<br /><br /><br />现在的代码如下:<br /><br /><pre name="code" class="java">import java.awt.BorderLayout;import java.awt.Component;import java.awt.Dimension;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.util.Vector;import javax.swing.AbstractCellEditor;import javax.swing.DefaultCellEditor;import javax.swing.DefaultListSelectionModel;import javax.swing.JButton;import javax.swing.JCheckBox;import javax.swing.JComboBox;import javax.swing.JFrame;import javax.swing.JScrollPane;import javax.swing.JTable;import javax.swing.JTextArea;import javax.swing.JTextField;import javax.swing.ListSelectionModel;import javax.swing.SwingConstants;import javax.swing.WindowConstants;import javax.swing.table.DefaultTableModel;import javax.swing.table.TableCellEditor;import javax.swing.table.TableCellRenderer;import javax.swing.table.TableColumnModel;public class PropertyJtable extends JTable {public PropertyJtable(Vector rowData, Vector columnNames) {super(rowData, columnNames);}public JComboBox getJComboBox() {JComboBox comboBox = new JComboBox();comboBox.addItem("red");comboBox.addItem("green");comboBox.addItem("blue");return comboBox;}public static void main(String[] args) {JFrame frame = new JFrame("属性编辑器");frame.setSize(300, 250);frame.setPreferredSize(new Dimension(300, 250));frame.setLayout(new BorderLayout());frame.setLocationRelativeTo(null);Vector title = new Vector();title.add("Property");title.add("Value");JTable jtable = new PropertyJtable(new Vector(), title);JScrollPane scrollPane = new JScrollPane(jtable);DefaultTableModel model = (DefaultTableModel) jtable.getModel();model.addRow(new Object[] { "name", "阿呆" });model.addRow(new Object[] { "是否显示", new Boolean(true) });model.addRow(new Object[] { "颜色1", "red" });model.addRow(new Object[] { "颜色2", "blue" });model.addRow(new Object[] { "年龄", "24" });model.addRow(new Object[] { "备注", "山东分n舵是否公司的n故事啊发放" });jtable.getColumnModel().getColumn(0).setPreferredWidth(50);jtable.getColumnModel().getColumn(1).setPreferredWidth(150);frame.add(scrollPane, BorderLayout.CENTER);JButton printButton = new JButton("关闭");frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);printButton.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent event) {System.exit(0);}});frame.add(printButton, BorderLayout.SOUTH);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);}// 根据值来设置单元格类型public TableCellEditor getCellEditor(int row, int col) {TableCellEditor editor = super.getCellEditor(row, col);// JCheckBoxif ("true".equals(getValueAt(row, col).toString())|| "false".equals(getValueAt(row, col).toString())) {// editor=super.getDefaultEditor(JCheckBox.class);//editor = new DefaultCellEditor(new JCheckBox());editor = new JCheckBoxEditor();}// JComboBoxif ("red".equals(getValueAt(row, col).toString())|| "green".equals(getValueAt(row, col).toString())|| "blue".equals(getValueAt(row, col).toString())) {editor = new DefaultCellEditor(getJComboBox());}// 字数大于10 使用JTextAreaif (getValueAt(row, col).toString().length() > 10) {editor = new JTextAreaEditor();}return editor;}// 单元格渲染public TableCellRenderer getCellRenderer(int row, int col) {TableCellRenderer renderer = super.getCellRenderer(row, col);if ("true".equals(getValueAt(row, col).toString())|| "false".equals(getValueAt(row, col).toString())) {//renderer = super.getDefaultRenderer(Boolean.class);renderer = new JCheckBoxRenderer();}if (getValueAt(row, col).toString().length() > 10) {renderer = new JTextAreaRenderer();}return renderer;}// 第一行不可编辑public boolean isCellEditable(int row, int col) {return (col != 0);}/* * 重写方法 单选模式 (non-Javadoc) * * @see javax.swing.JTable#createDefaultSelectionModel() */protected ListSelectionModel createDefaultSelectionModel() {DefaultListSelectionModel defaultListSelectionModel = new DefaultListSelectionModel();defaultListSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);return defaultListSelectionModel;}class JTextAreaEditor extends AbstractCellEditor implements TableCellEditor {protected JTextArea myEditor;public Component getTableCellEditorComponent(JTable table,Object value, boolean isSelected, int row, int column) {if (null == myEditor) {myEditor = new JTextArea();}myEditor.setText((String) value);TableColumnModel columnModel = table.getColumnModel();myEditor.setSize(columnModel.getColumn(column).getWidth(), 5);int heightWanted = (int) myEditor.getPreferredSize().getHeight();if (heightWanted != table.getRowHeight(row)) {table.setRowHeight(row, heightWanted);}return myEditor;}@Overridepublic Object getCellEditorValue() {return myEditor.getText();}}class JTextAreaRenderer extends JTextArea implements TableCellRenderer {public JTextAreaRenderer() { setLineWrap(true); setWrapStyleWord(true); } public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) { // 计算当下行的最佳高度 int maxPreferredHeight = 0; for (int i = 0; i < table.getColumnCount(); i++) { setText("" + table.getValueAt(row, i)); setSize(table.getColumnModel().getColumn(column).getWidth(), 5); maxPreferredHeight = Math.max(maxPreferredHeight, getPreferredSize().height); } if (table.getRowHeight(row) != maxPreferredHeight) // 少了这行则不能重绘 table.setRowHeight(row, maxPreferredHeight); setText(value == null ? "" : value.toString()); return this; } } class JCheckBoxEditor extends AbstractCellEditor implements TableCellEditor {protected JCheckBox myEditor;public Component getTableCellEditorComponent(JTable table,Object value, boolean isSelected, int row, int column) {if (null == myEditor) {myEditor = new JCheckBox();}boolean selected = false; if (value instanceof Boolean) { selected = ((Boolean)value).booleanValue();}else if (value instanceof String) { selected = value.equals("true");}myEditor.setSelected(selected);myEditor.setHorizontalAlignment(SwingConstants.CENTER);return myEditor;}@Overridepublic Object getCellEditorValue() {return myEditor.getText();}}class JCheckBoxRenderer extends JCheckBox implements TableCellRenderer { public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) { boolean selected = false; if (value instanceof Boolean) { selected = ((Boolean)value).booleanValue();}else if (value instanceof String) { selected = value.equals("true");}this.setSelected(selected); this.setHorizontalAlignment(SwingConstants.CENTER); return this; } }}</pre>
解决方案
1.显示的时候你要自适应显示宽度高度,还需要对该列写个render,你写的render只是显示一个textarea组件,具体可以参考我写的class TableCellTextAreaRenderer extends JTextArea implements TableCellRenderer { public TableCellTextAreaRenderer() { setLineWrap(true); setWrapStyleWord(true); } public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) { // 计算当下行的最佳高度 int maxPreferredHeight = 0; for (int i = 0; i < table.getColumnCount(); i++) { setText("" + table.getValueAt(row, i)); setSize(table.getColumnModel().getColumn(column).getWidth(), 0); maxPreferredHeight = Math.max(maxPreferredHeight, getPreferredSize().height); } if (table.getRowHeight(row) != maxPreferredHeight) // 少了这行则不能重绘 table.setRowHeight(row, maxPreferredHeight); setText(value == null ? "" : value.toString()); return this; }}2.关于jcheckbox跳到左边的问题,我以前也遇到到,好像只要该列值为boolean型,就不需要另写个render或者editor了。。会默认用jcheckbox展示