How to catch first time displaying of the WizardPage - java

I'm writing a little wizard for Eclipse with some pages and I need to catch the moment of the first time page displaying.
I checked constructor and createControl but they are called in the creation moment in the Wizard object (addPages).
Is there a way to get what I need? Maybe somebody knows some trick?

You can override setVisible(boolean) method in your WizardPage. So for example use something like:
private boolean initialized = false;
#Override
public void setVisible(boolean visible) {
if (!initialized && visible) {
//do something
initialized = true;
}
control.setVisible(visible);
}

You can use a IPageChangedListener or a IpageChangingListener, registered on the WizardDialog. They will be notified when the current page of the wizard changes.

I prefer to remove the listener after first painting. That way you don't need an additional boolean field and you avoid unnecessary calling paintControl and checking that boolean every time.
container.addPaintListener(new PaintListener()
{
#Override
public void paintControl(PaintEvent e)
{
doUsefulStuff();
container.removePaintListener(this);
}
});

Ok, I created a listener for a paint event and used a flag m_isFirsTime, which controlled from Wizard class:
public void createControl(Composite parent) {
Composite container = new Composite(parent, SWT.NONE);
setControl(container);
container.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent arg0) {
if (m_isFirstTime) {
m_isFirstTime = false;
StartXMLParsing();
}
}
});
...
}
It is ok for me.

After controls created the async UI task executed where a long init operation can be performed. UI already created and shown when Runnable starts therefore wizard appears immediately and user can see initialization progress:
public void createControl(Composite parent) {
// create controls
getContainer().getShell().getDisplay().asyncExec(new Runnable() {
#Override
public void run() {
try {
getContainer().run(false, false, new IRunnableWithProgress() {
#Override
public void run(IProgressMonitor arg0) throws InvocationTargetException, InterruptedException {
// init and validate controls here
}
});
} catch (InvocationTargetException e) {
// handle e.getCause();
} catch (InterruptedException e) {
// nothing
}
}
});
}

Related

Using SWT DateSpinner with RAP does not dispose calendar widget on focus lost

