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
Related
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.
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.
I currently have a JTable that is populated with a series of data that forms the basis of a import screen. When I have finished selecting which updates I want or do not want, I press on the Apply button and the updates are applied successfully but the JTable does not fully update.
This is the code for the method that deals with applying the changes:
private void doProcessChanges() {
ChangeProcessor cp = new ChangeProcessor();
final List<Integer> rowsToRemove = new ArrayList<Integer>();
BeanTableModel<UpdateModel> model = (BeanTableModel<UpdateModel>) table.getModel();
for (int i=0; i<model.getRowCount(); i++) {
UpdateRow ur = mode.getObject(i);
if (ur.isAccepted() <> ChangeAcceptance.NO_ACTION) {
cp.processChange(ur);
rowsToRemove.add(i);
}
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
for (int row : rowsToRemove) {
model.removeObject(row);
model.fireTableDataChanged();
}
}
);
}
The method is called from within a SwingWorker thread as below:
SwingWorker<Object, Object> worker = new SwingWorker<Object, Object>() {
#Override
protected Object doInBackground() throws Exception {
doProcessChanges();
return null;
}
#Override
protected void done() {
try {
get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
I do not get any exceptions from executing this so I am I doing anything wrong?
Thanks in advance.
Your fragment shows incorrect synchronization. In particular, you access BeanTableModel, a subclass of AbstractTableModel, from the background thread. Instead, pass the List<Integer> rowsToRemove to your worker in its constructor.
Addendum: Instead of invokeLater(), you can update the TableModel in your implementation of process(), which executes on the EDT. Also, you shouldn't have to fireTableDataChanged(), which "Notifies all listeners that all cell values in the table's rows may have changed." The removeObject() implementation should fire the least pervasive event required to effect the change.
I have a button click event that will fire a swing worker thread which in return fire another thread to do a long calculation including writing a file. Then this file is read to draw some graphics. However drawing part never happens if i don't add a delay in between.. (It says file not found although the file is there..What is the better way to fix this without adding a delay..
private void buttonFragmentActionPerformed(java.awt.event.ActionEvent evt) {
try
{
ESIPlusFragmenterWorker epfw = new ESIPlusFragmenterWorker(10, sdfFile, cidSpectrum);
epfw.execute();
Thread.sleep(1000);
holder.molTable1.drawMolViewPanel(currDir+sep+"esiFragments"+sep+"esiFrag.sdf");
}
catch (Exception e)
{
e.printStackTrace();
}
}
Swing Worker
public class ESIPlusFragmenterWorker extends SwingWorker<Void, Void>{
int mzppm_;
String SDF_;
String spectrum_;
Double mion_;
MolTable holder_;
ESIPlusFragmenterWorker(int mzppm, String SDF, String spectrum)
{
mzppm_ = mzppm;
SDF_ = SDF;
spectrum_ = spectrum;
}
#Override
protected Void doInBackground() {
try
{
Molecule mol;
MolImporter importer = new MolImporter(SDF_);
ExecutorService te = Executors.newFixedThreadPool(1);
while ((mol = importer.read()) != null)
{
Runnable epf = new ESIPlusFragmenter(mol, spectrum_, mzppm_);
Thread t = new Thread(epf);
te.execute(epf);
}
importer.close();
te.awaitTermination(10, TimeUnit.MINUTES);
}
catch (Exception e)
{
//
}
finally
{
return null;
}
}
#Override
protected void done() {
try {
//
} catch (Exception e) {
//e.printStackTrace();
}
}
}
Never, never, never call Thread.sleep(...) on the EDT as this will put your entire GUI to sleep. And besides, what if you estimate wrong, and the background process takes longer than your sleep delay time?
One possible solution is to add a PropertyChangeListener to the SwingWorker and listen on the "state" property for the SwingWorker.StateValue to be SwingWorker.StateValue.DONE, then do your drawing.
e.g.
private void buttonFragmentActionPerformed(java.awt.event.ActionEvent evt) {
try {
ESIPlusFragmenterWorker epfw = new ESIPlusFragmenterWorker(10,
sdfFile, cidSpectrum);
epfw.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if ("state".equals(pcEvt.getPropertyName())) {
if (pcEvt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
holder.molTable1.drawMolViewPanel(currDir + sep
+ "esiFragments" + sep + "esiFrag.sdf");
}
}
}
});
epfw.execute();
So what this does is waits until the SwingWorker has completed its business before calling the code inside of the listener.
Another option is to call your holder.molTable1.drawMolViewPanel inside of the SwingWorker's done() method, and this will work too, but by doing it as noted above with a PropertyChangeListener, the SwingWorker doesn't have to have any knowledge about the code called in the listener (as opposed to using SwingWorker's done() method), and this may allow for looser coupling.
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();
}
}
}
}