Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Standard Widget Toolkit (SWT) » Forcr UI update
Forcr UI update [message #554846] Tue, 24 August 2010 14:18 Go to next message
Mauro Condarelli is currently offline Mauro CondarelliFriend
Messages: 428
Registered: September 2009
Senior Member
Hi,
is there some way to progrmmatically ensure all UI updates are performed?

Situation is:
I have a long computation done asynchronously in a Job.
Job updates a progressMonitor.
At Job termination I need to transfer a long (>700k)String to a Text
widget (txtWid.setText(hugeString)).
This operation, on the very first time, takes a long time (>10s.),
second iteration is much faster (<2s.)
The update is done via syncExec().
During this period the UI is freezed (normal!)
Problem is the progress monitor "lags behind" at the moment of the
freeze (it should be at 90%, but fisually is at 30%)
I thus suspect the UI updates are cached somehow and the single
wid.setText() blocks everything.

This is the code I'm using:

final Book book = (Book) o;
final Job job = new Job("Assemble") {

@Override
protected IStatus run(final IProgressMonitor monitor) {
final SubMonitor progress = SubMonitor.convert(monitor, 100);
progress.setTaskName("Assemble LaTeX");

IStatus status = assemble(book, progress.newChild(80));

progress.subTask("Save");
if (status.isOK()) {

// vvvv Tried to force update vvvv
try {
Thread.sleep(2000);
} catch (InterruptedException e) {}
// ^^^^ Tried to force update ^^^^

Display.getDefault().syncExec(new Runnable() {
public void run() {
if (tset != null) {
tset.setBookTitle(title);
tset.setLaTeX(tex); // << here is wid.setText(tex)
ready = true;
}
}
});
} else {
Display.getDefault().syncExec(new Runnable() {
public void run() {
MessageDialog.openError(shell, "Unable to Assemble",
"Assemble error");
ready = false;
}
});

}
progress.worked(20);
return status;
}
};
job.setUser(true);
job.schedule();


Notice the part:
// vvvv Tried to force update vvvv
try {
Thread.sleep(2000);
} catch (InterruptedException e) {}
// ^^^^ Tried to force update ^^^^
This seems absolutely necessary to have the progress monitor behave
correctly.

In order to avoid a fixed amount of time I tried the following (and
several other variations), but it doesn't work;

// vvvv Tried to force update vvvv
Display.getDefault().syncExec(new Runnable() {
public void run() {
Display.getCurrent().update();
book.notify();
}
});
try {
book.wait(); // << line 111
} catch (InterruptedException e) {}
// ^^^^ Tried to force update ^^^^

this rises an error:
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at
it.condarelli.writer.commands.AssembleLaTeX$1.run(AssembleLa TeX.java:111)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)

Other combinations simply do not work.

Can someone please tell me what is the Right Way (TM) to ensure UI is
fully updated before doing something this long?

