我试图从JSONArray中显示表格。但结果永远不会出现。通过调用此initTable()方法,该表已显示正确的列名。 initTable()如下:
private void initTable() {
contentPane.removeAll();
PrintTableModel tblModel = new PrintTableModel();
DefaultTableColumnModel columns = new DefaultTableColumnModel();
TableColumn c;
c = new TableColumn();
c.setHeaderValue(columnNames[0]);
columns.addColumn(c);
c = new TableColumn();
c.setHeaderValue(columnNames[1]);
columns.addColumn(c);
c = new TableColumn();
c.setHeaderValue(columnNames[2]);
columns.addColumn(c);
c = new TableColumn();
c.setHeaderValue(columnNames[3]);
columns.addColumn(c);
listTable = new JTable(tblModel, columns);
listTable.getTableHeader().setReorderingAllowed(false);
JScrollPane scrollPane = new JScrollPane();
scrollPane.add(listTable);
scrollPane.setViewportView(listTable);
contentPane.add(scrollPane, BorderLayout.CENTER);
}
我从这样的线程调用刷新表:
public class RetrievePrintRequest extends Thread {
private boolean speedUp = false;
public void run() {
if (loginId == 0)
return;
try {
String token = generateLink("prc_admin_id=" + loginId);
do {
JSONArray jsonresult = readJsonFromUrl(BASE_URL + "ajax/get_latest_print?code=" + token);
// looping through All elements
// list holding row data
List<PrintModel> printList = new ArrayList<PrintModel>();
for (int i = 0; i < jsonresult.length(); i++) {
JSONObject c = jsonresult.getJSONObject(i);
// Storing each json item in variable
int printId = c.getInt("print_id");
String bookingCode = c.getString("booking_code");
long startDate = c.getLong("start_date");
String patientName = c.getString("patient_name");
String doctorName = c.getString("doc_name");
PrintModel printModel = new PrintModel(
printId, bookingCode, patientName, doctorName, new Date(startDate));
// add rest of the json data to NodePOJO class
System.out.println(printId + ";" + bookingCode + ";" + startDate + ";" + patientName + ";" + doctorName);
// the object to list
printList.add(printModel);
}
PrintTableModel printModel = (PrintTableModel) listTable.getModel();
printModel.refresh(printList); //<--- I expect this to refresh the table content
Thread.sleep(!speedUp ? 10000 : 60000);
} while(true);
} catch (JSONException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这是TableModel中的刷新方法(添加整个PrintTableModel类)
protected class PrintTableModel extends DefaultTableModel {
private List<PrintModel> listData;
public void refresh(List<PrintModel> data) {
listData = data; // <== refresh with new List and call fireTableDataChanged
fireTableDataChanged();
}
public Object getValueAt(int row, int column) {
Object result = null;
PrintModel model = (PrintModel)listData.get(row);
switch (column)
{
case 0:
result = model.getBookingCode();
break;
case 1:
result = SDF.format(model.getAppointmentDate());
break;
case 2:
result = model.getPatientName();
break;
case 3:
result = model.getDoctorName();
break;
}
return result;
}
public Class getColumnClass(int column) {
switch (column)
{
case 0:
return String.class;
case 1:
return String.class;
case 2:
return String.class;
case 3:
return String.class;
}
return null;
}
任何人都可以发现我的错误?非常感谢。
答案 0 :(得分:3)
您正在从未与Event Dispatch Thread
(EDT)同步的主题更新UI:
Swing事件处理代码在称为事件派发线程的特殊线程上运行。大多数调用Swing方法的代码也在这个线程上运行。 这是必要的,因为大多数Swing对象方法不是&#34;线程安全&#34;:从多个线程调用它们可能会导致线程干扰或内存一致性错误
Swing 不线程安全,因此您需要使用SwingUtilities.invokeLater
更新用户界面。
来自SwingUtilities.invokeLater
的文档:
导致doRun.run()在AWT事件派发线程上异步执行。这将在处理完所有挂起的AWT事件后发生。 当应用程序线程需要更新GUI时,应使用此方法。
PS:使用这种方法将表格添加到内容窗格中:
contentPane.add(new JScrollPane(listTable), BorderLayout.CENTER);
答案 1 :(得分:3)
添加到什么TT。已经说过......
对于for-loop
的迭代,你可以这样做......
PrintModel printModel = new PrintModel(printId, bookingCode, patientName, doctorName, new Date(startDate));
// add rest of the json data to NodePOJO class
System.out.println(printId + ";" + bookingCode + ";" + startDate + ";" + patientName + ";" + doctorName);
// the object to list
printList.add(printModel);
}
处理完每个&#34;行&#34;后,你就这样做了......
PrintTableModel printModel = (PrintTableModel) listTable.getModel();
printModel.refresh(printList); //<--- I expect this to refresh the table content
这里的问题是,您在PrintModel
中for-loop
与您尝试刷新的关系有什么关系?
相反,您应该在PrintTableModel
开始之前创建for-loop
的新实例,将每行数据添加到此PrintTableModel
实例,然后(在同步之后)致电EDT)将此PrintTableModel
实例应用于JTable
OR
使用SwingWorker
,publish
每行数据,并在PrintTableModel
时添加JTable
的当前实例(来自process
)。
有关详细信息,请参阅Concurrency in Java和Worker Threads and SwingWorker
答案 2 :(得分:1)
答案: 它没有用,因为DefaultTableModel拥有它自己的Vector数据,并且在调用fireTableDataChanged()时创建新的没有受到影响。所以,我猜DefaultTableModel没有设计要扩展,而是用作标准的TableModel。 Java为扩展目的提供了AbstractTableModel。
所以,这是从AbstractTableModel扩展的新代码:
protected class PrintTableModel extends AbstractTableModel {
private List<PrintModel> listData = new ArrayList<PrintModel>();
protected String[] columnNames;
public int getRowCount() {
return listData.size();
}
public void setColumnNames(String[] columnNames) {
this.columnNames = columnNames;
}
public String getColumnName(int column) {
return columnNames[column];
}
public int getColumnCount() {
return columnNames.length;
}
public void add(Object obj) {
listData.add(0, (PrintModel)obj);
fireTableRowsInserted(listData.size() - 1, listData.size() - 1);
}
public void update(Object obj, int row) {
listData.set(row, (PrintModel)obj);
fireTableRowsUpdated(row, row);
}
public void remove(int row) {
listData.remove(row);
fireTableRowsDeleted(row, row);
}
public Object getObjectAt(int row) {
return listData.get(row);
}
public void refresh(List<PrintModel> data) {
listData = data;
fireTableDataChanged();
}
public Object getValueAt(int row, int column) {
Object result = null;
PrintModel model = (PrintModel)listData.get(row);
switch (column)
{
case 0:
result = model.getBookingCode();
break;
case 1:
result = SDF.format(model.getAppointmentDate());
break;
case 2:
result = model.getPatientName();
break;
case 3:
result = model.getDoctorName();
break;
case 4:
result = "Print";
break;
}
return result;
}
public Class getColumnClass(int column) {
switch (column)
{
case 0:
return String.class;
case 1:
return String.class;
case 2:
return String.class;
case 3:
return String.class;
case 4:
return String.class;
}
return null;
}
}