I am working on a project where I need to use the SWT DateSpinner on a RAP application webpage. I brought the entire Datespinner API into my project and have made changes to accommodate it in the application. I am trying to dispose the calendar widget when the user clicks anywhere on the page outside the bounds of the calendar dropdown.
To accomplish this I tried adding a focus listener to the widget and the actual date spinner but the onFocusLost() method is never executed whenever the datespinner or the calendar composite lose focus. I also tried to add a mouse event listener where I try to dispose the widget if the mouse down event occurs outside the calendar composite bounds but that doesn't get executed either. The showCalendar() method is as shown:
private void showCalendar()
{
if (calendarDropDown != null && !calendarDropDown.isDisposed())
{
calendarDropDown.dispose();
}
calendarDropDown = new DropDown(this);
calendarDropDown.setUsingRelativeControlWidth(false);
Composite composite = calendarDropDown.getDropDown();
composite.setLayout(new FillLayout());
composite.setData(calendarToggle);
Calendar c = Calendar.getInstance();
Date date = this.getDate();
// get current date in the control
if (date != null)
{
c.setTime(this.getDate());
}
CalendarComposite calendarWidget = new CalendarComposite(composite, c);
calendarWidget.setNoneEnabled(this.allowNullDate);
calendarWidget.setMinimumDate(dateToCalendar(getMinimum()));
calendarWidget.setMaximumDate(dateToCalendar(getMaximum()));
// background to match the calendar
composite.setBackground(calendarWidget.getBackground());
calendarDropDown.show(true, composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
text.addFocusListener(new FocusListener()
{
#Override
public void focusLost(FocusEvent event)
{
dispose();
}
#Override
public void focusGained(FocusEvent event)
{
// TODO Auto-generated method stub
}
});
calendarWidget.addMainCalendarListener(new CalendarListenerAdapter()
{
#Override
public void dateChanged(Calendar date)
{
doSetDate(date != null ? date.getTime() : null, false, true);
}
#Override
public void popupClosed()
{
calendarDropDown.dispose();
}
});
}
And the show method of the DropDown is
if ((autoHide && !dropDownShell.isVisible())){
dropDownShell.addMouseListener(new MouseListener()
{
#Override
public void mouseUp(MouseEvent e)
{
// TODO Auto-generated method stub
}
#Override
public void mouseDown(MouseEvent e)
{
if (!isInside(e.x, e.y, dropDownShell.getDisplay().getBounds()))
{
dispose();
}
}
#Override
public void mouseDoubleClick(MouseEvent e)
{
// TODO Auto-generated method stub
}
});
Please let me know what I can do to make the CalendarWidget dispose on losing focus.
I think that if the widget you focus is in another shell than the currently focused widget (your Text), you may not get a focusLost event because each shell can have it's own focused widget. What is actually happens is that the shell the Text is in gets deactivated, which you can be notified about using a ShellListener.

Java JProgressBar does not show up by setVisible(true)

I have a method like below.
ProgressWindow is a sub class of JFrame containing JProgressBar.
addProgress() increments a value in the JProgressBar.
If I call this method from a method in another class, a frame of ProgressWindow will show up but not JProgressBar and some JLabels inside the frame. They show up after the last line (System.out.println("finish")).
If I call this method in a main method in the class containing this method, then every component (Bar, labels...) instantly shows up.
What can I do for showing the window correctly?
static void search(){
ProgressWindow window = new ProgressWindow();
window.setVisible(true);
ExecutorService execs = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors());
Collection<Callable<Void>> processes = new LinkedList<>();
for (int i = 0; i < 100; i++) {
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
progressWindow.addProgress(); // increment progress value
return null;
}
});
}
try {
execs.invokeAll(processes);
} catch (Exception e) {
e.printStackTrace();
} finally {
execs.shutdown();
}
System.out.println("finish");
The main problem is you seem to be calling search from the context of the Event Dispatching Thread.
The problem occurs because you are using execs.invokeAll which blocks until all the callables have finished running.
This means that the EDT is unable to process new events in Event Queue, including repaint events, this is why your UI is coming to a stand still...
There are a number of issues you are now going to face...
You should never update/modify a UI component from any thread other than the EDT
You should block the EDT for any reason
You seem to want to know when the search is complete, so you know need some kind of event notification...
The first thing we need is some way to be notified that the search has completed, this means you can no longer rely on search returning when the search is complete...
public interface SearchListener {
public void searchCompleted();
}
Next we need an intermeditate search method that builds the UI and ensure that the search is launched within it's own Thread...
static void search(final SearchListener listener) {
final ProgressWindow window = new ProgressWindow();
window.setVisible(true);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
search(listener, window);
}
});
t.start();
}
Then we need to modify the original search method to utilise the SearchListener interface to provide notification when the search is complete...
static void search(final SearchListener listener, final ProgressWindow window){
ExecutorService execs = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors());
Collection<Callable<Void>> processes = new LinkedList<>();
for (int i = 0; i < 100; i++) {
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
// This method needs to ensure that
// what ever it does to the UI, it is done from within
// the context of the EDT!!
progressWindow.addProgress();
return null;
}
});
}
try {
execs.invokeAll(processes);
} catch (Exception e) {
e.printStackTrace();
} finally {
execs.shutdown();
}
System.out.println("finish");
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
listener.searchCompleted();
}
});
}
Now, without the source code for addProgress, I might be tempted to use
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
progressWindow.addProgress();
}
});
return null;
}
});
}
Instead...
Take a look at Concurrency in Swing for more details
Sounds like you what you're wanting to do is invoke the setVisible on the Swing UI thread, you can do this with invokeAndWait or invokeLater.
So something like:
final ProgressWindow window = new ProgressWindow();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
window.setVisible(true);
}
});

Java close listener for ViewPart

I'm using eclipse RCP with a view and I want to print something on the console when the application is closed.
This is what I have done, but It's not working;
public void createPartControl(final Composite parent){
parent.getShell().addListener(SWT.CLOSE, new Listener() {
#Override
public void handleEvent(Event event) {
System.out.println("NOW !");
}
});
}
EDIT:
I found a solution, I needed to add a DisposeListener:
parent.addDisposeListener(new DisposeListener() {
#Override
public void widgetDisposed(DisposeEvent e) {
// TODO Auto-generated method stub
}
});
You want to use the SWT.Close event and not SWT.CLOSE. From the SWT Javadoc:
SWT.Close - The close event type (value is 21).
SWT.CLOSE - Style constant for close box trim (value is 1<<6, since we do not distinguish between CLOSE style and MENU style).

ProgressMonitorDialog - Watching active thread to update monitor

