我在寫一個類來跟蹤線程並在JTable中顯示狀態/進度。我想到的是一個JTable,其中包含所有必需的狀態/按鈕等。列在一列,每行一個線程。我使用了單元格編輯器來獲取表格中的可點擊按鈕,但是我無法解決的問題是,除非單擊另一個單元格,否則所選單元格中的項目不會更新。有沒有辦法讓選中的單元格更新?下面的代碼演示了這個問題。單擊行中的開始按鈕將啓動該線程,但在選中該行時,行中的進度不會更新。JTable中的選定單元格不刷新
import javax.swing.*;
import javax.swing.table.*;
import java.util.Random;
import java.lang.Thread;
import java.lang.Math;
import java.beans.*;
import java.util.concurrent.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.*;
/*
* Program tracks some threads' progress, updating status in
* cells in a JTable.
*
* Inner classes are MyDefTM, ThreadOB and ThreadCell which are
* the table model, the object representing the thread's data and
* the renderer/editor "stamp", respectively.
*/
public class ThreadManager {
public JFrame jFrame;
public JTable jTable;
public MyDefTM tm;
public JScrollPane jsp;
public ThreadManager() {
tm = new MyDefTM();
tm.addColumn("Threads");
jFrame = new JFrame("Thread List");
jTable = new JTable();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void createAndShowGUI() {
/*
* JTable in JScrollPane in JFrame.
*/
jTable.setModel(tm);
jTable.setRowHeight(60);
jsp = new JScrollPane(jTable);
jFrame.getContentPane().add(jsp);
jFrame.pack();
jTable.setDefaultRenderer(Object.class, new ThreadCell());
jTable.setDefaultEditor(Object.class, new ThreadCell());
jTable.setShowHorizontalLines(true);
/*
* Add some test threads.
*/
for (int ii = 0; ii < 5; ii++) {
ThreadOb to = new ThreadOb(ii, jTable);
Vector v = new Vector();
v.add(to);
tm.addRow(v);
}
jFrame.setSize(640, 480);
jFrame.setVisible(true);
return;
}
public static void main(String[] args) {
ThreadManager threadManager = new ThreadManager();
threadManager.createAndShowGUI();
}
/*
* Use DefaultTableModel but make every cell editable.
*/
public class MyDefTM extends DefaultTableModel {
public boolean isCellEditable(int row, int column) {
return true;
}
}
/*
* Represents a thread as stored in the table. Stores
* an ID for the thread, its progress and the result.
*/
public class ThreadOb {
public int threadID;
public int threadProgress;
public JTable jTable;
public SwingWorker workerThread;
public String threadResult;
public ThreadOb(int id, JTable t) {
jTable = t;
threadID = id;
threadProgress = 0;
}
public void buttonAction() {
/*
* Perform a task that takes just a little while to finish.
*/
workerThread = new SwingWorker<String,Object>() {
@Override
public String doInBackground() throws InterruptedException {
int prog = 0;
Random rand = new Random(42);
while (prog < 100) {
prog += Math.abs(rand.nextInt() % 5);
setProgress(prog);
Thread.sleep(1000);
setProgress(Math.min(prog, 100));
}
return "42";
}
};
workerThread.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent e) {
if (e.getPropertyName() == "state" &&
e.getNewValue() == "DONE") {
try {
threadResult = (String) workerThread.get();
} catch (Exception ignore) { }
}
if (e.getPropertyName() == "progress") {
threadProgress = ((Integer) e.getNewValue()).intValue();
/*
* Couple the model and view together. The table cells will
* not update without this line.
*/
((MyDefTM) jTable.getModel()).fireTableDataChanged();
}
}
});
workerThread.execute();
}
}
/*
* Represents the graphical "stamp" for the renderer and editor.
*/
public class ThreadCell extends AbstractCellEditor
implements TableCellRenderer, TableCellEditor {
private JLabel threadIDLabel;
private JLabel threadProgressLabel;
private JPanel threadPane;
private JButton but;
private JPanel statuspane;
private JProgressBar jpb;
private JPanel pane;
private Border offBorder;
private Border onBorder;
private ThreadOb val;
/*
* Establish the layout of the cells in the JTable.
* The selected cell has a red border.
*/
public ThreadCell() {
val = null;
threadIDLabel = new JLabel();
threadProgressLabel = new JLabel();
threadPane = new JPanel();
threadPane.setLayout(new BoxLayout(threadPane, BoxLayout.X_AXIS));
threadPane.add(threadIDLabel);
threadPane.add(threadProgressLabel);
statuspane = new JPanel();
statuspane.setLayout(new BoxLayout(statuspane, BoxLayout.X_AXIS));
statuspane.add(threadPane);
statuspane.add(Box.createHorizontalGlue());
but = new JButton("Start");
statuspane.add(but);
jpb = new JProgressBar(0, 100);
jpb.setStringPainted(true);
pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
pane.add(statuspane);
pane.add(jpb);
offBorder = BorderFactory.createEmptyBorder(2,2,2,2);
onBorder = BorderFactory.createLineBorder(java.awt.Color.RED, 2);
pane.setBorder(offBorder);
but.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
val.buttonAction();
/*
* Uncomment to deselect the cell after clicking.
*/
//fireEditingStopped();
}
});
}
/*
* Populate the cell with the correct values.
*/
public void update(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
if (value == null) {
return;
}
val = (ThreadOb) value;
threadIDLabel.setText("ID: " + ((ThreadOb) value).threadID + " ");
threadProgressLabel.setText("Progress: " +
((ThreadOb) value).threadProgress + "%");
jpb.setValue(((ThreadOb) value).threadProgress);
if (hasFocus) {
pane.setBorder(onBorder);
} else {
pane.setBorder(offBorder);
}
}
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
update(table, value, isSelected, hasFocus, row, column);
return pane;
}
public Component getTableCellEditorComponent(JTable table,
Object value,
boolean isSelected,
int row,
int column) {
update(table, value, isSelected, true, row, column);
return pane;
}
public Object getCellEditorValue() {
return val;
}
}
}
請您務必閱讀如何 - 一些基本教程(在線標籤的相應章節,在swing標籤wiki中引用) - 至今爲止,您正在這樣做_completely_ wrong:正如@MadProgrammer已經提到的那樣,您需要一個正確實現的_TableModel_來處理數據端... – kleopatra