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

网友投稿 875 2023-03-17


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

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

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

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

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

测试用例如下:

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.http://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 - 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程序设计有所帮助。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java 接口开发(java接口开发有哪些技术)
下一篇:Java Swing组件JFileChooser用法实例分析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~