此应用程序从文本文件中提取数据并将其插入 JTable
。安Observer
附加每 300 毫秒检查一次文件是否有更改并重新加载数据。我有setChanged()
和notifyObservers()
在我的Observer
类(class)。
当数据添加到表中时,会出现 getRowCount()
报告该行已添加,通知程序正在运行。事实上,除了 repaint()
之外,一切都正常。 。我已经尝试过revalidate()
和fireTableDataChanged()
一切都无济于事。我希望得到一些帮助。整个过程没有报编译错误。
表格模型
package HardwareDbFile;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.swing.table.AbstractTableModel;
public class HardwareFileTableModel extends AbstractTableModel{
protected Vector data;
protected Vector columnNames ;
protected String datafile;
public HardwareFileTableModel(String file){
datafile = file;
initVectors();
}
public void initVectors() {
String aLine ;
data = new Vector();
columnNames = new Vector();
try {
FileInputStream fin = new FileInputStream(datafile);
try (BufferedReader br = new BufferedReader(new InputStreamReader(fin))) {
StringTokenizer st1 = new StringTokenizer(br.readLine(), "|");
while(st1.hasMoreTokens()) {
columnNames.addElement(st1.nextToken());
}
// extract data
while ((aLine = br.readLine()) != null) {
StringTokenizer st2 = new StringTokenizer(aLine, "|");
while(st2.hasMoreTokens()) {
data.addElement(st2.nextToken());
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
@Override
public int getRowCount() {
return data.size() / getColumnCount();
}
@Override
public int getColumnCount(){
return columnNames.size();
}
@Override
public String getColumnName(int columnIndex) {
String colName = "";
if (columnIndex <= getColumnCount()) {
colName = (String)columnNames.elementAt(columnIndex);
}
return colName;
}
@Override
public Class getColumnClass(int columnIndex){
return String.class;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
public Object getValueAt(int rowIndex, int columnIndex) {
return (String)data.elementAt( (rowIndex * getColumnCount()) + columnIndex);
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
}
}
观察者类
package HardwareDbFile;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.Timer;
public class HardwareFileObserver extends Observable implements ActionListener {
Timer time = new Timer(300,this); // check every 300ms
long lastModified;
String file ;
HardwareFileObserver (String string) {
file = string;
File f = new File(file);
lastModified = f.lastModified(); // original timestamp
time.start();
}
@Override
public void actionPerformed(ActionEvent e) {
File f = new File(file);
long actualLastModified = f.lastModified();
if (lastModified != actualLastModified) {
// the file have changed
lastModified = actualLastModified;
setChanged();
notifyObservers();
}
}
}
主类
public class HardwareInventoryUI extends javax.swing.JFrame implements Observer {
private String datafile = "hardware.dat";
private String dataFilePath = "C:\\Windows\\Temp\\hardware.dat";
protected HardwareFileTableModel model;
/**
* Creates new form HardwareInventoryUI
*/
public HardwareInventoryUI() {
initComponents();
model = new HardwareFileTableModel(dataFilePath);
HardwareFileObserver fileWD;
// this Observable object is monitoring any file change
fileWD = new HardwareFileObserver(dataFilePath);
fileWD.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
// reload data because data file have changed
model.initVectors();
jTable.repaint();
}
添加录制按钮
private void jAddRecordActionPerformed(java.awt.event.ActionEvent evt) {
String toolID = jToolID.getText();
String toolName = jToolName.getText();
String quantity = jQuantity.getText();
String itemPrice = jItemPrice.getText();
try {
model = new HardwareFileTableModel(dataFilePath);
FileWriter fstream = new FileWriter(dataFilePath, true);
try (BufferedWriter newRecord = new BufferedWriter(fstream)) {
newRecord.newLine();
newRecord.write(toolID + "|"+ toolName + "|" + quantity + "|" + itemPrice );
}
} catch (IOException ex) {
Logger.getLogger(HardwareInventoryUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
最佳答案
您的
TableModel
应该实现Observer
,而不是您的 View 。在update()
方法中,更新data
和fireTableDataChanged()
。JTable
监听其TableModel
并自动更新自身作为响应。还要考虑提到的观察者模式的替代实现 here .
如图here ,您的
setValueAt()
实现不正确。您需要触发事件来通知监听表发生的变化:@Override public void setValueAt(Object value, int row, int column) { // update data fireTableCellUpdated(row, column); }
如果您的
数据文件
的内容可以作为命令的标准输出获得,您也许可以使用概述的方法here来消除该文件。 .
附录:正如 @kleopatra 评论的那样,“请注意,对于行为良好的模型,您永远不需要考虑 View 更新,它们只是自动神奇地发生:-) 或者相反:如果手动重新绘制 View (例如表、树、列表)似乎是一个解决方案,但模型实现不正确。”
关于java - JTable#repaint() 未按预期运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13661821/