如同其它的Swing组件,JTable使用MVC(模型、试图、控制器)设计方式,将可视化组件(JTable实例)从其数据(TableModel实现)中分离出来。
·TableModel接口
1、TableModel为JTable提供
·显示的数据
·表格的维数
·表格中每一列所包含的数据类型
·应该显示的列标题
·是否允许编辑指定单元格的值
2、实现TableModel:
TableValues类
- importjavax.swing.table.AbstractTableModel;
- /**
- *注意:一般使用AbstractTableModel创建TableModel的实现,只有少量数据时使用DefaultTableModel,
- */
- publicclassTableValuesextendsAbstractTableModel{
- privatestaticfinallongserialVersionUID=-8430352919270533604L;
- publicfinalstaticintNAME=0;
- publicfinalstaticintGENDER=1;
- publicfinalstaticString[]columnNames={"姓名","性别"};
- publicObject[][]values={
- {"Cannel_2020",true},
- {"Lucy",false},
- {"韩梅",false},
- {"李雷",true},
- {"Jim",true}
- };
- publicintgetColumnCount(){
- returnvalues[0].length;
- }
- publicintgetRowCount(){
- returnvalues.length;
- }
- publicObjectgetValueAt(introwIndex,intcolumnIndex){
- returnvalues[rowIndex][columnIndex];
- }
- /**
- *设置列名
- */
- publicStringgetColumnName(intcolumn){
- returncolumnNames[column];
- }
- }
SimpleTableTest类
- importjava.awt.BorderLayout;
- importjava.awt.Container;
- importjavax.swing.JFrame;
- importjavax.swing.JScrollPane;
- importjavax.swing.JTable;
- importjavax.swing.table.TableColumn;
- importjavax.swing.table.TableColumnModel;
- publicclassSimpleTableTestextendsJFrame{
- privatestaticfinallongserialVersionUID=-4172876583187222326L;
- protectedJTabletable;
- publicSimpleTableTest(){
- Containerpane=getContentPane();
- pane.setLayout(newBorderLayout());
- TableValuestv=newTableValues();
- table=newJTable(tv);
- //设置行高
- table.setRowHeight(30);
- //必须把table放入JScrollPane才会有列名出现
- JScrollPanejsp=newJScrollPane(table);
- pane.add(jsp,BorderLayout.CENTER);
- }
- publicstaticvoidmain(String[]args){
- SimpleTableTeststt=newSimpleTableTest();
- stt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- stt.setSize(400,200);
- stt.setVisible(true);
- }
- }
运行结果:
·实现TableCellRenderer(单元格渲染器)接口
1、使表格“性别”一列的单元格出现JComboBox组件
GenderRenderer类
- importjava.awt.Component;
- importjavax.swing.JComboBox;
- importjavax.swing.JTable;
- importjavax.swing.table.TableCellRenderer;
- publicclassGenderRendererextendsJComboBoximplementsTableCellRenderer{
- privatestaticfinallongserialVersionUID=-8624401777277852691L;
- publicGenderRenderer(){
- super();
- addItem("男");
- addItem("女");
- }
- publicComponentgetTableCellRendererComponent(JTabletable,Objectvalue,
- booleanisSelected,booleanhasFocus,introw,intcolumn){
- if(isSelected){
- setForeground(table.getForeground());
- super.setBackground(table.getBackground());
- }else{
- setForeground(table.getForeground());
- setBackground(table.getBackground());
- }
- booleanisMale=((Boolean)value).booleanValue();
- setSelectedIndex(isMale?0:1);
- returnthis;
- }
- }
2、把SimpleTableTest类的构造函数改变如下:
- publicSimpleTableTest(){
- setTitle("FromCannel_2020'sblog(CSDN)");
- setLayout(newBorderLayout());
- TableValuestv=newTableValues();
- table=newJTable(tv);
- //设置行宽
- table.setRowHeight(30);
- TableColumnModeltcm=table.getColumnModel();
- TableColumntc=tcm.getColumn(TableValues.GENDER);
- //设置“性别”列的单元格渲染器(renderer)
- tc.setCellRenderer(newGenderRenderer());
- //必须把table放入JScrollPane才会有列名出现
- JScrollPanejsp=newJScrollPane(table);
- add(jsp,BorderLayout.CENTER);
- }
运行结果:
3、注意:渲染器实际上并没有像可视化组件添加到Container中那样添加到JTable实例中,即表格中不含有JComboBox实例。此时,是将唯一的JComboBox实例绘制(通过向paint()方法传递Graphics对象)到“性别”一列的每一个单元格所占用的区域中。
4、在TableValues添加如下代码(覆盖AbstractTableModel中的方法),使得JTable实例中单元格可以编辑:
- /**
- *设置单元格可以编辑
- */
- publicbooleanisCellEditable(introw,intcolumn){
- returntrue;
- }
然而此时对“性别”一列的单元格进行编辑,会出现如下情况:
这就得使用到单元格编辑器了。
·实现TableCellEditor(单元格编辑器)接口
1、
- importjava.awt.Component;
- importjava.util.EventObject;
- importjavax.swing.JComboBox;
- importjavax.swing.JTable;
- importjavax.swing.event.CellEditorListener;
- importjavax.swing.event.ChangeEvent;
- importjavax.swing.event.EventListenerList;
- importjavax.swing.table.TableCellEditor;
- publicclassGenderEditorextendsJComboBoximplementsTableCellEditor{
- privatestaticfinallongserialVersionUID=5860619160549087886L;
- //EventListenerList:保存EventListener列表的类。
- privateEventListenerListlistenerList=newEventListenerList();
- //ChangeEvent用于通知感兴趣的参与者事件源中的状态已发生更改。
- privateChangeEventchangeEvent=newChangeEvent(this);
- publicGenderEditor(){
- super();
- addItem("男");
- addItem("女");
- //请求终止编辑操作可以包含单元格的JTable收到,也可以从编辑器组件本身(如这里的JComboBox)获得
- /*addActionListener(newActionListener(){
- publicvoidactionPerformed(ActionEvente){
- System.out.println("ActionListener");
- //如同stopCellEditing,都是调用fireEditingStopped()方法
- fireEditingStopped();
- }
- });*/
- }
- publicvoidaddCellEditorListener(CellEditorListenerl){
- listenerList.add(CellEditorListener.class,l);
- }
- publicvoidremoveCellEditorListener(CellEditorListenerl){
- listenerList.remove(CellEditorListener.class,l);
- }
- privatevoidfireEditingStopped(){
- CellEditorListenerlistener;
- Object[]listeners=listenerList.getListenerList();
- for(inti=0;i<listeners.length;i++){
- if(listeners[i]==CellEditorListener.class){
- //之所以是i+1,是因为一个为CellEditorListener.class(Class对象),
- //接着的是一个CellEditorListener的实例
- listener=(CellEditorListener)listeners[i+1];
- //让changeEvent去通知编辑器已经结束编辑
- <spanstyle="white-space:pre"></span>//在editingStopped方法中,JTable调用getCellEditorValue()取回单元格的值,
- //并且把这个值传递给TableValues(TableModel)的setValueAt()
- listener.editingStopped(changeEvent);
- }
- }
- }
- publicvoidcancelCellEditing(){
- }
- /**
- *编辑其中一个单元格,再点击另一个单元格时,调用。-------------!!!!!
- */
- publicbooleanstopCellEditing(){
- //可以注释掉下面的fireEditingStopped();,然后在GenderEditor的构造函数中把
- //addActionListener()的注释去掉(这时请求终止编辑操作从JComboBox获得),
- System.out.println("编辑其中一个单元格,再点击另一个单元格时,调用。");
- fireEditingStopped();//请求终止编辑操作从JTable获得
- returntrue;
- }
- /**
- *为一个单元格初始化编辑时,getTableCellEditorComponent被调用
- */
- publicComponentgetTableCellEditorComponent(JTabletable,Objectvalue,
- booleanisSelected,introw,intcolumn){
- booleanisMale=((Boolean)value).booleanValue();
- setSelectedIndex(isMale?0:1);
- returnthis;
- }
- /**
- *询问编辑器它是否可以使用anEvent开始进行编辑。
- */
- publicbooleanisCellEditable(EventObjectanEvent){
- returntrue;
- }
- /**
- *如果应该选择正编辑的单元格,则返回true,否则返回false。
- */
- publicbooleanshouldSelectCell(EventObjectanEvent){
- returntrue;
- }
- /**
- *返回值传递给TableValue(TableModel)中的setValueAt()方法
- */
- publicObjectgetCellEditorValue(){
- returnnewBoolean(getSelectedIndex()==0?true:false);
- }
- }
2、把SimpleTableTest类的构造函数中
- tc.setCellRenderer(newGenderRenderer());
后面加入:
- //设置“性别”列的单元格编辑器(editor)
- tc.setCellEditor(newGenderEditor());
运行结果:
3、还有一点别忘了再在TableValues加入如下代码(原因:看第4的最后一点)
- /**
- *单元格被编辑完后,调用此方法更新值
- */
- publicvoidsetValueAt(Objectvalue,introw,intcolumn){
- values[row][column]=value;
- }
4、GenderEditor类的工作流程:
1)、调用TableCellEditor接口中的getTableCellEditorComponent()方法初始化编辑
2)、编辑当前的单元格,再点击另一个单元格时,调用CellEditor中的stopCellEditing(),通过fireEditingStopped()调用到editingStopped()。
3)、在editingStopped方法中,JTable调用getCellEditorValue()取回单元格的值,并且把这个值传递给TableValues(TableModel)的setValueAt()