Я пытаюсь изменить TableDemo.java из https://docs.oracle.com/javase/tutorial/uiswing/components/table.html, чтобы модель таблицы можно было обновлять из внешнего источника данных (например, данные, считанные из сокета). Единственное решение, которое я смог придумать, заключалось в изменении метода 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)},
{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;
}
}
}
}