本文實例講述了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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
/* * 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.zmynmublwnt.cn" ); 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
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程序設計有所幫助。
原文鏈接:http://www.cnblogs.com/pzy4447/p/5164775.html