How to wait till SWT browser finishes loading? - java

I am using a SWT browser in my application. I need to run a script on HTML page in the browser. But the script is being run before the page is completely loaded. So how do i make the app wait till the browser finishes loading. I have tried something like this.
completed = true;
browser.addProgressListener(new ProgressListener() {
#Override
public void completed(ProgressEvent event) {
completed = true; //say this is a global variable
}
#Override
public void changed(ProgressEvent event) {
completed = false;
System.out.println("Page changing");
}
});
//some other method
void m1()
{
browser.setText("blah blah blah");
while (completed == false)
{}
// EXECUTE THE SCRIPT NOW
}
But this does not work!
This is similar to Java SWT browser: Waiting till dynamic page is fully loaded but there is no solution.

You can define a BrowserFunction and call it from the JavaScript code:
public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
Browser browser = new Browser(shell, SWT.NONE);
new CustomFunction(browser, "theJavaFunction");
browser.setText("<style>#map { width: 100%; height: 300px; }</style><script src='http://maps.google.com/maps/api/js?sensor=false'></script><div id='map'></div><script>var map;function initialize() { var mapOptions = { zoom: 8, center: new google.maps.LatLng(-34.397, 150.644) }; map = new google.maps.Map(document.getElementById('map'), mapOptions);} google.maps.event.addDomListener(window, 'load', initialize);window.onload = function () { theJavaFunction(); };</script>");
shell.pack();
shell.setSize(600, 400);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
private static class CustomFunction extends BrowserFunction
{
CustomFunction(Browser browser, String name)
{
super(browser, name);
}
#Override
public Object function(Object[] arguments)
{
System.out.println("theJavaFunction() called from javascript");
return null;
}
}

Baz gives the direction to the correct answer. I will attempt to put his answer in your context:
private boolean loading; // Instance variable
createBrowserControl() { // Browser widget definition method
Browser b = ...; // Create the browser widget
browser.addProgressListener(new ProgressListener() {
#Override
public void completed(ProgressEvent event) {
loading = false;
}
#Override
public void changed(ProgressEvent event) {
loading = true;
}
});
}
public boolean loadPage(String url) {
Display display = ... // Get the display from the UI or the widget
boolean set = browser.setUrl(url); // URL content loading is asynchronous
loading = true;
while(loading) { // Add synchronous behavior: wait till it finishes loading
if(!display.readAndDispatch()) {
display.sleep();
}
}
return set;
}

Related

Is there a way to make a SWT shell moveable and on top?

I'm trying to make a dialog stay on top of it's parent. The following code is similar to what I've done with the child dialog, minus the passing in of a parent. I started out by writing the following code:
public static void main(String [] args)
{
final Display display = new Display();
final Shell shell = new Shell(display, SWT.ON_TOP);
shell.setLayout(new FillLayout());
shell.open();
while(!shell.isDisposed())
{
if(!display.readAndDispatch())
{
display.sleep();
}
}
}
This causes the dialog to remain on top, but now I'm no longer able to move it. I tried updating the call to the shell's constructor to:
final Shell shell = new Shell(display, SWT.ON_TOP | SWT.DIALOG_TRIM);
and
final Shell shell = new Shell(display, SWT.ON_TOP | SWT.SHELL_TRIM);
Both of these options allows me to change the size of the dialog by clicking and dragging on the border around the window but does not allow me to move the dialog.
The only thing I found online was to add a listener for mouse events and do the moving myself:
Listener l = new Listener()
{
Point origin;
#Override
public void handleEvent(Event pEvent)
{
switch(pEvent.type)
{
case SWT.MouseDown:
origin = new Point(pEvent.x, pEvent.y);
break;
case SWT.MouseUp:
origin = null;
break;
case SWT.MouseMove:
if(origin != null)
{
Point p = display.map(shell, null, pEvent.x, pEvent.y);
shell.setLocation(p.x - origin.x, p.y - origin.y);
}
break;
}
}
};
shell.addListener(SWT.MouseDown, l);
shell.addListener(SWT.MouseUp, l);
shell.addListener(SWT.MouseMove, l);
shell.open(); //Rest of code as above
I found this suggestion at: http://jexp.ru/index.php/Java_Tutorial/SWT/Shell
Is there anyway to create a dialog in SWT that is always on top and has the same look, feel and interactions of a default SWT dialog (a dialog with style: SWT.SHELL_TRIM) without having to write my own listener?
You need use own listeners. Below code should help:-
public class Demo {
static Boolean blnMouseDown=false;
static int xPos=0;
static int yPos=0;
public static void main(final String[] args) {
Display display=new Display();
final Shell shell = new Shell( Display.getDefault(), SWT.RESIZE);
shell.open();
shell.addMouseListener(new MouseListener() {
#Override
public void mouseUp(MouseEvent arg0) {
// TODO Auto-generated method stub
blnMouseDown=false;
}
#Override
public void mouseDown(MouseEvent e) {
// TODO Auto-generated method stub
blnMouseDown=true;
xPos=e.x;
yPos=e.y;
}
#Override
public void mouseDoubleClick(MouseEvent arg0) {
// TODO Auto-generated method stub
}
});
shell.addMouseMoveListener(new MouseMoveListener() {
#Override
public void mouseMove(MouseEvent e) {
// TODO Auto-generated method stub
if(blnMouseDown){
shell.setLocation(shell.getLocation().x+(e.x-xPos),shell.getLocation().y+(e.y-yPos));
}
}
});
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.close();
}
}

