Reputation: 43
I got a problem with my JPanel. I built a html/css scraper with an interface. That interface has an JTextArea that updates with the steps the scraper completes like "Found HTML" and "Saved Files Succesfully". I want to add these messages to the JTextArea while the code is running. A simple check shows the updates are working with the observerpattern, but the all the messages don't show up until all code is finished.
Example Code from observerable class(triggered like 100 times):
private void addItem(String line, char type, String classOrId) {
String[] lineSplit = line.split(classOrId+"="+type);
lineSplit = lineSplit[1].split(""+type);
lineSplit = lineSplit[0].split(" ");
for (String a : lineSplit) {
if(classOrId == "id"){
if (!usedIds.contains(a)) {
usedIds.add(a);
}
}
else if(classOrId == "class"){
if (!usedClasses.contains(a)) {
usedClasses.add(a);
}
}
consoleText = consoleText + "Class \"" + a + "\" is found.";
setChanged();
notifyObservers();
}
}
Example Code from observer class:
public class ScraperView extends JPanel implements Observer {
Scraper scraper;
public ScraperView(Scraper scraper){
this.scraper = scraper;
scraper.addObserver(this);
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
refresh();
}
private void refresh() {
System.out.println("TrIGGER");
removeAll();
int removedClasses = scraper.getRemovedClasses();
int totalClasses = scraper.getTotalClasses();
JLabel classesText = new JLabel(" Total Classes: "+ Integer.toString(totalClasses));
JLabel removedClassesText = new JLabel(" Removed Classes: "+ Integer.toString(removedClasses));
this.add(classesText);
this.add(removedClassesText);
this.revalidate();
this.repaint();
}
@Override
public void update(Observable o, Object arg) {
refresh();
}
}
Is there a way to wait until the jPanel is updated? I notice that the code gets triggered every time, but doesn't update..
Upvotes: 2
Views: 93
Reputation: 11113
You're creating and adding new JLabels every time you update which is a bad idea, you should create the labels once and then update them, you should also ensure that you update them on the UI thread which you can do with SwingUtilities.invokeLater(Runnable)
public class ScraperView extends JPanel implements Observer {
Scraper scraper;
JLabel classesText = new JLabel();
JLabel removedClassesText = new JLabel();
public ScraperView(Scraper scraper){
this.scraper = scraper;
scraper.addObserver(this);
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.add(classesText);
this.add(removedClassesText);
refresh();
}
private void refresh() {
System.out.println("TrIGGER");
int removedClasses = scraper.getRemovedClasses();
int totalClasses = scraper.getTotalClasses();
classesText.setText(" Total Classes: "+ Integer.toString(totalClasses));
removedClassesText.setText(" Removed Classes: "+ Integer.toString(removedClasses));
}
@Override
public void update(Observable o, Object arg) {
SwingUtilities.invokeLater(this::refresh);
}
}
Upvotes: 0
Reputation: 81
You should look at the SwingWorker class, it is designed to perform a task in thread while updating the UI at the same time.
Upvotes: 1