Reputation: 1
I have a JTable that I'm inserting rows into using data found on the internet. When I run the code that fills the list directly from the main function, I can see each row being inserted at the same time 'fireTableRowsInserted' is called - which is the behavior I want. However, when I run that same code from a JButton's ActionListener (during 'ActionPreformed()', the table does not update until the thread/event has finished. I think the problem has something to do with threads, but I am not very familiar with how thread work and am not sure where to start. Here is an example of the problem:
public class Main {
static TestModel myTestModel = new TestModel();
public static void main(String[] args) {
JFrame testFrame = new JFrame();
JTable table = new JTable(myTestModel);
JButton button = new JButton("Load");
testFrame.getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);
testFrame.getContentPane().add(button, BorderLayout.PAGE_END);
testFrame.pack();
testFrame.setVisible(true);
testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button.addActionListener(new ActionListener(){
@Override public void actionPerformed(ActionEvent e) {
//When openURLStr is called here, the table in the JFrame doesn't add rows until
// the function has exited.
openURLStr("http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Component.html", true);
}
});
//When openURLStr is called here, the table in the JFrame adds rows at the same time the
// list in the table-model adds a row. (the desired behavoir)
openURLStr("http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Component.html", true);
myTestModel.myArrayList.clear();
myTestModel.fireTableDataChanged();
}
static class TestModel extends AbstractTableModel {
ArrayList<String> myArrayList = new ArrayList<String>();
@Override public int getColumnCount() { return(3); }
@Override public int getRowCount() { return(myArrayList.size()); }
@Override public Object getValueAt(int row, int col) {
char c = '*';
String rowStr = myArrayList.get(row);
if ( rowStr.length() > col ) c = rowStr.charAt(col);
return(c);
}
public boolean add(String line) {
int row = myArrayList.size();
if ( row < 100 ) {
myArrayList.add(line);
this.fireTableRowsInserted(row, row);
return(true);
}
else {
return(false);
}
}
}
private static void openURLStr(String urlStr, boolean lookForLinks) {
try {
URL url = new URL(urlStr);
InputStreamReader isr = new InputStreamReader(url.openConnection().getInputStream());
BufferedReader br = new BufferedReader(isr);
ArrayList<String> linksFound = new ArrayList<String>();
if ( br != null ) {
String strLine = br.readLine();
//row added to table-model here:
boolean continueParse = myTestModel.add(strLine);
//this code is mainly to induce more time between each addition of a line.
while ( strLine != null && continueParse ) {
if ( lookForLinks && strLine != null ) {
String ahrefStr = "a href=\"";
int start_i = strLine.indexOf(ahrefStr) + ahrefStr.length();
if ( start_i > -1 ) {
int end_i = strLine.indexOf("\"", start_i+1);
if ( end_i > -1 && end_i > start_i ) {
linksFound.add(strLine.substring(start_i, end_i));
}
}
}
strLine = br.readLine();
}
br.close();
}
for ( String link : linksFound ) {
openURLStr(link, false);
}
} catch (IOException e) {
}
}
}
Upvotes: 0
Views: 1530
Reputation: 39207
The ActionListener's actionPerformed
is executed on the event dispatch thread and this will be blocked by your code inside. Thus the GUI freezes for this time and no updates will be shown at all.
Try to separate the "long running" URL call e.g. in a SwingWorker
.
Upvotes: 5