I have a problem.
Here is the code:
JButton buttonChangeServer = new JButton("Change server");
buttonChangeServer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getLobbies();
}
}
});
private void getLobbies() {
lobbyListModel.removeAllElements();
statusLabel.setText("Connecting...");
final ArrayList<LobbyInfo> lobbyInfos =
UserClient.getLobbies(host, action, null);
if (lobbyInfos != null) {
setLobbies(lobbyInfos);
statusLabel.setText("Sucessfully got lobby list from " + getHost());
}
else {
statusLabel.setText("Failed to connect to " + getHost());
}
}
The UserClient.getLobbies(host, action, null) method executes for a 3 seconds (timeout) if it can not establish connection.
The problem is that this two operations
lobbyListModel.removeAllElements();
statusLabel.setText("Connecting...");
are not visible while executing.
I suppose that the problem is that the method getLobbies() in actionPerformed(ActionEvent e) executes in Swing thread, and all the GUI operations are not being shown till the end of the execution of the getLobbies();
My aim is to show all the changes of GUI, before and after the execution of UserClient.getLobbies(host, action, null);. How can I manage that? Is there an easy way to show all of them? Thank you.
P.S. One of the solutions may be putting that potentionally long operation in another thread, like this:
private void getLobbies() {
lobbyListModel.removeAllElements();
statusLabel.setText("Connecting...");
new Thread(new Runnable() {
#Override
public void run() {
final ArrayList<LobbyInfo> lobbyInfos =
UserClient.getLobbies(host, action, null);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (lobbyInfos != null) {
setLobbies(lobbyInfos);
statusLabel.setText("Sucessfully got lobby list from " + getHost());
}
else {
statusLabel.setText("Failed to connect to " + getHost());
}
}
});
}
}).start();
}
It works, but it is rather complicated. Are there any ways easier?
One of the solutions may be putting that potentially long operation in another thread
Yes, long operations (or blocking operations) should not execute on the EDT.
So you do need to execute the long running task on a separated Thread. Check out the section from the Swing tutorial on Worker Threads and Swing Worker for the Swing solution to this problem.
When your query finishes executing you can "publish" the results so the code is executed on the EDT when the Swing components are updated.
Related
I want JList to be populated with multiple threads.
I tried this way but jlist is empty.
It would be good if jlist was updated on the fly
There are two threads, the other one loads in anouther direction
new Thread(new Runnable() {
#Override
public void run() {
for(i=0; i<cells.size()/2; i++){
System.out.println("thread");
try{
HtmlPage p = client.getPage("https://tbilisi.embassytools.com/en/slotsReserve?slot="+cells.get(i).getAttribute("data-slotid"));
pages.add(p);
if(!p.getUrl().toString().contains("slotsReserve"))
model.add(i,p.getUrl().toString());
}
catch (Exception e){
e.printStackTrace();
}
}
}
});
list1.setModel(model)
Thanks in advance
UPDATE*
So I fixed by using SwingWorker
Swing is a single threaded framework, that is, it is expected that all updates and modifications to the UI are done from within the context of the Event Dispatching Thread.
Equally, you should do nothing in the EDT that might block or otherwise prevent it from processing the Event Queue (like downloading content from the web).
This raise a conundrum. Can't update the UI outside the EDT, need to use some kind of background process to execute time consuming/blocking tasks...
So long as the order of items is unimportant, you would use multiple SwingWorkers in place o of the Threads, for example...
DefaultListModel model = new DefaultListModel();
/*...*/
LoadWorker worker = new LoadWorker(model);
worker.execute();
/*...*/
public class LoaderWorker extends SwingWorker<List<URL>, String> {
private DefaultListModel model;
public LoaderWorker(DefaultListModel model) {
this.model = model;
}
protected void process(List<String> pages) {
for (String page : pages) {
model.add(page);
}
}
protected List<URL> doInBackground() throws Exception {
List<URL> urls = new ArrayList<URL>(25);
for(i=0; i<cells.size()/2; i++){
try{
HtmlPage p = client.getPage("https://tbilisi.embassytools.com/en/slotsReserve?slot="+cells.get(i).getAttribute("data-slotid"));
pages.add(p);
if(!p.getUrl().toString().contains("slotsReserve")) {
publish(p.getUrl().toString());
urls.add(p.getUrl());
}
}
catch (Exception e){
e.printStackTrace();
}
}
return urls;
}
}
This allows you execute your blocking/long running in the backround (doInBackground) and publish the results of this method which are then processed within the context of the EDT...
See Concurrency in Swing for more details
Swing is not thread safe you should use SwingUtilities to run multiple threads updating swing.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
doWhateverYouWant();
}
});
read more
Hi i got following problem...
I have main jframe started like this:
public static void main (String args[]){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Form3 myF=new Form3();
}
});
};
in the jframe i have Jpanels. On jpanel i want to start 2nd thread.
I tried it like this:
try {
while (DBAccess.haveResult("ASS"+harnessId)==null&&cancelCycle == 0) {
thread1.sleep(3*1000);
System.out.println("+++++++++");
System.out.println(DBAccess.haveResult("ASS"+harnessId));
res = DBAccess.haveResult("ASS"+harnessId);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
but I am unable to stop that thread and cant even cancel it, because main window stops reacting
to clarify my problem:
i have "Test" button on JPanel, which is starting test process. Test process consists of loop whiuch is repeating every 3 seconds, this loop checks database status. Problem is I am unable to stop this loop until the status appears in db (while condition), because window is busy after i click on "test". Even implementing runnable and putting test method into "run()" doesnt worked.
testbutton source code:
if (e.getActionCommand().equals("Test")){
run();}
run method:
#Override
public final void run() {
test();
}
test method:
Map result_row = DBAccess.addRow("ASS"+harnessId,htOperList.get(seqNumber-1).getNametestprogram(),"",null);
if(result_row.containsKey("ADDROW")){System.out.println("Record inserted" );}
Database db = null;
Map res = null;
try {
while (DBAccess.haveResult("ASS"+harnessId)==null&&cancelCycle == 0) {
thread1.sleep(3*1000);
System.out.println(DBAccess.haveResult("ASS"+harnessId));
res = DBAccess.haveResult("ASS"+harnessId);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
You are blocking the event dispatch thread. Use a SwingWorker for heavy tasks. Put the main DB operation in doInBackround(), and use publish() for the interim results.
If you need to stop it before doInBackround() completes, you can use cancel(). See here for notes about that.
Tons of JProgressBar questions on here I know, but through all the answers and I can't seem to diagnose my issue. I am processing a file with some address verification software. I click the Process button and I need my JProgressBar to update with each file processed.
Here is the button:
private JButton getJButton0() {
...
jButton0.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
jButton0ActionActionPerformed(event);
t.start();
}
...
Per everybody's recommendation, I used the setValue() method within a thread
Thread t = new Thread(){
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jProgressBar0.setValue(BulkProcessor.getPercentComplete());
}
});
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
...
BulkProcessor.getPercentComplete() is a method I'm calling from another class which represents the percentage complete. I have tested this method and it updates correctly. The issue is that the progress bar will not update until the files are finished processing, and then it will jump to 100%. I apologize if this is a repeat question, but I have done some serious digging on this site with no luck. Any help much appreciated.
Edit:
Per recommended duplicate, I tried this:
public void update(){
new SwingWorker<Void,Void>() {
protected Void doInBackground() throws Exception {
jProgressBar0.setValue(BulkProcessor.getPercentComplete());
return null;
};
}.execute();
}
And then tried calling this update() method under the actionPerformed() (switched t.start() with update()). I am still having the same issue.
Edit
Based on user1676075's recommendation, however same issue:
public static void update(){
new SwingWorker<Void,Integer>() {
protected Void doInBackground() throws Exception {
do
{
percentComplete = BulkProcessor.getPercentComplete();
publish(percentComplete);
Thread.sleep(100);
} while(percentComplete < 100);
return null;
}
#Override
protected
void process(List<Integer> progress)
{
jProgressBar0.setValue(progress.get(0));
}
}.execute();
}
Edit
Here is the code from my BulkProcessor class
private String getOutputLine( String searchString, String inputLine )
throws QasException
{
..(code for processing lines)..
countRecord++;
percentComplete = (int) Math.round((countRecord/totalRecord)*100);
totalRecord is updated in the main class of my BulkProcessor class
public static void main( String input, String output ){
count.clear();
try{
String inputFile = input;
String outputFile = output;
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(input)));
lnr.skip(Long.MAX_VALUE);
totalRecord = lnr.getLineNumber() + 1; //line count in file
BulkProcessor bulk = new BulkProcessor(inputFile, outputFile, ConfigManager.DFLT_NAME);
bulk.process();
}catch(Exception e ){
e.printStackTrace();
}
}
Looks like you're mixing usages. See the SwingWorker documentation, example at the top: http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html.
Ideally you'd update your BulkProcessor in the doInBackground method of the SwingWorker, and that would call setProgress, and the jProgressBar would be listening for those progress updates as in the example.
If that won't work for you, which it seems like it won't just based on the above, start a SwingWorker from the button press event. Implement the SwingWorker methods kinda like this (pseudocode):
new SwingWorker<Void,Integer>()
{
doInBackground()
{
do
{
percentComplete = BulkProcessor.getPercentComplete();
publish(percentCompete);
Thread.sleep(100);
} while (percentComplete < 100);
}
#Override
process(List<Integer> progress)
{
jProgressBar0.setValue(progress.get(0));
}
}.execute();
You'll need to add error-handling and checks for complete and failure cases, but that should get you started and to where you want to be. doInBackground runs in a background thread so won't block anything, and process() runs on the swing worker thread so will post the updates.
The mistake you probably went on is calling the t.start(); after thejButton0ActionPerformed(event); which makes that after the action is performed the thread will start. Therefore the value of the progress bar is not updated as intended.
You need to start the thread in jButton0ActionPerformed(event); and then update the value in it.
Just a hunch, but...
percentComplete = (int) Math.round((countRecord/totalRecord)*100);
Are you sure this is not integer arithmetic? I don't know the type of totalRecord, so I can't say for sure.
I'd guess everything works fine, and just the progress is 0 all the time, until complete where it magically is 100. This is because an int divided by an int will not have fraction values (ie. 99/100 == 0, 100/100 == 1). This fits perfectly with the symptoms you are experiencing.
Try replacing the line above with:
percentComplete = (int) Math.round((countRecord/(double) totalRecord)*100);
to see it I'm right. :-)
Have you tried to use the PropertyChangeListener-interface?
The calculations will be done by the Swingworker-thread and the main-gui will implement this interface. Some example-code
#Override
public void actionPerformed(ActionEvent e) {
this.myButton.setEnabled(false);
MyWorkerThread thread = new MyWorkerThread(); //Data-processing
thread.addPropertyChangeListener(this.mainguiframe); //Separation of concern
thread.execute();
}
Using the "setProgress"-method of the swing-worker-thread the main-gui-thread will be notified if something has happend.
#Override
public void propertyChange(PropertyChangeEvent property) {
Integer currentValue = new Integer(0);
currentValue = (Integer) property.getNewValue();
this.progressBar.setValue(currentValue.intValue());
}
Swing is not thread-safe. This is not the best solution but perhaps it can help you. Please comment if there is somethin horrible wrong.
private void StartActionPerformed(java.awt.event.ActionEvent evt) {
Queue queue=new Queue();
int target=Integer.parseInt(Target.getText());
String path=Path.getText();
final Producer p=new Producer(queue, target);
Consumer c=new Consumer(queue);
p.start();
c.start();
while(p.finish !=true)
{
Runnable r = new Runnable() {
public void run() {
ProgressPrecent.setValue(Producer.ProgressPercent);
}
};
if(EventQueue.isDispatchThread()) {
r.run();
}
else {
EventQueue.invokeLater(r);
}
}
}
I have two classes that have a shared Queue. one of them is Producer that produces till a target other one consume those elements. all of two extends Thread. I want to display the progress percent to the user, but it freeze my GUI so what should I do?
Worker Threads by default never to invoked EventDispatchThread, you have issue with Concurency in Swing
all updates to Swing GUI must be done on EDT
Runnable could be proper way but ProgressPrecent.setValue(Producer.ProgressPercent); must be wrapped in invokeLater
code
SwingUtilities.invokeLater(new Runnable(){
public void run(){
ProgressPrecent.setValue(Producer.ProgressPercent);
}
});
remove testing for EDT,
code lines
if(EventQueue.isDispatchThread()) {
r.run();
}
Workers Thread by defaut never ever to invoke EDT, then doesn't matter if is started from EDT, nor tested for isDispatchThread() doesn't make me some sence
never ever, don't to use Thread.sleep(int) inside Swing Listeners, because caused freeze Swing GUI too
I think you can to use SwingWorker for this job too
I think you will have to put the whole while loop into a thread. Otherwise the loop will block your ActionEvent and thus freezes the UI.
Something like:
new Thread(){
public void run(){
while(!p.finish){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
ProgressPrecent.setValue(Producer.ProgressPercent);
}
});
try{
Thread.sleep(100);
}catch(...){}
}
}
}.start();
Is there a way to wait for all Runnables submitted to the SWT UI Thread via asyncExec(...) to finish?
Background:
I have a long-running operation, which among other things is triggering events that in turn submit Runnables to the SWT UI thread via the asyncExec(...) instance method of Display.
The progress of the long-running operation is shown in a ProgressMonitorDialog, and I would like to close the dialog only after the UI thread has finished executing the Runnables.
Changing the calls from asyncExec(...) to syncExec(...) is not an option, as the latter is not desired when the events are triggered from other contexts.
org.eclipse.swt.widgets.Display.readAndDispatch() will process an event from the event queue and return false if there are no more events to process. But you probably don't want to use this as it processes an event.
asyncExec(*) is a FIFO queue (although OS graphics events supersede the asyncExecs), so you could do most of your long-running op processing and then place a final asyncExec in the queue:
final boolean[] done = new boolean[1];
Runnable r = new Runnable() {
public void run() {
done[0] = true;
}
};
// now wait for the event somehow. The brute force method:
while (!done[0]) {
Thread.sleep(200);
}
In theory, all of the other asyncExecs spawned from your long running op will be finished by the time you get to the last one.
EDIT: potential other option
Create your own org.eclipse.core.runtime.jobs.Job and then join() it at the end:
public static class RefCountJob extends Job {
public RefCountJob() {
super("REF_COUNT");
}
int count = 0;
public void increment() {
count++;
}
public void decrement() {
count--;
}
#Override
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask("WAITING", IProgressMonitor.UNKNOWN);
while (count > 0) {
Thread.sleep(200);
monitor.worked(1);
}
monitor.done();
return Status.OK_STATUS;
}
}
To use it, increment() it every time you are going to fire off events, and have them decrement it when they're done (You have to make sure they decrement it no matter what exception is thrown :-)
RefCountJob ref = new RefCountJob();
// ... do stuff, everybody increments and decrements ref
ref.increment();
// ... do more stuff
ref.increment();
// at the end of your long-running job
ref.schedule();
ref.join();
Thanks, I ended up with the following. I think it is a pretty clean solution. By the way I would upvote your answer if I had enough reputation for that :)
public class SWTThreadingUtils
{
public static void waitForAsyncExecsToFinish(Display display)
{
Object waitObj = new Object();
display.asyncExec(new DummyRunnable(waitObj));
synchronized (waitObj)
{
try {
waitObj.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
private static class DummyRunnable implements Runnable
{
private Object waitObj;
public DummyRunnable(Object waitObj)
{
this.waitObj = waitObj;
}
#Override
public void run()
{
synchronized (waitObj)
{
waitObj.notify();
}
}
}
}