我遇到了JTable选择处理程序的问题。
该表每15秒从Control中的刷新线程更新一次。
我想在JTable中选择一行并提取我将用于构建文件名的列内容。
只要在刷新期间未选择第0行,一切正常。但是如果在触发刷新时选择了第0行,它看起来像是在setAppserverData过程和事件处理程序之间跳转,直到它超过表的rowCount并且我得到一个IndexOutOfBoundsException。
我是一个Java新手,这是我所知的边缘,所以我很难搞清楚代码有什么问题。我的直觉是,它与我试图实现MVC结构有关,而且我无法以正确的方式分离代码。
//控制器
// Appserver worker
class AppserverWorker extends SwingWorker<Integer, Integer>{
protected Integer doInBackground() throws Exception{
// Check appservers
while(true){
theModel.readAppservData();
// Update action buttons
try {
if(!theModel.isStatusOk()){
theGui.actionButtonPanel.setAppServBtnColor("RED");
// theGui.actionButtonPanel.setButtonFlashOn();
}else theGui.actionButtonPanel.setAppServBtnColor("GREEN");
} catch (IllegalArgumentException e1) {
sysLogger.logMsg("SEVERE",e1.getMessage());
JOptionPane.showMessageDialog(null, e1.getMessage());
}
// Update GUI
theGui.extAppServPanel.setAppserverData(theModel.getAppservData());
// Sleep refresh time
// TODO read refresh from init table
try {
Thread.sleep(appServRefreshTime);
} catch (InterruptedException e) {}
}
}
// List selection handler
class SharedListSelectionHandler implements ListSelectionListener {
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()){ // To avoid double trigger of listener
System.out.println(">>>>>>>>> Selection list handler >>>>>>>>");
String fileName = null;
String fileExt = ".txt";
ListSelectionModel lsm = (ListSelectionModel)e.getSource();
try {
int selectedRow = lsm.getAnchorSelectionIndex(); // Get the row clicked
if (selectedRow>=0){ // If -1 no row selected
fileName = theGui.extAppServPanel.getAppservName(selectedRow)+fileExt; // Get appserver name and build file name
theModel.readCollectFile(InitParameters.collectFilePath, fileName); // Read collect file
theGui.extAppServPanel.setAppservInfo(theModel.getCollectFileContent()); // Fill the text panel with collect file
}
}
catch(FileNotFoundException e1){
sysLogger.logMsg("SEVERE",this.getClass().getSimpleName()+": Collect file "+fileName+" is missing");
JOptionPane.showMessageDialog(null, "Collect file "+fileName+" is missing");
}
catch(IOException e1){
sysLogger.logMsg("SEVERE",this.getClass().getSimpleName()+": System error: An I/O error occurred");
System.err.println("System error: An I/O error occurred");
System.exit(0);;
}
}
}
}
//视图
public class ExtAppServPanel extends JPanel {
private JTable table;
private DefaultTableModel model;
private JTextArea textAreaInfo;
private JButton btnSaveInfo;
private List colData;
public boolean ignoreTableChanges = false;
/**
* Constructor
*/
public ExtAppServPanel() {
System.out.println(this.getClass().getSimpleName()+": Constructor");
setLayout(new MigLayout("", "[350:376.00,grow,leading]", "[100px:100,grow][][48.00,grow][]"));
this.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Application servers info", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0)));
// Set up table
String[] columnNames = {"Server name", "Type","Status"};
model = new DefaultTableModel(null,columnNames);
table = new JTable(model){
// Color code rows
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {
Component comp = super.prepareRenderer(renderer, row, col);
if (!isRowSelected(row)){
comp.setBackground(getBackground());
int modelRow = convertRowIndexToModel(row);
String type = (String)getModel().getValueAt(modelRow, 2);
if ("FAIL".equals(type)) comp.setBackground(Color.RED);
if ("WARNING".equals(type)) comp.setBackground(Color.YELLOW);
}
return comp;
}
};
// Set grid
table.setGridColor(Color.LIGHT_GRAY);
// Set width and alignment
table.getColumnModel().getColumn(1).setMinWidth(200);
table.getColumnModel().getColumn(1).setMaxWidth(200);
table.getColumnModel().getColumn(1).setPreferredWidth(200);
table.getColumnModel().getColumn(2).setMinWidth(75);
table.getColumnModel().getColumn(2).setMaxWidth(75);
table.getColumnModel().getColumn(2).setPreferredWidth(75);
// Add scrollpane
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
table.setFillsViewportHeight(true);
this.add(scrollPane, "cell 0 0,grow");
// Set up text area
JLabel lblDetails = new JLabel("Details");
this.add(lblDetails, "cell 0 1,alignx leading");
textAreaInfo = new JTextArea();
textAreaInfo.setBackground(Color.BLACK);
textAreaInfo.setForeground(Color.GREEN);
textAreaInfo.setEditable(false);
textAreaInfo.setFont(new Font("Lucida Console",Font.PLAIN,10));
JScrollPane scrollPane_1 = new JScrollPane();
scrollPane_1.setViewportView(textAreaInfo);
this.add(scrollPane_1, "cell 0 2,grow");
// Save button
btnSaveInfo = new JButton("Save");
add(btnSaveInfo, "cell 0 3,alignx right");
}
/*
* Setters and getters
*/
public void setAppserverData(ArrayList<ArrayList<String>> dataRecord) {
ArrayList<String> dataCol = new ArrayList<String>();
// Init values array from result set
try {
model.setRowCount(0); // <<<<<<<<<< Problem
String[] arrayRow;
String status = "Ok";
// Get first row from list
dataCol = dataRecord.get(0);
arrayRow = new String[dataCol.size()];
arrayRow[0] = dataCol.get(2);
arrayRow[1] = dataCol.get(1);
arrayRow[2] = dataCol.get(4);
for (int i = 0; i < dataRecord.size(); i++){
dataCol = dataRecord.get(i);
// Check status
if (dataCol.get(4).toUpperCase().equals("FAIL")){
status = "FAIL";
}else if (dataCol.get(4).toUpperCase().equals("WARNING")){
status = "WARNING";
}
if (!dataCol.get(2).toUpperCase().equals(arrayRow[0].toUpperCase())){
arrayRow[2] = status; // Override status
System.out.println(">>>>>>>>> Updating table >>>>>>>>");
model.addRow(arrayRow); // Add row to table
arrayRow = new String[dataCol.size()];
arrayRow[0] = dataCol.get(2);
arrayRow[1] = dataCol.get(1);
arrayRow[2] = dataCol.get(4);
status = "Ok";
}
}
setAppservName();
} catch (Exception e) {
e.printStackTrace();
}
}
// Get row count
public int getRowCount(){
return model.getRowCount();
}
// Set table data
public void setAppservName(){
Vector data = model.getDataVector();
Vector row = (Vector) data.elementAt(1);
// Copy the first column
int mColIndex = 0;-
colData = new ArrayList(table.getRowCount()+1);
for (int i = 0; i < table.getRowCount(); i++) {
row = (Vector) data.elementAt(i);
colData.add(row.get(mColIndex));
}
}
// Get table data
public String getAppservName(int rowNum){
return (String) colData.get(rowNum);
}
// Set appserver info
public void setAppservInfo(String appservInfo){
textAreaInfo.setText(appservInfo);
textAreaInfo.setCaretPosition(0); // Set cursor at top of text
}
// Get appserver info
public String getAppservInfo(){
return textAreaInfo.getText();
}
/**
* Action listeners
*/
public void addTableRowListener(ListSelectionListener listSelectionEvent) {
table.getSelectionModel().addListSelectionListener(listSelectionEvent);
}
public void addButtonListener(ActionListener buttonEvent) {
btnSaveInfo.addActionListener(buttonEvent);
btnSaveInfo.setActionCommand("saveAppServInfo");
}
}
选择非零行并运行刷新线程时的跟踪输出
** Appserver worker **
CmtModel: readAppservData
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>> Rowcount = 8
选择零行并运行刷新线程时的跟踪输出
** Appserver worker **
CmtModel: readAppservData
>>>>>>>>> Selection list handler ! >>>>>>>>
>> Controll: selectedRow = 0 <<
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Selection list handler ! >>>>>>>>
>> Controll: selectedRow = 1 <<
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Selection list handler ! >>>>>>>>
>> Controll: selectedRow = 2 <<
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Selection list handler ! >>>>>>>>
>> Controll: selectedRow = 3 <<
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Selection list handler ! >>>>>>>>
>> Controll: selectedRow = 4 <<
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Selection list handler ! >>>>>>>>
>> Controll: selectedRow = 5 <<
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Selection list handler ! >>>>>>>>
>> Controll: selectedRow = 6 <<
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Selection list handler ! >>>>>>>>
>> Controll: selectedRow = 7 <<
>>>>>>>>> Updating the table >>>>>>>>
>>>>>>>>> Selection list handler ! >>>>>>>>
>> Controll: selectedRow = 8 <<
java.lang.IndexOutOfBoundsException: Index: 8, Size: 8
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at panels.ExtAppServPanel.getAppservName(ExtAppServPanel.java:219)
at Control$SharedListSelectionHandler.valueChanged(Control.java:330)
at javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source)
at javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source)
at javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source)
at javax.swing.DefaultListSelectionModel.insertIndexInterval(Unknown Source)
at javax.swing.JTable.tableRowsInserted(Unknown Source)
at javax.swing.JTable.tableChanged(Unknown Source)
at javax.swing.table.AbstractTableModel.fireTableChanged(Unknown Source)
at javax.swing.table.AbstractTableModel.fireTableRowsInserted(Unknown Source)
at javax.swing.table.DefaultTableModel.insertRow(Unknown Source)
at javax.swing.table.DefaultTableModel.addRow(Unknown Source)
at javax.swing.table.DefaultTableModel.addRow(Unknown Source)
at panels.ExtAppServPanel.setAppserverData(ExtAppServPanel.java:172)
at Control$AppserverWorker.doInBackground(Control.java:434)
at Control$AppserverWorker.doInBackground(Control.java:1)
at javax.swing.SwingWorker$1.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at javax.swing.SwingWorker.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
答案 0 :(得分:2)
// Update GUI
theGui.extAppServPanel.setAppserverData(theModel.getAppservData());
不要在doInBackground()
方法中更新模型或GUI。
GUI的所有更新都应在EventDispatchThread (EDT)
。
相反,当数据发生变化时,您需要&#34;发布&#34;结果所以代码可以在process(...)
的{{1}}方法中执行,该方法在EDT上执行,因此GUI将在EDT上更新。
阅读Concurrency上Swing教程中的部分以获取更多信息。 SwingWorker
部分有一个发布方法示例。