`
huobengluantiao8
  • 浏览: 1031233 次
文章分类
社区版块
存档分类
最新评论

浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值

 
阅读更多

如同其它的Swing组件,JTable使用MVC(模型、试图、控制器)设计方式,将可视化组件(JTable实例)从其数据(TableModel实现)中分离出来。

·TableModel接口

1、TableModel为JTable提供

·显示的数据

·表格的维数

·表格中每一列所包含的数据类型

·应该显示的列标题

·是否允许编辑指定单元格的值

2、实现TableModel:

TableValues类

  1. importjavax.swing.table.AbstractTableModel;
  2. /**
  3. *注意:一般使用AbstractTableModel创建TableModel的实现,只有少量数据时使用DefaultTableModel,
  4. */
  5. publicclassTableValuesextendsAbstractTableModel{
  6. privatestaticfinallongserialVersionUID=-8430352919270533604L;
  7. publicfinalstaticintNAME=0;
  8. publicfinalstaticintGENDER=1;
  9. publicfinalstaticString[]columnNames={"姓名","性别"};
  10. publicObject[][]values={
  11. {"Cannel_2020",true},
  12. {"Lucy",false},
  13. {"韩梅",false},
  14. {"李雷",true},
  15. {"Jim",true}
  16. };
  17. publicintgetColumnCount(){
  18. returnvalues[0].length;
  19. }
  20. publicintgetRowCount(){
  21. returnvalues.length;
  22. }
  23. publicObjectgetValueAt(introwIndex,intcolumnIndex){
  24. returnvalues[rowIndex][columnIndex];
  25. }
  26. /**
  27. *设置列名
  28. */
  29. publicStringgetColumnName(intcolumn){
  30. returncolumnNames[column];
  31. }
  32. }

SimpleTableTest类

  1. importjava.awt.BorderLayout;
  2. importjava.awt.Container;
  3. importjavax.swing.JFrame;
  4. importjavax.swing.JScrollPane;
  5. importjavax.swing.JTable;
  6. importjavax.swing.table.TableColumn;
  7. importjavax.swing.table.TableColumnModel;
  8. publicclassSimpleTableTestextendsJFrame{
  9. privatestaticfinallongserialVersionUID=-4172876583187222326L;
  10. protectedJTabletable;
  11. publicSimpleTableTest(){
  12. Containerpane=getContentPane();
  13. pane.setLayout(newBorderLayout());
  14. TableValuestv=newTableValues();
  15. table=newJTable(tv);
  16. //设置行高
  17. table.setRowHeight(30);
  18. //必须把table放入JScrollPane才会有列名出现
  19. JScrollPanejsp=newJScrollPane(table);
  20. pane.add(jsp,BorderLayout.CENTER);
  21. }
  22. publicstaticvoidmain(String[]args){
  23. SimpleTableTeststt=newSimpleTableTest();
  24. stt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  25. stt.setSize(400,200);
  26. stt.setVisible(true);
  27. }
  28. }

运行结果:


·实现TableCellRenderer(单元格渲染器)接口

1、使表格“性别”一列的单元格出现JComboBox组件

GenderRenderer类

  1. importjava.awt.Component;
  2. importjavax.swing.JComboBox;
  3. importjavax.swing.JTable;
  4. importjavax.swing.table.TableCellRenderer;
  5. publicclassGenderRendererextendsJComboBoximplementsTableCellRenderer{
  6. privatestaticfinallongserialVersionUID=-8624401777277852691L;
  7. publicGenderRenderer(){
  8. super();
  9. addItem("男");
  10. addItem("女");
  11. }
  12. publicComponentgetTableCellRendererComponent(JTabletable,Objectvalue,
  13. booleanisSelected,booleanhasFocus,introw,intcolumn){
  14. if(isSelected){
  15. setForeground(table.getForeground());
  16. super.setBackground(table.getBackground());
  17. }else{
  18. setForeground(table.getForeground());
  19. setBackground(table.getBackground());
  20. }
  21. booleanisMale=((Boolean)value).booleanValue();
  22. setSelectedIndex(isMale?0:1);
  23. returnthis;
  24. }
  25. }

2、SimpleTableTest类的构造函数改变如下:

  1. publicSimpleTableTest(){
  2. setTitle("FromCannel_2020'sblog(CSDN)");
  3. setLayout(newBorderLayout());
  4. TableValuestv=newTableValues();
  5. table=newJTable(tv);
  6. //设置行宽
  7. table.setRowHeight(30);
  8. TableColumnModeltcm=table.getColumnModel();
  9. TableColumntc=tcm.getColumn(TableValues.GENDER);
  10. //设置“性别”列的单元格渲染器(renderer)
  11. tc.setCellRenderer(newGenderRenderer());
  12. //必须把table放入JScrollPane才会有列名出现
  13. JScrollPanejsp=newJScrollPane(table);
  14. add(jsp,BorderLayout.CENTER);
  15. }

运行结果:


3、注意:渲染器实际上并没有像可视化组件添加到Container中那样添加到JTable实例中,即表格中不含有JComboBox实例。此时,是将唯一的JComboBox实例绘制(通过向paint()方法传递Graphics对象)到“性别”一列的每一个单元格所占用的区域中。

4、在TableValues添加如下代码(覆盖AbstractTableModel中的方法),使得JTable实例中单元格可以编辑:

  1. /**
  2. *设置单元格可以编辑
  3. */
  4. publicbooleanisCellEditable(introw,intcolumn){
  5. returntrue;
  6. }

然而此时对“性别”一列的单元格进行编辑,会出现如下情况:


这就得使用到单元格编辑器了。

·实现TableCellEditor(单元格编辑器)接口

1、

  1. importjava.awt.Component;
  2. importjava.util.EventObject;
  3. importjavax.swing.JComboBox;
  4. importjavax.swing.JTable;
  5. importjavax.swing.event.CellEditorListener;
  6. importjavax.swing.event.ChangeEvent;
  7. importjavax.swing.event.EventListenerList;
  8. importjavax.swing.table.TableCellEditor;
  9. publicclassGenderEditorextendsJComboBoximplementsTableCellEditor{
  10. privatestaticfinallongserialVersionUID=5860619160549087886L;
  11. //EventListenerList:保存EventListener列表的类。
  12. privateEventListenerListlistenerList=newEventListenerList();
  13. //ChangeEvent用于通知感兴趣的参与者事件源中的状态已发生更改。
  14. privateChangeEventchangeEvent=newChangeEvent(this);
  15. publicGenderEditor(){
  16. super();
  17. addItem("男");
  18. addItem("女");
  19. //请求终止编辑操作可以包含单元格的JTable收到,也可以从编辑器组件本身(如这里的JComboBox)获得
  20. /*addActionListener(newActionListener(){
  21. publicvoidactionPerformed(ActionEvente){
  22. System.out.println("ActionListener");
  23. //如同stopCellEditing,都是调用fireEditingStopped()方法
  24. fireEditingStopped();
  25. }
  26. });*/
  27. }
  28. publicvoidaddCellEditorListener(CellEditorListenerl){
  29. listenerList.add(CellEditorListener.class,l);
  30. }
  31. publicvoidremoveCellEditorListener(CellEditorListenerl){
  32. listenerList.remove(CellEditorListener.class,l);
  33. }
  34. privatevoidfireEditingStopped(){
  35. CellEditorListenerlistener;
  36. Object[]listeners=listenerList.getListenerList();
  37. for(inti=0;i<listeners.length;i++){
  38. if(listeners[i]==CellEditorListener.class){
  39. //之所以是i+1,是因为一个为CellEditorListener.class(Class对象),
  40. //接着的是一个CellEditorListener的实例
  41. listener=(CellEditorListener)listeners[i+1];
  42. //让changeEvent去通知编辑器已经结束编辑
  43. <spanstyle="white-space:pre"></span>//在editingStopped方法中,JTable调用getCellEditorValue()取回单元格的值,
  44. //并且把这个值传递给TableValues(TableModel)的setValueAt()
  45. listener.editingStopped(changeEvent);
  46. }
  47. }
  48. }
  49. publicvoidcancelCellEditing(){
  50. }
  51. /**
  52. *编辑其中一个单元格,再点击另一个单元格时,调用。-------------!!!!!
  53. */
  54. publicbooleanstopCellEditing(){
  55. //可以注释掉下面的fireEditingStopped();,然后在GenderEditor的构造函数中把
  56. //addActionListener()的注释去掉(这时请求终止编辑操作从JComboBox获得),
  57. System.out.println("编辑其中一个单元格,再点击另一个单元格时,调用。");
  58. fireEditingStopped();//请求终止编辑操作从JTable获得
  59. returntrue;
  60. }
  61. /**
  62. *为一个单元格初始化编辑时,getTableCellEditorComponent被调用
  63. */
  64. publicComponentgetTableCellEditorComponent(JTabletable,Objectvalue,
  65. booleanisSelected,introw,intcolumn){
  66. booleanisMale=((Boolean)value).booleanValue();
  67. setSelectedIndex(isMale?0:1);
  68. returnthis;
  69. }
  70. /**
  71. *询问编辑器它是否可以使用anEvent开始进行编辑。
  72. */
  73. publicbooleanisCellEditable(EventObjectanEvent){
  74. returntrue;
  75. }
  76. /**
  77. *如果应该选择正编辑的单元格,则返回true,否则返回false。
  78. */
  79. publicbooleanshouldSelectCell(EventObjectanEvent){
  80. returntrue;
  81. }
  82. /**
  83. *返回值传递给TableValue(TableModel)中的setValueAt()方法
  84. */
  85. publicObjectgetCellEditorValue(){
  86. returnnewBoolean(getSelectedIndex()==0?true:false);
  87. }
  88. }

2、SimpleTableTest类的构造函数中

  1. tc.setCellRenderer(newGenderRenderer());

后面加入:

  1. //设置“性别”列的单元格编辑器(editor)
  2. tc.setCellEditor(newGenderEditor());

运行结果:


3、还有一点别忘了再在TableValues加入如下代码(原因:看第4的最后一点

  1. /**
  2. *单元格被编辑完后,调用此方法更新值
  3. */
  4. publicvoidsetValueAt(Objectvalue,introw,intcolumn){
  5. values[row][column]=value;
  6. }

4、GenderEditor类的工作流程:

1)、调用TableCellEditor接口中的getTableCellEditorComponent()方法初始化编辑

2)、编辑当前的单元格,再点击另一个单元格时,调用CellEditor中的stopCellEditing(),通过fireEditingStopped()调用到editingStopped()。

3)、在editingStopped方法中,JTable调用getCellEditorValue()取回单元格的值,并且把这个值传递给TableValues(TableModel)的setValueAt()


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics