问题描述
我正在尝试从 https://docs.oracle.com/javase/tutorial/uiswing/components/table.html 修改 TableDemo.java,以便可以从外部数据源(例如从套接字读取的数据)更新表模型。我能想到的唯一解决方案是将 createAndShowGUI() 方法从静态更改为非静态。但是,我不知道这是否是此用例的推荐解决方案。我的工作代码粘贴在此处,但如果您有任何改进或替代方法的建议,我将不胜感激。
package components;
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;
@SuppressWarnings("serial")
public class DynamicTableDemo extends JPanel {
// Add a MyTableModel member with a getter so you can modify table model data
public final MyTableModel myTableModel;
public DynamicTableDemo() {
super(new GridLayout(1,0));
myTableModel = new MyTableModel();
JTable table = new JTable(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);
}
public MyTableModel getMyTableModel() {
return myTableModel;
}
class MyTableModel extends AbstractTableModel {
private String[] columnNames = {"Stuff"};
private Object[][] data = {
{new Integer(0)},{new Integer(0)},{new Integer(0)}
};
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];
}
/*
* FIXME:
* Multiple markers at this line
* - overrides javax.swing.table.AbstractTableModel.getColumnClass
* - Type safety: The return type Class for getColumnClass(int) from the type DynamicTableDemo.MyTableModel
* needs unchecked conversion to conform to Class<?> from the type AbstractTableModel
* - Class is a raw type. References to generic type Class<T> should be parameterized
*/
public Class getColumnClass(int c) {
return getValueAt(0,c).getClass();
}
public void setValueAt(Object value,int row,int col) {
data[row][col] = value;
fireTableCellUpdated(row,col);
}
}
/**
* Create the GUI and show it. For thread safety,* this method should be invoked from the
* event-dispatching thread.
*
* NOTE: Typically this is a static method but I removed static
* so the underlying table model can be modified.
*/
private void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("DynamicTableDemo");
frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
this.setopaque(true); //content panes must be opaque
frame.setContentPane(this);
//display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
DynamicTableDemo dynamicTableDemo = new DynamicTableDemo();
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokelater(new Runnable() {
public void run() {
dynamicTableDemo.createAndShowGUI();
}
});
int count = 0; // Change table data with an incrementing count
while (true) {
try {
final int count2 = count; // copy to a final variable for Runnable,feels a bit kludgey...
/*
* In full application,blocking read of a value from a socket here.
* Note that myTableModel is updated from the EDT,but the socket read
* and sleep below will not be from the EDT.
*/
javax.swing.SwingUtilities.invokelater(new Runnable() {
public void run() {
dynamicTableDemo.getMyTableModel().setValueAt(new Integer(count2),count2 % dynamicTableDemo.getMyTableModel().getRowCount(),0);
}
});
count++;
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
}
}
解决方法
根据评论更新版本:
package components;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.table.AbstractTableModel;
@SuppressWarnings("serial")
public class DynamicTableDemo extends JPanel {
// Make the JTable a field,so inner class TableCellTask can access it
private final JTable table;
public DynamicTableDemo() {
super(new GridLayout(1,0));
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);
new TableCellTask().execute();
}
private static class TableCell {
private final Object value;
private final int row,col;
TableCell(Object value,int row,int col) {
this.value = value;
this.row = row;
this.col = col;
}
}
private class TableCellTask extends SwingWorker<Void,TableCell> {
@Override
protected Void doInBackground() {
int count = 0; // Change table data with an incrementing count
while (!isCancelled()) {
/*
* In full application,blocking read of a value from a socket here.
* Note that myTableModel is updated from the EDT,but the socket read
* and sleep below will not be from the EDT.
*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
publish(new TableCell(count,count % table.getModel().getRowCount(),0));
count++;
}
return null;
}
@Override
protected void process(List<TableCell> tableCells) {
for (TableCell tableCell : tableCells) {
table.getModel().setValueAt(tableCell.value,tableCell.row,tableCell.col);
}
}
}
class MyTableModel extends AbstractTableModel {
private String[] columnNames = {"Stuff"};
private Object[][] data = {
{new Integer(0)},{new Integer(0)},{new Integer(0)}
};
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];
}
public Class<?> getColumnClass(int c) {
return getValueAt(0,c).getClass();
}
public void setValueAt(Object value,int col) {
data[row][col] = value;
fireTableCellUpdated(row,col);
}
}
/**
* 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("DynamicTableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
DynamicTableDemo newContentPane = new DynamicTableDemo();
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();
}
});
}
}