Sub-question:
Is it normal there's this long delay the first time I fill a Text widget
with a lot of stuff?
I thought it might be due to some class loading or repeated need to
enlarge the underlying text structures (I don't know which).
If so: is there some way to "preallocate"?
One second delay (on a fast computer!) is acceptable, 10s+ isn't.


Thanks in advance.
Mauro
Re: Forcr UI update [message #554903 is a reply to message #554846] Tue, 24 August 2010 16:35 Go to previous messageGo to next message
Mariot Chauvin is currently offline Mariot ChauvinFriend
Messages: 174
Registered: July 2009
Senior Member
Hi Mauro,

You may try this :

/**
* Wait the end of the asynchronous calls waiting in UI thread.
*/
public static void synchronizationWithUIThread() {
while (PlatformUI.getWorkbench().getDisplay().readAndDispatch()) {
// Do nothing, just wait
}
}

Regards,

Mariot

Mauro Condarelli a écrit :
> Hi,
> is there some way to progrmmatically ensure all UI updates are performed?
>
> Situation is:
> I have a long computation done asynchronously in a Job.
> Job updates a progressMonitor.
> At Job termination I need to transfer a long (>700k)String to a Text
> widget (txtWid.setText(hugeString)).
> This operation, on the very first time, takes a long time (>10s.),
> second iteration is much faster (<2s.)
> The update is done via syncExec().
> During this period the UI is freezed (normal!)
> Problem is the progress monitor "lags behind" at the moment of the
> freeze (it should be at 90%, but fisually is at 30%)
> I thus suspect the UI updates are cached somehow and the single
> wid.setText() blocks everything.
>
> This is the code I'm using:
>
> final Book book = (Book) o;
> final Job job = new Job("Assemble") {
>
> @Override
> protected IStatus run(final IProgressMonitor monitor) {
> final SubMonitor progress = SubMonitor.convert(monitor, 100);
> progress.setTaskName("Assemble LaTeX");
>
> IStatus status = assemble(book, progress.newChild(80));
>
> progress.subTask("Save");
> if (status.isOK()) {
>
> // vvvv Tried to force update vvvv
> try {
> Thread.sleep(2000);
> } catch (InterruptedException e) {}
> // ^^^^ Tried to force update ^^^^
>
> Display.getDefault().syncExec(new Runnable() {
> public void run() {
> if (tset != null) {
> tset.setBookTitle(title);
> tset.setLaTeX(tex); // << here is wid.setText(tex)
> ready = true;
> }
> }
> });
> } else {
> Display.getDefault().syncExec(new Runnable() {
> public void run() {
> MessageDialog.openError(shell, "Unable to Assemble",
> "Assemble error");
> ready = false;
> }
> });
>
> }
> progress.worked(20);
> return status;
> }
> };
> job.setUser(true);
> job.schedule();
>
>
> Notice the part:
> // vvvv Tried to force update vvvv
> try {
> Thread.sleep(2000);
> } catch (InterruptedException e) {}
> // ^^^^ Tried to force update ^^^^
> This seems absolutely necessary to have the progress monitor behave
> correctly.
>
> In order to avoid a fixed amount of time I tried the following (and
> several other variations), but it doesn't work;
>
> // vvvv Tried to force update vvvv
> Display.getDefault().syncExec(new Runnable() {
> public void run() {
> Display.getCurrent().update();
> book.notify();
> }
> });
> try {
> book.wait(); // << line 111
> } catch (InterruptedException e) {}
> // ^^^^ Tried to force update ^^^^
>
> this rises an error:
> java.lang.IllegalMonitorStateException
> at java.lang.Object.wait(Native Method)
> at java.lang.Object.wait(Object.java:485)
> at
> it.condarelli.writer.commands.AssembleLaTeX$1.run(AssembleLa TeX.java:111)
> at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
>
> Other combinations simply do not work.
>
> Can someone please tell me what is the Right Way (TM) to ensure UI is
> fully updated before doing something this long?
>
> Sub-question:
> Is it normal there's this long delay the first time I fill a Text widget
> with a lot of stuff?
> I thought it might be due to some class loading or repeated need to
> enlarge the underlying text structures (I don't know which).
> If so: is there some way to "preallocate"?
> One second delay (on a fast computer!) is acceptable, 10s+ isn't.
>
>
> Thanks in advance.
> Mauro
Re: Forcr UI update [message #554909 is a reply to message #554903] Tue, 24 August 2010 17:01 Go to previous messageGo to next message
Mauro Condarelli is currently offline Mauro CondarelliFriend
Messages: 428
Registered: September 2009
Senior Member
Il 24/08/2010 18:35, Mariot Chauvin ha scritto:
> Hi Mauro,
>
> You may try this :
>
> /**
> * Wait the end of the asynchronous calls waiting in UI thread.
> */
> public static void synchronizationWithUIThread() {
> while (PlatformUI.getWorkbench().getDisplay().readAndDispatch()) {
> // Do nothing, just wait
> }
> }
>
> Regards,
>

It doesn't work.

If I call it from my job I get:

!ENTRY org.eclipse.core.jobs 4 2 2010-08-24 18:51:06.641
!MESSAGE An internal error occurred during: "Assemble".
!STACK 0
org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(SWT.java:4083)
at org.eclipse.swt.SWT.error(SWT.java:3998)
at org.eclipse.swt.SWT.error(SWT.java:3969)
at org.eclipse.swt.widgets.Display.error(Display.java:1249)
at org.eclipse.swt.widgets.Display.checkDevice(Display.java:755 )
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java :3646)
at
it.condarelli.writer.commands.AssembleLaTeX$1.run(AssembleLa TeX.java:118)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)

which is reasonable, if I call it from the UI thread (via syncExec) it
simply does nothing, which, again, is reasonable since the loop is
executed exactly zero times.

OTOH a delay of about 600ms seems necessary to complete all painting.
Does SWT do some background painting?
readAndDispatch() seems to just queue operations and not actually
performing them.
Is this possible?

Regards
Mauro

> Mariot
>
> Mauro Condarelli a écrit :
>> Hi,
>> is there some way to progrmmatically ensure all UI updates are performed?
>>
>> Situation is:
>> I have a long computation done asynchronously in a Job.
>> Job updates a progressMonitor.
>> At Job termination I need to transfer a long (>700k)String to a Text
>> widget (txtWid.setText(hugeString)).
>> This operation, on the very first time, takes a long time (>10s.),
>> second iteration is much faster (<2s.)
>> The update is done via syncExec().
>> During this period the UI is freezed (normal!)
>> Problem is the progress monitor "lags behind" at the moment of the
>> freeze (it should be at 90%, but fisually is at 30%)
>> I thus suspect the UI updates are cached somehow and the single
>> wid.setText() blocks everything.
>>
>> This is the code I'm using:
>>
>> final Book book = (Book) o;
>> final Job job = new Job("Assemble") {
>>
>> @Override
>> protected IStatus run(final IProgressMonitor monitor) {
>> final SubMonitor progress = SubMonitor.convert(monitor, 100);
>> progress.setTaskName("Assemble LaTeX");
>>
>> IStatus status = assemble(book, progress.newChild(80));
>>
>> progress.subTask("Save");
>> if (status.isOK()) {
>>
>> // vvvv Tried to force update vvvv
>> try {
>> Thread.sleep(2000);
>> } catch (InterruptedException e) {}
>> // ^^^^ Tried to force update ^^^^
>>
>> Display.getDefault().syncExec(new Runnable() {
>> public void run() {
>> if (tset != null) {
>> tset.setBookTitle(title);
>> tset.setLaTeX(tex); //<< here is wid.setText(tex)
>> ready = true;
>> }
>> }
>> });
>> } else {
>> Display.getDefault().syncExec(new Runnable() {
>> public void run() {
>> MessageDialog.openError(shell, "Unable to Assemble",
>> "Assemble error");
>> ready = false;
>> }
>> });
>>
>> }
>> progress.worked(20);
>> return status;
>> }
>> };
>> job.setUser(true);
>> job.schedule();
>>
>>
>> Notice the part:
>> // vvvv Tried to force update vvvv
>> try {
>> Thread.sleep(2000);
>> } catch (InterruptedException e) {}
>> // ^^^^ Tried to force update ^^^^
>> This seems absolutely necessary to have the progress monitor behave
>> correctly.
>>
>> In order to avoid a fixed amount of time I tried the following (and
>> several other variations), but it doesn't work;
>>
>> // vvvv Tried to force update vvvv
>> Display.getDefault().syncExec(new Runnable() {
>> public void run() {
>> Display.getCurrent().update();
>> book.notify();
>> }
>> });
>> try {
>> book.wait(); //<< line 111
>> } catch (InterruptedException e) {}
>> // ^^^^ Tried to force update ^^^^
>>
>> this rises an error:
>> java.lang.IllegalMonitorStateException
>> at java.lang.Object.wait(Native Method)
>> at java.lang.Object.wait(Object.java:485)
>> at
>> it.condarelli.writer.commands.AssembleLaTeX$1.run(AssembleLa TeX.java:111)
>> at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
>>
>> Other combinations simply do not work.
>>
>> Can someone please tell me what is the Right Way (TM) to ensure UI is
>> fully updated before doing something this long?
>>
>> Sub-question:
>> Is it normal there's this long delay the first time I fill a Text widget
>> with a lot of stuff?
>> I thought it might be due to some class loading or repeated need to
>> enlarge the underlying text structures (I don't know which).
>> If so: is there some way to "preallocate"?
>> One second delay (on a fast computer!) is acceptable, 10s+ isn't.
>>
>>
>> Thanks in advance.
>> Mauro
Re: Forcr UI update [message #555053 is a reply to message #554909] Wed, 25 August 2010 10:11 Go to previous message
Vijay RajFriend
Messages: 608
Registered: July 2009
Senior Member
modify the code to
 /**
 * Wait the end of the asynchronous calls waiting in UI thread.
 */
public static void synchronizationWithUIThread() {
Display.getDefault().sysncExec(new Runnable(){
while (Display.getDefault().readAndDispatch()) {
 // Do nothing, just wait
 }
 }
});


but i doubt this will solve your hanging problem on settext method,
for that may be you have to innovate...

may be use text.append method by breaking your text into small peaces
and providing a UI feedback that the text control is being loaded by GC or by a animated giff lable near your text control
all this can be done in a asyncExec which after each append or after n no of append calls ,
call Dispaly.getDefault().readAndDispatch();

for example

package winctr;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.SWT;




public class NewComposite extends org.eclipse.swt.widgets.Composite {
	private Text text1;
	private Text text2;

	
	public static void main(String[] args) {
		showGUI();
	}

	
	public static void showGUI() {
		Display display = Display.getDefault();
		Shell shell = new Shell(display);
		NewComposite inst = new NewComposite(shell, SWT.NULL);
		Point size = inst.getSize();
		shell.layout();
		shell.setLayout(new FillLayout());
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
	}

	public NewComposite(org.eclipse.swt.widgets.Composite parent, int style) {
		super(parent, style);
		initGUI();
	}

	private void initGUI() {
		try {
			GridLayout thisLayout = new GridLayout();
			thisLayout.makeColumnsEqualWidth = true;
			thisLayout.numColumns = 2;
			this.setLayout(thisLayout);
			{
				text1 = new Text(this, SWT.MULTI | SWT.WRAP | SWT.H_SCROLL
						| SWT.V_SCROLL | SWT.BORDER);
				GridData text1LData = new GridData(GridData.FILL_BOTH);
				text1.setLayoutData(text1LData);
				text1.setText("text1");
			}
			{
				text2 = new Text(this, SWT.MULTI | SWT.WRAP | SWT.H_SCROLL
						| SWT.V_SCROLL | SWT.BORDER);
				text2.setText("text2");
				GridData text2LData = new GridData(GridData.FILL_BOTH);
				text2.setLayoutData(text2LData);
			}
			text1.getDisplay().asyncExec(new Runnable(){

				public void run() {
					try {
						setText();
					} catch (FileNotFoundException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}					
				}
				
			});

			this.layout();
			pack();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void setText() throws FileNotFoundException, IOException {
		BufferedReader rd = new BufferedReader(new FileReader(new File(
				"c:\\spy.log")));
		text1.setText("");
		String line = null;
		try {
			do {
				line = rd.readLine();
				if (line != null) {
					text1.append(line);
					text1.getDisplay().readAndDispatch();
				}
				text1.append(Text.DELIMITER);
			} while (line != null);
		} finally {
			rd.close();
		}
	}

}


give a large file to the reader instead of spy.log
you can modify this code and instead of using asyncExec for settext method you can use a UIJob in you RCP application...

or

IWorbenchWindow.run(boolean fork, boolean cancelable, IRunnableWithProgress runnable)




---------------------
why, mr. Anderson, why, why do you persist?
Because I Choose To.
Regards,
Vijay
Previous Topic:Being notified when other shell is being closed
Next Topic:Clipboard problem on Windows
Goto Forum:
  


Current Time: Fri Oct 20 01:52:48 GMT 2017

Powered by FUDForum. Page generated in 0.01826 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software