Java SWT and Invalid Thread Access

I've seen this but it doesn't work for my code. This is my unique class:
public static void main(String[] args) {
try {
Main window = new Main();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
public void open() {
Display display = Display.getDefault();
createContents();
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
protected void createContents() {
shell = new Shell(SWT.CLOSE | SWT.MIN | SWT.TITLE | SWT.ON_TOP);
shell.setSize(301, 212);
shell.setText("MyShell");
// ...Other contents...
btn = new Button(shell, SWT.NONE);
btn.setBounds(114, 151, 76, 25);
btn.setText("BUTTON!");
btn.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
doSomething();
}
});
}
The method doSomething() is a caller for another method, like this:
private void doSomething()
{
Thread th = new Thread() {
public void run() {
threadMethod();
}
};
th.start();
}
When I click my button, an "Invalid Thread Access" raises from Thread-0, and it points to the first instruction of threadMethod() (wich doesn't access to UI widgets). I've tried to surround my button listener with
Display.getDefault().asyncExec(new Runnable() {
public void run() {
// ...
}
});
but it doesn't work either. I need the doSomething() method because it checks some code before creating the thread.
This is threadMethod()
private void threadMethod()
{
String[] listItems = list.getItems();
String fileName;
Path source, target;
File folder = new File(dir + File.separator);
if (!folder.exists()) {
folder.mkdir();
}
try
{
for(int i = 0; i < list.getItemCount(); i++)
{
// do something with non UI widgets
}
list.removeAll();
}
catch(IOException | InterruptedException e)
{
//print error
}
}
Why I've got Invalid thread access? Thank you!
List is an SWT widget and if you call the getItems() method on it outside of the UI Thread (in this case your main thread), you get an ERROR_THREAD_INVALID_ACCESS SWTException. This is defined in the List API: ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
The Thread that created the receiver, is the the thread that created the Display. If a Display does not exist, the first call to Display.getDefault() creates one. Therefore your main thread, which calls the open() method, is the UI thread. Your code will work if you wrap the contents of the threadMethod():
private void threadMethod() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
// threadMethod contents
}
});
}
It will then be executed in the UI thread.

SWT application showing updated display in near realtime

