当前位置: 移动技术网 > IT编程>开发语言>Java > Java Swing实现JTable检测单元格数据变更事件的方法示例

Java Swing实现JTable检测单元格数据变更事件的方法示例

2019年07月19日  | 移动技术网IT编程  | 我要评论
本文实例讲述了java swing实现jtable检测单元格数据变更事件的方法。分享给大家供大家参考,具体如下: 在jtable的初级教程中往往会提到,使用tablemo

本文实例讲述了java swing实现jtable检测单元格数据变更事件的方法。分享给大家供大家参考,具体如下:

在jtable的初级教程中往往会提到,使用tablemodel的 addtablemodellistener方法可以监听单元格数据的变更,在其事件处理函,数tablechanged中,可以通过e.getcolumn()e.getfirstrow()e.getlastrow()e.gettype()来获取变更发生的位置和变更的类型(插入、更新或删除)。然而该方法存在2个致命的问题:

1.双击单元格使其处于可编辑状态后,即使没有做出任何修改,当单元格失去焦点时,该事件将被激活。

2.通过该事件你可以获取单元格最新的数据,却无法获取原有数据。

经过一番搜索发现该文章已经解决了这个问题table cell listener,作者自己实现了一个单元格监听器tablecelllistener,它订阅了指定table的addpropertychangelistener,根据e.getpropertyname()来识别单元格编辑事件,根据table.isediting()方法来判断单元格正在编辑还是编辑完毕。如果是正在编辑,则记录单元格位置和原因数据;如果已经编辑完毕,则记录新数据并与原有数据进行比对,如果不一致则说明单元格数据发生了变更,则激活指定响应函数。

测试用例如下:

tabledemo.java

/*
 * copyright (c) 1995, 2008, oracle and/or its affiliates. all rights reserved.
 *
 * redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  - redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 *  - redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 *  - neither the name of oracle or the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * this software is provided by the copyright holders and contributors "as
 * is" and any express or implied warranties, including, but not limited to,
 * the implied warranties of merchantability and fitness for a particular
 * purpose are disclaimed. in no event shall the copyright owner or
 * contributors be liable for any direct, indirect, incidental, special,
 * exemplary, or consequential damages (including, but not limited to,
 * procurement of substitute goods or services; loss of use, data, or
 * profits; or business interruption) however caused and on any theory of
 * liability, whether in contract, strict liability, or tort (including
 * negligence or otherwise) arising in any way out of the use of this
 * software, even if advised of the possibility of such damage.
 */
package awtdemo;
/*
 * tabledemo.java requires no other files.
 */
import javax.swing.abstractaction;
import javax.swing.action;
import javax.swing.jframe;
import javax.swing.jpanel;
import javax.swing.jscrollpane;
import javax.swing.jtable;
import javax.swing.table.abstracttablemodel;
import java.awt.dimension;
import java.awt.gridlayout;
import java.awt.event.actionevent;
/** 
 * tabledemo is just like simpletabledemo, except that it
 * uses a custom tablemodel.
 */
@suppresswarnings("serial")
public class tabledemo extends jpanel {
  private boolean debug = false;
  @suppresswarnings("unused")
 public tabledemo() {
    super(new gridlayout(1,0));
    jtable table = new jtable(new mytablemodel());
    table.setpreferredscrollableviewportsize(new dimension(500, 70));
    table.setfillsviewportheight(true);
    //create the scroll pane and add the table to it.
    jscrollpane scrollpane = new jscrollpane(table);
    //add the scroll pane to this panel.
    add(scrollpane);
    action action = new abstractaction()
    {
      public void actionperformed(actionevent e)
      {
        tablecelllistener tcl = (tablecelllistener)e.getsource();
        system.out.printf("cell changed%n");
        system.out.println("row  : " + tcl.getrow());
        system.out.println("column: " + tcl.getcolumn());
        system.out.println("old  : " + tcl.getoldvalue());
        system.out.println("new  : " + tcl.getnewvalue());
      }
    };
    tablecelllistener tcl = new tablecelllistener(table, action);
  }
  class mytablemodel extends abstracttablemodel {
    private string[] columnnames = {"first name",
                    "last name",
                    "sport",
                    "# of years",
                    "vegetarian"};
    private object[][] data = {
    {"kathy", "smith",
     "snowboarding", new integer(5), new boolean(false)},
    {"john", "doe",
     "rowing", new integer(3), new boolean(true)},
    {"sue", "black",
     "knitting", new integer(2), new boolean(false)},
    {"jane", "white",
     "speed reading", new integer(20), new boolean(true)},
    {"joe", "brown",
     "pool", new integer(10), new boolean(false)}
    };
    public int getcolumncount() {
      return columnnames.length;
    }
    public int getrowcount() {
      return data.length;
    }
    public string getcolumnname(int col) {
      return columnnames[col];
    }
    public object getvalueat(int row, int col) {
      return data[row][col];
    }
    /*
     * jtable uses this method to determine the default renderer/
     * editor for each cell. if we didn't implement this method,
     * then the last column would contain text ("true"/"false"),
     * rather than a check box.
     */
    @suppresswarnings({ "unchecked", "rawtypes" })
 public class getcolumnclass(int c) {
      return getvalueat(0, c).getclass();
    }
    /*
     * don't need to implement this method unless your table's
     * editable.
     */
    public boolean iscelleditable(int row, int col) {
      //note that the data/cell address is constant,
      //no matter where the cell appears onscreen.
      if (col < 2) {
        return false;
      } else {
        return true;
      }
    }
    /*
     * don't need to implement this method unless your table's
     * data can change.
     */
    public void setvalueat(object value, int row, int col) {
      if (debug) {
        system.out.println("setting value at " + row + "," + col
                  + " to " + value
                  + " (an instance of "
                  + value.getclass() + ")");
      }
      data[row][col] = value;
      firetablecellupdated(row, col);
      if (debug) {
        system.out.println("new value of data:");
        printdebugdata();
      }
    }
    private void printdebugdata() {
      int numrows = getrowcount();
      int numcols = getcolumncount();
      for (int i=0; i < numrows; i++) {
        system.out.print("  row " + i + ":");
        for (int j=0; j < numcols; j++) {
          system.out.print(" " + data[i][j]);
        }
        system.out.println();
      }
      system.out.println("--------------------------");
    }
  }
  /**
   * create the gui and show it. for thread safety,
   * this method should be invoked from the
   * event-dispatching thread.
   */
  private static void createandshowgui() {
    //create and set up the window.
    jframe frame = new jframe("tabledemo - www.jb51.net");
    frame.setdefaultcloseoperation(jframe.exit_on_close);
    //create and set up the content pane.
    tabledemo newcontentpane = new tabledemo();
    newcontentpane.setopaque(true); //content panes must be opaque
    frame.setcontentpane(newcontentpane);
    //display the window.
    frame.pack();
    frame.setvisible(true);
  }
  public static void main(string[] args) {
    //schedule a job for the event-dispatching thread:
    //creating and showing this application's gui.
    javax.swing.swingutilities.invokelater(new runnable() {
      public void run() {
        createandshowgui();
      }
    });
  }
}