In my GUI I have a PDF file creation operation. The operation can take up to 10-15 seconds to complete. When I start the operation, I attach a listener to it. The listener changes the cursor and disables the GUI, until the operation completes.
I would also like to add a progressbar, so the users will have a idea when it is going to complete.
Created a method startProgressBar() and called it from the start of the operation method.
See Below:
private void startSavePdfOperation() {
startProgressBar();
saveOp = new AplotSaveOperation(appReg.getString("aplot.message.SAVETOPDF"), "PDF", session);
saveOp.addOperationListener(new MyOperationListener(this) {
startProgressBar Method - See Below:
public void startProgressBar() {
Shell shell = new Shell(getShell());
shell.setSize(260, 120);
final ProgressBar bar = new ProgressBar(shell, SWT.SMOOTH);
bar.setBounds (20, 20, 200, 20);
shell.open();
final int maximum = bar.getMaximum();
new Thread(new Runnable() {
public void run() {
for (final int[] i = new int[1]; i[0] <= maximum; i[0]++) {
try {Thread.sleep (100);} catch (Throwable th) {}
if (Display.getDefault().isDisposed()) return;
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if (bar.isDisposed ()) return;
bar.setSelection(i[0]);
}
});
}
}
}).start();
The code above created the ProgressBar. The issue is that the operation would end well before the progressbar indicator was close to ending.
Question: Is this because in the method I am creating a new thread and the indicator is updating according to the new thread and not the operation thread?
Question: Is it possible to create a new thread that watches the GUI thread and updates the progressbar accordingly?
Read a article suggesting using ProgressMonitorDialog with IRunnableWithProgress.
Method startProgressBar using ProgressMonitorDialog - see below:
public void startProgressBar() {
ProgressMonitorDialog dialog = new ProgressMonitorDialog(getShell());
try {
dialog.run(true, true, new IRunnableWithProgress(){
public void run(IProgressMonitor monitor) {
monitor.beginTask("Some nice progress message here ...", 100);
** getThread(); **
monitor.done();
}
});
}
catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void getThread() {
new Thread etc.. etc...
}
It seems that it will have the same issues with threading and updating as the code above.
Question: So now I am thinking can I just add or update the ProgressBar to my existing Listener
OperationListener Code - see below:
public abstract class MyOperationListener implements InterfaceAIFOperationListener {
AplotCreatePDFDialog w = null;
public MyOperationListener(AplotCreatePDFDialog win) {
w = win;
}
public void startOperation(String startMessage) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
w.recursiveSetEnabled(getShell(), getShell().getEnabled());
w.getShell().setEnabled(!getShell().getEnabled());
}
});
}
public void endOperation() {
try {
endOperationImpl();
}
finally {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
w.recursiveSetEnabled(getShell(), true);
w.getShell().setEnabled(!getShell().getEnabled());
w.close();
}
});
}
}
abstract protected void endOperationImpl();
} // end class MyOperationListener
Thanks for any help you can give me with this.
EDIT
Baz, your answer below is exactly what the question asked, so thank you for answering.
But I am starting to think that what I am trying to do is not possible.
When my operation starts, I wanted the progress bar indicator to start and when my operation ended I wanted the indicator be at the end and the monitor would close.
I thought there might bee a way to use my listener to add the progressbar. Something like the following.
public void startOperation(String startMessage) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
->monitor.beginTask("Creating PDF File(s)", IProgressMonitor.UNKNOWN);<-
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
w.recursiveSetEnabled(getShell(), getShell().getEnabled());
w.getShell().setEnabled(!getShell().getEnabled());
}
});
}
public void endOperation() {
try {
->monitor.worked(1);<-
endOperationImpl();
}
finally {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
w.recursiveSetEnabled(getShell(), true);
w.getShell().setEnabled(!getShell().getEnabled());
->monitor.done();<-
w.close();
}
});
}
}
abstract protected void endOperationImpl();
} // end class MyOperationListener
But I am starting to see that the ProgressBar has to have some sort of measurement to display the indicator correctly.
I would be happy if the indicator just went back and forth and the monitor would close at the end of the operation.
Why not use ProgressMonitorDialog?
Here is a related answer from me showing a simple example.
This is what it looks like:
If you are not sure about the workload, use this code:
monitor.beginTask("Copying files", IProgressMonitor.UNKNOWN);
It will show the idle bar while running.

SWT event propagation

I'm trying to detect click events on a Composite control that contains a number of other composites. I tried:
topComposite.addMouseListener(new MouseListener() {
...
#Override
public void mouseUp(MouseEvent arg0) {
logger.info("HERE");
});
});
But the event never fires. I assumed that when a mouse event occurred on a child it would propagate up the chain but that doesn't happen. How do I do this?
In SWT, the general rule is that events do not propagate. The main exception to this, is the propagation of traverse events - which is pretty complicated to describe.
The easy answer to your problem is that you must add the listener to all the children of you Composite - recursively!
E.g. like this
public void createPartControl(Composite parent) {
// Create view...
final MouseListener ma = new MouseAdapter() {
#Override
public void mouseDown(MouseEvent e) {
System.out.println("down in " + e.widget);
}
};
addMouseListener(parent, ma);
}
private void addMouseListener(Control c, MouseListener ma) {
c.addMouseListener(ma);
if (c instanceof Composite) {
for (final Control cc : ((Composite) c).getChildren()) {
addMouseListener(cc, ma);
}
}
}
The clicked-upon widget is found in e.widget as seen above. An important issue is to remember to do this again if you add more Controls later.

Categories