Question:
Can you show any simple example or explanation of SWT display part(which updates the window/shell)? Or can you any sites that you think they are the best for SWT application development?
Background:
I am new to SWT application and currently building an application for running some tests.
It has a main display shell class with text area which keeps getting updated after user clicked on a run button.
The run button starts another thread process which updates public static object such as AtomicCounter in the StartView class.
Current Stage
The program seems running well, however, it does not update the text area in realtime.
Well, I can't say realtime but it shows a little bit delayed information.(I can say it's delayed because I print out on the console as well)
It seems like I don't understand displaying concept of SWT well enough to do whatever I am trying to do with it.
Goal
A. Main Display class which starts and stops C regardless of B running or not
B. Threaded process which updates text area of A class with public static object of A
C. Threaded process which does its job and updating public static object of A
Example Code (Working Code)
public class UnitTest {
public static Display display;
private Shell shell;
public static AtomicInteger counter = new AtomicInteger(0);
public static Text text;
private TestThread test1 = null, test2 = null;
public UnitTest()
{
display = Display.getDefault();
this.shell = new Shell(display, SWT.CLOSE);
this.shell.setSize(226, 120);
text = new Text(shell, SWT.BORDER);
text.setBounds(10, 10, 199, 19);
Button btnStart = new Button(shell, SWT.NONE);
btnStart.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent arg0) {
test1 = new TestThread();
test1.start();
test2 = new TestThread();
test2.start();
}
});
btnStart.setBounds(10, 54, 94, 28);
btnStart.setText("Start");
Button btnStop = new Button(shell, SWT.NONE);
btnStop.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent arg0) {
test1.interrupt();
test2.interrupt();
counter.set(0);
}
});
btnStop.setBounds(115, 54, 94, 28);
btnStop.setText("Stop");
this.shell.open();
this.shell.layout();
this.shell.addListener(SWT.Close, new Listener(){
public void handleEvent(Event event)
{
shell.dispose();
}
});
while(!this.shell.isDisposed())
{
if(!display.readAndDispatch())
{
//text.setText(""+counter.get());
display.sleep();
}
}
}
public static void main(String[] args)
{
new UnitTest();
}
}
class TestThread extends Thread
{
public void run()
{
try
{
int i = 0;
while(i++ < 1000 && !this.isInterrupted() )
{
UnitTest.counter.getAndIncrement();
try {
TestThread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
break;
}
if(UnitTest.display.isDisposed())
return;
UnitTest.display.asyncExec(new Runnable() {
public void run() {
if (UnitTest.text.isDisposed())
return;
UnitTest.text.setText(""+UnitTest.counter.get());
}
});
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
System.out.println("Existing thread...");
}
}
}
You should carefully use UI updates from separate threads. Please, read this:
http://goo.gl/At8hC

SWT - Inheriting parent dialog shell?

I am really needing to understand how parent/child dialogs work.
My users use a OTB Application called Teamcenter. I am writing a add on application that is invoked from a menu selection in the Teamcenter Application.
When they click the menu item, that executes a handler class and that creates the base dialog for my application.
public class AplotDialogHandler extends AbstractHandler {
private static AplotBaseDialog dlg = null;
public AplotDialogHandler() {
}// end Constructor
//////////////////////////////////////////////////////////////////////////
// execute() //
//////////////////////////////////////////////////////////////////////////
#Override
public Object execute(final ExecutionEvent event) throws ExecutionException {
if (dlg == null) {
try {
AbstractAIFApplication app = AIFDesktop.getActiveDesktop().getCurrentApplication();
TCSession session = (TCSession) app.getSession();
TCUserService userService = session.getUserService();
AplotVersion.negotiateVersion(userService);
AplotQueryCapabilities.initialize(userService);
dlg = new AplotBaseDialog(null, session);
}
catch (Exception ex) {
MessageBox.post(HandlerUtil.getActiveWorkbenchWindowChecked(event).getShell(), ex, true);
}
}
dlg.create();
dlg.getShell().setSize(700, 400);
dlg.open();
return null;
}// end execute()
}// end EdiDialogHandler()
Question 1. It seems like my application is not tied to the Teamcenter application. Meaning that I can close Teamcenter and my Application stays open.
Question 2. Should I get the workspace shell and pass it in the base dialog?
But even when my application is open, the user still needs to be able to use the Teamcenter application to select data to send to my application
Question 3. When opening dialogs from my base dialog, should I always pass the base dialog shell to those dialogs?
Question 4. Is there a standard way I should close down the dialogs when the user is done?
You need to pass the parent Shell to the dialog so that when you close parent shell, child shells will also be closed.
You should make your dialog MODELESS ( use SWT.MODELSS as style. Note: it is Hint) so that it will not block your parent shell.
Here is sample code:
public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
shell.setSize(200, 200);
Button b = new Button(shell, SWT.NONE);
b.setText("Click");
b.addSelectionListener(new SelectionListener() {
#Override
public void widgetSelected(SelectionEvent e) {
CDialog dialog = new CDialog(shell);
dialog.open();
}
#Override
public void widgetDefaultSelected(SelectionEvent e) {
// TODO Auto-generated method stub
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
private static class CDialog extends Dialog
{
/**
* #param parentShell
*/
protected CDialog(Shell parentShell) {
super(parentShell);
}
/* (non-Javadoc)
* #see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
*/
#Override
protected Control createDialogArea(Composite parent) {
Composite comp = (Composite) super.createDialogArea(parent);
Label lbl = new Label(comp, SWT.NONE);
lbl.setText("Test modeless dialog");
return comp;
}
/* (non-Javadoc)
* #see org.eclipse.jface.window.Window#getShellStyle()
*/
#Override
protected int getShellStyle() {
return SWT.DIALOG_TRIM|SWT.MODELESS;
}
}

SWT - Grey out and disable current shell

When I have a operation running in the back ground, I am setting my cursor to busy until the process completes. Is there a way to also grey out and disable the current Display/Dialog/Shell until the process completes. I want to visually let the user know that something is working and they have to wait.
EDIT
plotButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event arg0) {
getShell().setEnabled(!getShell().getEnabled());
getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
recursiveSetEnabled(getShell(), getShell().getEnabled());
startPrinterListOperation(); <== This is method that runs operation
}
});
Method that runs a printer operation.
private void startPrinterListOperation() {
listOp = new AplotPrinterListOperation(appReg.getString("aplot.message.GETPRINTERLIST"), session);
listOp.addOperationListener(new MyOperationListener(this) {
public void endOperationImpl() {
try {
printers.clear();
printers.addAll((ArrayList<PrinterProfile>) listOp.getPrinters());
Display.getDefault().asyncExec(new Runnable() {
public void run() {
showAplotPlotterDialog(); <== When operation returns - opens selection dialog
}
});
}
finally {
listOp.removeOperationListener(this);
listOp = null;
}
}
});
session.queueOperation(listOp);
} // end startPrinterListOperation()
showAplotPlotterDialog() (Seperate Class) opens a dialog with network printers, then with a button push sends a job to the selected printer. When that operation finishes the Plotter Dialog closes - This is the end of that method - baseDialog is the MAIN GUI
finally {
plotOp.removeOperationListener(this);
plotOp = null;
Display.getDefault().asyncExec(new Runnable() {
public void run() {
baseDialog.removeAllTableRows();
baseDialog.plotRequestCompleted = true;
baseDialog.setResultsButtonVisibility();
getShell().close();
}
});
}
The following should do what you want. It will recursively disable and grey out all the Controls in your Shell. The Shell itself does not have a setGrayed method, but this will work:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
Button button = new Button(shell, SWT.PUSH);
button.setText("Button");
button.addListener(SWT.Selection, new Listener() {
#Override
public void handleEvent(Event arg0) {
shell.setEnabled(!shell.getEnabled());
shell.setCursor(new Cursor(display, SWT.CURSOR_WAIT));
recursiveSetEnabled(shell, shell.getEnabled());
}
});
new Text(shell, SWT.NONE).setText("TEXT");
shell.setSize(400, 400);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private static void recursiveSetEnabled(Control control, boolean enabled) {
if (control instanceof Composite)
{
Composite comp = (Composite) control;
for (Control c : comp.getChildren())
recursiveSetEnabled(c, enabled);
}
else
{
control.setEnabled(enabled);
}
}
Use
BusyIndicator.showWhile(Display.getDefault(), new Runnable()
{
public void run()
{
//operation
}
});
It sets the busy cursor on all Shells (Window, Dialog, ...) for the current Display until the Runnable.run() is executed.
Baz's answer was a great start for me, but doesn't act on Combo since it extends Composite. By making the call to setEnabled unconditional, every Control (including Combo) are enabled/disabled correctly.
private static void recursiveSetEnabled(Control control, boolean enabled) {
if (control instanceof Composite)
{
Composite comp = (Composite) control;
for (Control c : comp.getChildren())
recursiveSetEnabled(c, enabled);
}
control.setEnabled(enabled);
}

Categories