I seem to have a problem with SwingWorker.
I basically implemented the Java Example Code updating the UI from the propertyChange() method of my JFrame.
I also copied the sleep up to one second part in doInBackground.
This leaves me with a good update rate of setProgress within my Worker.
However the propertyChange Event is fired only once about every 10sec.
I know from the API that not every setProgress fires an event, and I'm ok with that, however it seems that this is kinda slow and too many events are lost.
When stepping through in a Debugger I get a better rate, ~once every 3 calls to setProgress
Any ideas why it is so slow?
Here are the parts of my Code:
public Void doInBackground() {
Random random = new Random();
setProgress(0);
float getSize=0,gotSize=0;
while (Sync.syncing) {
//Sleep for up to one second.
try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException ignore) {
ignore.printStackTrace();
}
try{
getSize=Main.getSyncGet();
gotSize=Main.getSyncGot();
System.out.println("setProgress: "+(gotSize/getSize));
setProgress((int)((gotSize/(getSize))*100));
}catch(Exception e){
Main.LOGGER.log(Level.WARNING,"Error setting progress",e);
}
}
return null;
}
public void propertyChange(PropertyChangeEvent evt) {
if ("progress" == evt.getPropertyName()) {
jpb.setValue((Integer) evt.getNewValue());
}
}
Kind Regards
Jens
Your problem is quite possibly here:
System.out.println("setProgress: "+(gotSize/getSize));
setProgress((int)((gotSize/(getSize))*100));
Have you tested that the progress is actually being changed? A better println would be:
int value = (int)((gotSize/(getSize))*100);
System.out.println("setProgress: "+ value);
setProgress(value);
Now check to see if value is in fact changing.
Ooops, this is definitely wrong:
public void propertyChange(PropertyChangeEvent evt) {
if ("progress" == evt.getPropertyName()) {
jpb.setValue((Integer) evt.getNewValue());
}
}
Don't compare Strings using ==. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two objects are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here. So instead of
if (fu == "bar") {
// do something
}
do,
if ("bar".equals(fu)) {
// do something
}
or,
if ("bar".equalsIgnoreCase(fu)) {
// do something
}
read SwingWorker, there are described possible scenarios, including code examples
setProgress(0); and setProgress((int)((gotSize/(getSize))*100)); must be called on EDT
output from folows methods could be done on EDT during doInBackground()
process()
publish()
setProgress()
most complex code example by #trashgod about PropertyChangeListener
for better help sooner post an SSCCE
You can try firing property changes manually:
setProgress(1);
firePropertyChange("progress", 0, 1);
Related
how to access value from outside the actionlistener
jbtnOne.addActionListener(new ActionListener() {
private String ana_data;
#SuppressWarnings("override")
public void actionPerformed(ActionEvent le) {
ana_data=jtf.getText();
}
});
pos_pred=def_pred(f_path,ana_data,prob_p,poslen,pcount);
neg_pred=def_pred(f_path1,ana_data,prob_n,neglen,ncount);
I need to take the data from outside the ActionListener inside the method given after that? can someone please help me?
There is no way of doing that.
The reason is that the ActionListener is executed later in time when the rest of the method is already run.
So if you want to work with something that depends on the action listener you have to move it there (or in a method tat is called from the ActionListener .
One of possible general patterns to tackle problems where some part of your code depends on values from code executed asynchronously is to use promises (CompletableFuture in Java). Generally it is advisable to design your overall code asynchronously in such situations, so that the method producing the value and the method requiring the value can both proceed at some even at some later point in time. From you question it is not clear if you can design it that way in your case. So I will assume you cannot. If your caller cannot behave asynchronously and needs the result of an asynchronous operation within a synchronous flow, then you will need to block the thread waiting for the result:
CompletableFuture<String> anaDataPromise = new CompletableFuture<>();
jbtnOne.addActionListener(new ActionListener() {
#SuppressWarnings("override")
public void actionPerformed(ActionEvent le) {
anaDataPromise.complete(jtf.getText());
}
});
anaData = anaDataPromise.get(); // will block until action performed
// anaData = anaDataPromise.get(10, TimeUnit.MINUTE); // will block until action performed or for max of 10 minutes
If you could permit the code that needs the anaData value to be fully asynchronous, then you could write it in a non-blocking fashion:
CompletableFuture<String> anaDataPromise = new CompletableFuture<>();
jbtnOne.addActionListener(new ActionListener() {
#SuppressWarnings("override")
public void actionPerformed(ActionEvent le) {
anaDataPromise.complete(jtf.getText());
}
});
anaDataPromise.whenComplete((anaData, throwable) -> {
if (throwable != null) {
throw new RuntimeException(throwable);
}
// do something with anaData value
});
// this point is reached immediately as the above code simply declares
// the action that will run later, the actions themselves are not yet run
first of all I'm not an English native speaker so I apologize for any eventual “weird” writing.
I'm developing a Swing Java application on Eclipse that updates a Jpanel. This panel contains several sub-panels, and I'm constantly switching the panels “modes”, what happens to be a MouseListener changing so they respond in a slightly different manner to the user mouse inputs.
Regardless of what the application do, it's happening an error that seems to have no logical explanation to me. At some point in my code I try to update the panels to what I called neutralMode. This happens on the following method:
//Guarded block (see http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html)
private synchronized boolean waitsForUserSatisfactionAnswer()
{
while(!userIndicatedSatisfaction)
{
try {
wait();
} catch (InterruptedException e) {}
}
userIndicatedSatisfaction = false; //reset for future new query
getObjectSetVisualizationPanel().neutralMode();
//getObjectSetVisualizationPanel().queryPatternMode();
return userSatisfied;
}
This updating doesn't work (the call to neutralMode() dont do what is expected). However the call to queryPatternMode() (commented on the line right below) works perfectly. So I decided to COPY queryPatternMode()'s body and PASTE it on neutralMode()'s body ECXATLY THE SAME! AND IT STILL DOESNT WORK!
The methods code is like this:
public void queryPatternMode()
{
System.out.println("Inside queryPatternMode!!!");
System.out.println("panels.size(): " + panels.size());
for (DigitalObjectPanel panel : panels)
{
System.out.println("Inside the loop!!!");
panel.resetBehavior();
panel.setQuerySelectionBehavior(gui);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
panel.validate();
}
});
}
}
public void neutralMode()
{
System.out.println("Inside neutralMode!!!");
System.out.println("panels.size(): " + panels.size());
for (DigitalObjectPanel panel : panels)
{
System.out.println("Inside the loop!!!");
panel.resetBehavior();
panel.setQuerySelectionBehavior(gui);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
panel.validate();
}
});
}
}
What happens is that, when I call neutralMode(), the “panels” collection happens to be empty (panels.size() equals zero). However when I call queryPatternMode() instead, the collection happens to have it's expected size (20 panels). But both methods are equals, and both are called from the same place!!!
What it could be??? Is there any possible explanation for that??
It definitely looks like a synchronisation issue. You should check how many threads are accessing the collection 'panels'.
It is just a stroke of luck that it works for you with queryPatternMode() all the time, and not with neutralMode(). On another fine day, it might be other way around.
I have an issue with my swing project , and after long time, I found that I have a concurrency issue. Nevertheless, I am clueless about concurrency issues ,and I just try to learn.
My project in nutshell is a database that gets connected to a JTable. When some operations such as enter, update, and delete happens, it affects both database which is derby and JTable at the same time.
I use SwingWorker and invokeLater in my code. Sometimes it works, but some other times it doesnot work.
my code is as follows
Note: I implement AbstractTableModel for my JTable which I advice I should have used DefualtTableModel.
the following code is for deleting part and I think I can apply the same functionality for other operations.
am I right about it?
private void deleteJBActionPerformed(java.awt.event.ActionEvent evt) {
deleteDB = new DeleteDB();
deleteDB.execute();
}
class DeleteDB extends SwingWorker<Void, Void> {
#Override
public Void doInBackground() {
try {
ed.deleteQuery(name1);
} catch (SQLException ex) {
Logger.getLogger(MyFrame.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("deleteing isuse is " + ex);
}
return null;
}
#Override
public void done() {
if (jTable1.getSelectedRow() >= 0) {
tm.removeRow(jTable1.getSelectedRow());
} else {
System.out.println("nothing is selected");
}
name.setText("");
tel.setText("");
ed.printData();
JOptionPane.showMessageDialog(null, "Task completed");
}
}
Please be kind and help to find out where my problem is.
Please inform me if you need more information from me.
Your basic code in the ActionListener is overly complicated.
Code invoked within a listener executes on the Event Dispatch Thread, so there is no need for the SwingUtilities.invokeLater()
for the same reason you don't need the synchronize block.
I would place all the code in the SwingWorker. That is, first you should delete the data from the database (since this is the functionality that is most likely to fail). If the deletete completes successfully then I would remove the row from the TableModel. So you could need to "publish" the row that you want to be deleted within the doInBackground() method. Then the code that executes in the process() method of the SwingWorker will automatically run on the EDT.
See Tasks That Have Intermediate Results for more information.
I have code which I have been using for years and this morning I noticed property change isn't being called when the task is done. I've got the swing worker set up as an inner class and I put a break point on the String properyName = evt..... and it never hits the break point.
void loadData() {
work2 = new bkgdLoadData();
work2.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if( propertyName.equals("state")) {
SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
if( state == SwingWorker.StateValue.DONE) {
work2 = null;
}
}
}
});
work2.execute();
}
You can see that I set the object work2 to null when the task is finished and now it is no longer being set to null. In the class I added a done routine which it hits when the doinbackground is finished. What is puzzling me is why the property change listener isn't triggered. Something must have changed without my noticing.
protected class bkgdLoadData extends SwingWorker<Integer, Object> {
#Override
protected Integer doInBackground() {
switch(bkgdMode) {
case 0:
doRead();
break;
case 1:
doWrite();
break;
case 2:
runRobot();
break;
}
return 0;
}
#Override
protected void done() {
int i=0;
i++;
}
}
The breakpoint at done is hit but no property change notice is delivered. (I put the done routine for the sole purpose of verifying that the swing worker knows that it is done.)
I looked at the documentation and I don't see that I have to manually fire off some sort of property change, so I am really, really stuck and would appreciate another pair of eyes to tell me what stupid mistake I am mistaking.
Thanks,
Ilan
It turned out my Java was corrupted. Removing JDK 1.6 and reinstalling it from the repository wasn't good enough.
My links in Netbeans to 1.6 got damamged and I had to reinstall Netbeans as well (going over to 7.3.1 in the process). Netbeans would not recognize the repository JDK 1.6 as valid so I had to go to Oracle and get the original version. Netbeans recognized the original and the problem I reported above was no longer a problem.
I removed the void done() routine since it had no purpose other than a place to put a break point. The code as such is OK. Thanks for the help.
I was building a small test tool with Java Swing using Netbeans IDE.
I am trying to update a label, which is somehow not getting 'repainted'/'refreshed'. I looked into a couple of similar questions on SO but was not able to resolve my problem.
private void excelFileChooserActionPerformed(java.awt.event.ActionEvent evt)
{
if(!JFileChooser.CANCEL_SELECTION.equals(evt.getActionCommand()))
{
String selectedFile = excelFileChooser.getSelectedFile().getAbsolutePath();
loaderLabel.setText("Please Wait..");
try {
//This is sort of a blocking call, i.e. DB calls will be made (in the same thread. It takes about 2-3 seconds)
processFile(selectedFile);
loaderLabel.setText("Done..");
missingTransactionsPanel.setVisible(true);
}
catch(Exception e) {
System.out.println(e.getMessage());
loaderLabel.setText("Failed..");
}
}
}
loaderLabel is a JLabel and the layout used is AbsoluteLayout.
So, my problem is "Please Wait..." is never shown. Although call to the method processFile takes about 2-3 seconds, "Please Wait..." is never shown. However, "Done..."/"Failed..." are shown.
If I add a popup (JOptionPane) before the call to processFile, "Please Wait.." is shown. I am not able to clearly understand why this is happening.
Is there a "good practice" that I should follow before a heavy method call? Do I need to call an explicit repaint/refresh/revalidate?
You need to call
processFile(selectedFile);
in another thread (not in the AWT thread). To do so you can do something like this :
Thread t = new Thread(){
public void run(){
processFile(selectedFile);
// now you need to refresh the UI... it must be done in the UI thread
// to do so use "SwingUtilities.invokeLater"
SwingUtilities.invokeLater(new Runnable(){
public void run(){
loaderLabel.setText("Done..");
missingTransactionsPanel.setVisible(true);
}
}
)
}
};
t.start();
Please not that I didn't work with swing for a long time, so there may be some syntax issues with this code.
Have you tried dispatching the call to the EDT with SwingUtilities.invokeLater() ?
http://www.javamex.com/tutorials/threads/invokelater.shtml