tablecelllistener.java

package awtdemo;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
/*
 * this class listens for changes made to the data in the table via the
 * tablecelleditor. when editing is started, the value of the cell is saved
 * when editing is stopped the new value is saved. when the oold and new
 * values are different, then the provided action is invoked.
 *
 * the source of the action is a tablecelllistener instance.
 */
public class tablecelllistener implements propertychangelistener, runnable
{
  private jtable table;
  private action action;
  private int row;
  private int column;
  private object oldvalue;
  private object newvalue;
  /**
   * create a tablecelllistener.
   *
   * @param table  the table to be monitored for data changes
   * @param action the action to invoke when cell data is changed
   */
  public tablecelllistener(jtable table, action action)
  {
    this.table = table;
    this.action = action;
    this.table.addpropertychangelistener( this );
  }
  /**
   * create a tablecelllistener with a copy of all the data relevant to
   * the change of data for a given cell.
   *
   * @param row the row of the changed cell
   * @param column the column of the changed cell
   * @param oldvalue the old data of the changed cell
   * @param newvalue the new data of the changed cell
   */
  private tablecelllistener(jtable table, int row, int column, object oldvalue, object newvalue)
  {
    this.table = table;
    this.row = row;
    this.column = column;
    this.oldvalue = oldvalue;
    this.newvalue = newvalue;
  }
  /**
   * get the column that was last edited
   *
   * @return the column that was edited
   */
  public int getcolumn()
  {
    return column;
  }
  /**
   * get the new value in the cell
   *
   * @return the new value in the cell
   */
  public object getnewvalue()
  {
    return newvalue;
  }
  /**
   * get the old value of the cell
   *
   * @return the old value of the cell
   */
  public object getoldvalue()
  {
    return oldvalue;
  }
  /**
   * get the row that was last edited
   *
   * @return the row that was edited
   */
  public int getrow()
  {
    return row;
  }
  /**
   * get the table of the cell that was changed
   *
   * @return the table of the cell that was changed
   */
  public jtable gettable()
  {
    return table;
  }
//
// implement the propertychangelistener interface
//
  @override
  public void propertychange(propertychangeevent e)
  {
    // a cell has started/stopped editing
    if ("tablecelleditor".equals(e.getpropertyname()))
    {
      if (table.isediting()){
        //system.out.printf("tablecelleditor is editing..%n");
        processeditingstarted();
      }
      else{
        //system.out.printf("tablecelleditor editing stopped..%n");
        processeditingstopped();
      }
    }
  }
  /*
   * save information of the cell about to be edited
   */
  private void processeditingstarted()
  {
    // the invokelater is necessary because the editing row and editing
    // column of the table have not been set when the "tablecelleditor"
    // propertychangeevent is fired.
    // this results in the "run" method being invoked
    swingutilities.invokelater( this );
  }
  /*
   * see above.
   */
  @override
  public void run()
  {
    row = table.convertrowindextomodel( table.geteditingrow() );
    column = table.convertcolumnindextomodel( table.geteditingcolumn() );
    oldvalue = table.getmodel().getvalueat(row, column);
    //这里应对oldvalue为null的情况做处理,否则将导致原值与新值均为空时仍被视为值改变
    if(oldvalue == null)
      oldvalue = "";
    newvalue = null;
  }
  /*
   *  update the cell history when necessary
   */
  private void processeditingstopped()
  {
    newvalue = table.getmodel().getvalueat(row, column);
    //这里应对newvalue为null的情况做处理,否则后面会抛出异常
    if(newvalue == null)
      newvalue = "";
    // the data has changed, invoke the supplied action
    if (! newvalue.equals(oldvalue))
    {
      // make a copy of the data in case another cell starts editing
      // while processing this change
      tablecelllistener tcl = new tablecelllistener(
        gettable(), getrow(), getcolumn(), getoldvalue(), getnewvalue());
      actionevent event = new actionevent(
        tcl,
        actionevent.action_performed,
        "");
      action.actionperformed(event);
    }
  }
}

运行效果:

由图可见,单元格数据修改后,控制台输出内容变更信息!

更多关于java相关内容感兴趣的读者可查看本站专题:《java数据结构与算法教程》、《java字符与字符串操作技巧总结》、《java操作dom节点技巧总结》、《java文件与目录操作技巧汇总》和《java缓存操作技巧汇总

希望本文所述对大家java程序设计有所帮助。

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网