java - 从外部数据源(例如从套接字读取的数据)修改 Java JTable AbstractTableModel
问题描述
我正在尝试从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)},
{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)},
{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 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.
*
*/
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();
}
});
}
}
推荐阅读
- firebase - firebase 功能在 blaze 计划上部署计费问题
- android - ViewStub 元素找不到 BindingAdapter
- android - beeware将toga imageview添加到android
- c++ - 队列和文本文件
- amazon-web-services - AWS Data Exchange 限制如何避免?
- angular - NgRx 存储选择器单元测试
- java - 如何使用以当前日期为输入的java获取下一个日期
- c# - Xna 可破坏的墙壁
- microsoft-graph-api - 尝试在 MS Graph 中创建会议时出现内部服务器错误
- linux - ln:创建符号链接失败:文件存在