Java JFace databinding: Update SWT widget from background thread - java

A background thread shall update a simple text input field with some value.
I created the POJO with getter/setter in advance, called the JFACE databinding wizard to generate a shell and let it generate the code.
I'm entirely relying on the generated code, just added an inline thread that sets the value data by calling the setter.
While it is working perfectly from the UI to the data POJO, the other way round, no way.
I tried POJOs as well as beans applying PropertyChangeSupport and firePropertyChange(), no way.
Can please somebody shed a light on this or point to some web ressources ? (Sure I googled and applied search here ...)
(For simplicity I've changed some elements to 'static' in this sample as well ommitted some proper thread handling.)
Best regards
Gerd
Code:
public class Gui extends Shell {
private DataBindingContext m_bindingContext;
private static com.gsi.MyDataClass myDataClass = new com.gsi.MyDataClass();
private Text myStringText;
/**
* Launch the application.
* #param args
*/
public static void main(String args[]) {
Display display = new Display();
Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
public void run() {
try {
Display display = Display.getDefault();
Gui shell = new Gui(display, SWT.SHELL_TRIM);
shell.open();
shell.layout();
// here is the thread -----------------------------------------
new Thread () {
public void run () {
while (true) {
try { Thread.sleep(1000); } catch (InterruptedException e) { }
myDataClass.setMyString("Date1:" + new Date().toString());
}
}
} .start();
// the rest is generated code ------------------------------------------------------------
while (!shell.isDisposed()) { if (!display.readAndDispatch()) {
display.sleep(); }
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the shell.
* #param display
* #param style
*/
public Gui(Display display, int style) {
super(display, style);
createContents();
}
/**
* Create contents of the window.
*/
protected void createContents() {
setText("SWT Application");
setSize(242, 99);
setLayout(new GridLayout(2, false));
new Label(this, SWT.NONE).setText("MyString:");
myStringText = new Text(this, SWT.BORDER | SWT.SINGLE);
myStringText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
false));
if (myDataClass != null) {
m_bindingContext = initDataBindings();
}
}
#Override
protected void checkSubclass() {
// Disable the check that prevents subclassing of SWT components
}
public com.gsi.MyDataClass getMyDataClass() {
return myDataClass;
}
public void setMyDataClass(com.gsi.MyDataClass newMyDataClass) {
setMyDataClass(newMyDataClass, true);
}
public void setMyDataClass(com.gsi.MyDataClass newMyDataClass,
boolean update) {
myDataClass = newMyDataClass;
if (update) {
if (m_bindingContext != null) {
m_bindingContext.dispose();
m_bindingContext = null;
}
if (myDataClass != null) {
m_bindingContext = initDataBindings();
}
}
}
protected DataBindingContext initDataBindings() {
DataBindingContext bindingContext = new DataBindingContext();
//
IObservableValue myStringObserveWidget = SWTObservables.observeText(myStringText, SWT.Modify);
IObservableValue myStringObserveValue = PojoObservables.observeValue(myDataClass, "myString");
bindingContext.bindValue(myStringObserveWidget, myStringObserveValue, null, null);
// bindingContext.bindValue(myStringObserveWidget, myStringObserveValue,
// new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE), new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE));
//
return bindingContext;
}
}

PojoObservable is a simple wrap around POJO to use them in databindings. They have no way to check if one of their property change, so there isn't any way they can change the UI in response to change in their internal state.

Use
BeanProperties.value(myDataClass, "myString");
Instead of
PojoObservables.observeValue(myDataClass, "myString");
And your bean setter method must call fireProperyChage(....)

Related

Worldwind SurfaceImage Deep/Batch Picking

I'm using WorldWind and trying to "pick" multiple surface images in the same layer and not understanding why it isn't working.
I was under the impression that calling this:
this.getWwd().getSceneController().setDeepPickEnabled(true);
Would enable me to pick multiple renderables in the same layer. This seems to work for all other cases other than SurfaceImage. I also noticed if I force the loaded SurfaceImage into different layers it works as expected.
This is the code I'm using to test this out:
public class SurfaceImageViewer extends ApplicationTemplate
{
public static class AppFrame extends ApplicationTemplate.AppFrame
{
private JFileChooser fileChooser = new JFileChooser();
private JSlider opacitySlider;
private SurfaceImageLayer layer;
private JLabel statusLabel = new JLabel("status: ready");
public AppFrame()
{
super(true, true, false);
this.getWwd().getSceneController().setDeepPickEnabled(true);
try
{
this.layer = new SurfaceImageLayer();
this.layer.setOpacity(1);
this.layer.setPickEnabled(true);
this.layer.setName("Surface Images");
insertBeforeCompass(this.getWwd(), layer);
this.getControlPanel().add(makeControlPanel(), BorderLayout.SOUTH);
}
catch (Exception e)
{
e.printStackTrace();
}
this.getWwd().addSelectListener(new SelectListener() {
#Override
public void selected(SelectEvent event) {
PickedObjectList pol = AppFrame.this.getWwd().getObjectsAtCurrentPosition();
if(event.isLeftClick()){
System.out.println("POL SIZE "+pol.size());
}
}
});
}
Action openElevationsAction = new AbstractAction("Open Elevation File...")
{
public void actionPerformed(ActionEvent e)
{
int status = fileChooser.showOpenDialog(AppFrame.this);
if (status != JFileChooser.APPROVE_OPTION)
return;
final File imageFile = fileChooser.getSelectedFile();
if (imageFile == null)
return;
Thread t = new Thread(new Runnable()
{
public void run()
{
try
{
CompoundElevationModel cem
= (CompoundElevationModel) getWwd().getModel().getGlobe().getElevationModel();
LocalElevationModel em = new LocalElevationModel();
em.addElevations(imageFile.getPath());
cem.addElevationModel(em);
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
});
t.setPriority(Thread.MIN_PRIORITY);
t.start();
}
};
Action openImageAction = new AbstractAction("Open Image File...")
{
public void actionPerformed(ActionEvent actionEvent)
{
int status = fileChooser.showOpenDialog(AppFrame.this);
if (status != JFileChooser.APPROVE_OPTION)
return;
final File imageFile = fileChooser.getSelectedFile();
if (imageFile == null)
return;
Thread t = new Thread(new Runnable()
{
public void run()
{
try
{
statusLabel.setText("status: Loading image");
// TODO: proper threading
layer.addImage(imageFile.getAbsolutePath());
getWwd().redraw();
statusLabel.setText("status: ready");
}
catch (IOException e)
{
e.printStackTrace();
}
}
});
t.setPriority(Thread.MIN_PRIORITY);
t.start();
}
};
private JPanel makeControlPanel()
{
JPanel controlPanel = new JPanel(new GridLayout(0, 1, 5, 5));
JButton openImageButton = new JButton(openImageAction);
controlPanel.add(openImageButton);
this.opacitySlider = new JSlider();
this.opacitySlider.setMaximum(100);
this.opacitySlider.setValue((int) (layer.getOpacity() * 100));
this.opacitySlider.setEnabled(true);
this.opacitySlider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = opacitySlider.getValue();
layer.setOpacity(value / 100d);
getWwd().redraw();
}
});
JPanel opacityPanel = new JPanel(new BorderLayout(5, 5));
opacityPanel.setBorder(new EmptyBorder(0, 10, 0, 0));
opacityPanel.add(new JLabel("Opacity"), BorderLayout.WEST);
opacityPanel.add(this.opacitySlider, BorderLayout.CENTER);
controlPanel.add(opacityPanel);
JButton openElevationsButton = new JButton(openElevationsAction);
controlPanel.add(openElevationsButton);
controlPanel.add(statusLabel);
controlPanel.setBorder(new EmptyBorder(15, 15, 15, 15));
return controlPanel;
}
}
public static void main(String[] args)
{
ApplicationTemplate.start("World Wind Surface Images", SurfaceImageViewer.AppFrame.class);
}
}
These are 2 geotiffs that are layered on top of each other that I've been using to test this out. I would expect my println on the SelectListener to print out "3" when I single left click on both geotiffs. (I've uploaded the geotiffs into a zip available here)
The area where you will see these is in San Francisco, see screenshot:
Update:
It was discovered that the examples for Batch Picking were oriented around AbstractSurfaceObject instances, which did not apply in this case. For the handling of SurfaceImage instances the property for setAlwaysOnTop should be configured to false which appears to let the selection event process all elements under the cursor.
Reading through the examples for DeepPicking, there are actually 2 things that need to be done.
setDeepPickEnabled(true); //This is done.
Disable Batch picking on the desired elements
https://github.com/nasa/World-Wind-Java/blob/master/WorldWind/src/gov/nasa/worldwindx/examples/DeepPicking.java
In order to enable deep picking, any batch picking for the desired elements must be disabled and the
SceneController's deep picking property must be enabled. See {#link gov.nasa.worldwind.SceneController#setDeepPickEnabled(boolean)
Took me a little while to understand the second one, but it appears to be tied to the AbstractSurfaceObject class.
I am assuming that the things that you're drawing on the layer are a subclass of AbstractSurfaceObject
I believe that in this situation, I would subclass the SurfaceImageLayer, and override the addRenderable methods. I would check the renderable if it was an instance of an AbstractSurfaceObject, and disable batch picking on it before forwarding it to the super class.
This code may not be the best long-term solution, but it may provide quick results to determine if this is the underlying issue.
import gov.nasa.worldwind.layers.SurfaceImageLayer;
import gov.nasa.worldwind.render.AbstractSurfaceObject;
import gov.nasa.worldwind.render.Renderable;
/**
* Very Rough extension of SurfaceImageLayer which disables batch picking on all AbstractSurfaceobjects.
* #author http://stackoverflow.com/users/5407189/jeremiah
* #since Nov 26, 2016
*
*/
public class MySurfaceImageLayer extends SurfaceImageLayer {
#Override
public void addRenderable(Renderable renderable) {
if (renderable instanceof AbstractSurfaceObject) {
((AbstractSurfaceObject)renderable).setEnableBatchPicking(false);
}
super.addRenderable(renderable);
}
#Override
public void addRenderables(Iterable<? extends Renderable> renderables) {
for (Renderable r : renderables) {
addRenderable(r);
}
}
}
IF the thing you want to have picked is the image directly, that appears to not be supported out-of-the-box. You would need to do something to get the SurfaceImage references from the SurfaceImageLayer to be visible to the RenderableLayer on doPick. That may come with a new set of problems to watch out for.
As a side-note, if you're rendering Icons then all you need to do is set the IconRenderer.setAllowBatchPicking(false)
I hope that's at least somewhat helpful.
Best of Luck.

Java SWT create listener to change text of a label and return data

My problem is the following. I suppose it is a rather easy problem. However, after spending several hours searching for a solution on google, I still don't have an answer.
I have a function createGui which I give a String variable text. This function creates a GUI where the user can click on a button. Whenever he clicks the button, I want to modify the variable text. Also I want to set the label label to the value of text. Finally, I want to return the so modified variable text.
Can you tell me, how to achieve my goal?
public String createGui(String text)
{
Display display = new Display();
Shell shell = new Shell( display );
shell.setLayout( new GridLayout( 1, false ) );
Label label = new Label( shell, SWT.NONE );
label.setText( "abc" );
Button b = new Button( shell, SWT.CHECK );
b.setText( "check" );
b.addSelectionListener( new SelectionAdapter()
{
#Override
public void widgetSelected( SelectionEvent e )
{
// modify text
// change label to text
}
} );
shell.pack();
shell.open();
while( !shell.isDisposed() )
{
if( !display.readAndDispatch() )
{
display.sleep();
}
}
display.dispose();
return text;
}
You can't return a value from an anonymous inner class to the caller of the containing method.
You can however pass in a callback and call a method of this callback when you're done:
public void createGui(String text, Callback callback)
{
[...]
b.addListener(SWT.Selection, (e) -> {
String modifiedText = // Manipulate the text
label.setText(modifiedText);
callback.onChange(modifiedText);
});
[...]
}
private static interface Callback
{
void onChange(String newValue);
}
public static void main(String[] args)
{
createGui("InitialText", (s) -> {
// Do something with the string here.
});
}
This is Java8. Here's a Java 7 version:
public void createGui(String text, final Callback callback)
{
[...]
b.addListener(SWT.Selection, new Listener()
{
#Override
public void handleEvent(Event event)
{
String modifiedText = // Manipulate the text
// label.setText(modifiedText);
callback.onChange(modifiedText);
}
});
[...]
}
private interface Callback
{
void onChange(String newValue);
}
public static void main(String[] args)
{
createGui("InitialText", new Callback()
{
#Override
void onChange(String newValue)
{
// Do something with the string here.
}
});
}

Enter Key Listener for Date is not working in linux flavours

Here is my full coding.I have Two class firstone MyDateTime and Second one is Employee.
i have included currently working coding of mine.For the EmployeePart class,AbstractEditorPart is our own parent class Which is extended
public class MyDateTime extends DateTime{
public DateTime(Composite parent, int style)
{
super(parent, style);
}
public Date getValue()
{
Date date = new Date(getYear(), getMonth(), getDay());
return date;
}
}
public Class EmployeePart extends AbstractEditorPart(
private MyDateTime currentDate;
public void createBody(Composite parent){
currentDate=Util.createDateChooserCombo(parent, toolkit, "Date:", 2);
}
public void save(Employee input){
return null;
}
}
}
Turns out to be a little more complicated than I first thought.
One solution is to define a TabList for the Composite that contains your Widgets.
This way you can first define in which order you want them to be traversed.
Then add a Listener to each of the Widgets you want to traverse. This Listener will determine the next item in the TabList and force the focus on this item when either Tab or Enter is pressed.
Here is some example code:
public static void main(String[] args)
{
Display display = Display.getDefault();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
final Composite content = new Composite(shell, SWT.NONE);
content.setLayout(new FillLayout());
Text first = new Text(content, SWT.BORDER);
Text second = new Text(content, SWT.BORDER);
content.setTabList(new Control[] {first, second});
Listener enterListener = new Listener()
{
#Override
public void handleEvent(Event event)
{
/* Is it a traverse via Tab or Enter? */
if(event.keyCode == SWT.CR || event.keyCode == SWT.TRAVERSE_RETURN || event.keyCode == SWT.TRAVERSE_TAB_NEXT)
{
/* Get source of event */
Widget source = event.widget;
/* Get traverse order of content composite */
Control[] tabList = content.getTabList();
/* Try to find current position in the tab list */
for(int i = 0; i < tabList.length; i++)
{
if(source.equals(tabList[i]))
{
/* Get the next item in the tab list */
Control nextControl = tabList[(i + 1) % tabList.length];
/* And force the focus on this item */
nextControl.setFocus();
nextControl.forceFocus();
return;
}
}
}
}
};
first.addListener(SWT.KeyUp, enterListener);
second.addListener(SWT.KeyUp, enterListener);
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}

Font not taking effect during initial construction of new Composite

I wanted to have a Text widget that could display a message in it when the user has not entered a value into the field yet. I extended composite and essentially wrapped a text field in it. Added a focus listener to remove the message on focus, and to replace the message when the focus is lost if the field is empty. That all works as expected.
The issue I am having is I wanted the prompt to be styled differently when it is placed in the text field. The font does not seem to be being used initially. Once the field has had focus and loses focus it looks correct.
For example this is how it looks when it initially loads:
And this is how it should look on initial load and how it looks after having and lost focus:
It gets a little stranger, as when I run this inside a simple shell, it works how it should. When I run it as an Eclipse application is when it does not get styled correctly.
Here is the code for my composite:
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Text;
/**
* The <code>PromptingTextInput</code> component is a small enhancement to
* standard <code>Text</code>. It adds the ability to specify a prompt value
* that displays when the text is empty and the field does not have focus.
*/
public class PromptingTextInput extends Composite {
private String prompt;
private Text input;
private boolean textEmpty;
Font emptyFont;
Font inputFont;
public PromptingTextInput(String prompt, Composite parent, int style, boolean passwordField) {
super(parent, style);
this.prompt = prompt;
setLayout(new FillLayout());
this.textEmpty = true;
this.input = new Text(this, (passwordField ? SWT.PASSWORD : SWT.NONE));
setEmptyInputStyle();
this.input.setText(this.prompt);
this.input.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent e) {
PromptingTextInput.this.focusGained();
}
public void focusLost(FocusEvent e) {
PromptingTextInput.this.focusLost();
}
});
addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
disposeFonts();
}
});
}
protected void focusGained() {
if (this.textEmpty) {
this.input.setText("");
setInputStyle();
}
}
protected void focusLost() {
if (input.getText() == null || input.getText().trim().length() == 0) {
this.input.setText(this.prompt);
setEmptyInputStyle();
this.textEmpty = true;
} else {
this.textEmpty = false;
}
}
protected void setInputStyle() {
if (this.inputFont == null){
this.inputFont = new Font(Display.getCurrent(), "Verdana", 8, SWT.DEFAULT);
}
this.input.setFont(this.inputFont);
this.input.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
}
protected void setEmptyInputStyle() {
if (this.emptyFont == null){
this.emptyFont = new Font(Display.getCurrent(), "Verdana", 6, SWT.ITALIC);
}
this.input.setFont(this.emptyFont);
this.input.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
}
public String getPrompt() {
return prompt;
}
public void setPrompt(String prompt) {
this.prompt = prompt;
if(!this.input.isFocusControl()){
this.input.setText(this.prompt);
setEmptyInputStyle();
}
}
public Text getInput() {
return input;
}
public boolean isTextEmpty() {
return textEmpty;
}
public String getText() {
return this.input.getText();
}
public void addModifyListener (ModifyListener listener) {
this.input.addModifyListener(listener);
}
public void disposeFonts(){
if (this.inputFont != null){
this.inputFont.dispose();
}
if (this.emptyFont != null){
this.emptyFont.dispose();
}
}
}
UPDATE: As Baz has shown this is not an issue in Indigo and only seems to be an issue with an E4 app in Juno.
Building upon sambi's answer, I got the following working. Maybe this works in Juno:
private static Font italic;
public static void main(String[] args) {
final Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1,false));
italic = new Font(Display.getCurrent(), "Verdana", 6, SWT.ITALIC);
final Text text = new Text(shell, SWT.BORDER);
text.addListener(SWT.Paint, new Listener() {
#Override
public void handleEvent(Event event) {
if(text.getText().length() < 1 && !text.isFocusControl())
{
GC gc = event.gc;
gc.setFont(italic);
gc.setForeground(display.getSystemColor(SWT.COLOR_GRAY));
Point size = text.computeSize(SWT.DEFAULT, SWT.DEFAULT);
/* Strangely the y positioning doesn't work correctly */
//gc.drawText("Please enter text", 1, (size.y / 2) - (italic.getFontData()[0].getHeight() / 2));
gc.drawText("Please enter text", 1, 4);
}
}
});
text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
Button button = new Button(shell, SWT.PUSH);
button.setText("Dummy");
button.forceFocus();
shell.setSize(200, 100);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
italic.dispose();
display.dispose();
}
Without focus and empty text:
With focus or text:
You could use Text.setMessage (String message). The problem with this is you will not be able to customize much with font size and fore ground...etc.
To customize it, you can actually draw message with in the bounds of Text.

Eclipse RCP application - custom splash screen

I'm currently developing an Eclipse RCP application, in which I'm trying to implement a custom splash screen handler, sporting a progress bar (behavior similar to the default progress bar you can define in the .product definition) and multiple cycling background images.
After editing the extensions of the main application plugin this way:
[...]
<!-- install custom splash handler -->
<extension point="org.eclipse.ui.splashHandlers">
<splashHandler
class="com.example.application.splash.SlideShowSplashHandler"
id="splash.slideshow">
</splashHandler>
<splashHandlerProductBinding
productId="com.example.application.product"
splashId="com.example.application.splash.slideshow">
</splashHandlerProductBinding>
</extension>
<!-- define images (in plugin root directory) to be shown -->
<extension point="com.example.application.splashExtension">
<splashExtension id="01" image="01_Splash2Ag.bmp"></splashExtension>
<splashExtension id="02" image="02_Splash3Ag.bmp"></splashExtension>
<splashExtension id="00" image="00_Splash1Ag.bmp"></splashExtension>
</extension>
[...]
I'm trying to implement the custom splashscreen handler class:
public class SlideShowSplashHandler extends AbstractSplashHandler {
private List<Image> fImageList;
private ProgressBar fBar;
private final static String F_SPLASH_EXTENSION_ID = "com.example.application.splashExtension"; //NON-NLS-1
private final static String F_ELEMENT_IMAGE = "image"; //NON-NLS-1
private int imageIdx = 0;
public SlideShowSplashHandler() {
fImageList = new ArrayList<Image>(5);
}
/* (non-Javadoc)
* #see org.eclipse.ui.splash.AbstractSplashHandler#init(org.eclipse.swt.widgets.Shell)
*/
public void init(Shell splash) {
// Store the shell
super.init(splash);
// Force shell to inherit the splash background
getSplash().setBackgroundMode(SWT.INHERIT_DEFAULT);
// Load all splash extensions
loadSplashExtensions();
// If no splash extensions were loaded abort the splash handler
if (hasSplashExtensions() == false) return;
// Create UI
createUI(splash);
}
private boolean hasSplashExtensions() {
if (fImageList.isEmpty()) {
return false;
} else {
return true;
}
}
#Override
public IProgressMonitor getBundleProgressMonitor() {
return new NullProgressMonitor() {
#Override
public void beginTask(String name, final int totalWork) {
getSplash().getDisplay().syncExec(new Runnable() {
public void run() {
fBar.setSelection(50);
}
});
}
#Override
public void subTask(String name) {
getSplash().getDisplay().syncExec(new Runnable() {
public void run() {
if (fBar.getSelection() < 100) fBar.setSelection(fBar.getSelection() + 10);
if (imageIdx >= fImageList.size()) imageIdx = 0;
Image image = fImageList.get(imageIdx++);
getSplash().setBackgroundImage(image);
getSplash().setRedraw(true);
getSplash().redraw();
}
});
}
};
}
private void createUI(Shell shell) {
Composite container = new Composite(shell, SWT.NONE);
container.setLayout(new GridLayout(1, false));
container.setLocation(5, 374);
container.setSize(480, 15);
/* Progress Bar */
fBar = new ProgressBar(container, SWT.HORIZONTAL);
fBar.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
((GridData) fBar.getLayoutData()).heightHint = 13;
fBar.setMaximum(100);
fBar.setSelection(25);
/* Version Label */
Label versionLabel = new Label(container, SWT.NONE);
versionLabel.setLayoutData(new GridData(SWT.END, SWT.BEGINNING, true, false));
//versionLabel.setFont(fVersionFont);
//versionLabel.setForeground(fVersionColor);
//versionLabel.setText(NLS.bind(Messages.SplashHandler_BUILD, "2.1 Nightly")); //$NON-NLS-1$
/* Layout All */
shell.layout(true, true);
}
private void loadSplashExtensions() {
// Get all splash handler extensions
IExtension[] extensions = Platform.getExtensionRegistry()
.getExtensionPoint(F_SPLASH_EXTENSION_ID).getExtensions();
// Process all splash handler extensions
for (int i = 0; i < extensions.length; i++) {
processSplashExtension(extensions[i]);
}
}
/**
* Parse the extension points with the images filename.
*/
private void processSplashExtension(IExtension extension) {
// Get all splash handler configuration elements
IConfigurationElement[] elements = extension.getConfigurationElements();
// Process all splash handler configuration elements
for (int j = 0; j < elements.length; j++) {
processSplashElements(elements[j]);
}
}
/**
* Create the images defined as extension points
*/
private void processSplashElements(IConfigurationElement configurationElement) {
String name = configurationElement.getAttribute(F_ELEMENT_IMAGE);
ImageDescriptor descriptor = Activator.getImageDescriptor("/"+name);
if (descriptor != null) {
Image image = descriptor.createImage();
if (image !=null) {
fImageList.add(image);
}
}
}
public void dispose() {
super.dispose();
// Check to see if any images were defined
if ((fImageList == null) ||
fImageList.isEmpty()) {
return;
}
// Dispose of all the images
Iterator<Image> iterator = fImageList.iterator();
while (iterator.hasNext()) {
Image image = iterator.next();
image.dispose();
}
}
}
Problem is that the progress bar just works, while the images are not shown. While debugging I could verify that the images are actually found and loaded, and correctly set in the shell; the shell just seems to not being redrawn. Am i missing something?=
I could solve the problem on linux and windows, but it did not work on macos/cocoa (in which the splash screen is looking "scrambled" on each image slideshow iteration).
Is was very simple indeed, just attaching an extra Composite between the splash shell and the container containing the widgets; then change the background image on the newly create container object.
private void createUI(Shell shell) {
Composite bgcontainer = new Composite(shell, SWT.NONE); // new
[...]
Composite container = new Composite(bgcontainer, SWT.NONE);
[...]
fBar = new ProgressBar(container, SWT.HORIZONTAL);
[...]
Label versionLabel = new Label(container, SWT.NONE);
versionLabel.setLayoutData(new GridData(SWT.END, SWT.BEGINNING, true, false));
shell.layout(true, true);
}
#Override public IProgressMonitor getBundleProgressMonitor() {
return new NullProgressMonitor() {
#Override public void beginTask(String name, final int totalWork) {
getSplash().getDisplay().syncExec(new Runnable() {
public void run() {
if (fBar != null) fBar.setSelection(40);
Image image = fImageList.get(imageIdx++);
bgcontainer.setBackgroundImage(image);
bgcontainer.setRedraw(true);
bgcontainer.update();
}
});
}
#Override public void subTask(String name) {
final String n = name;
getSplash().getDisplay().syncExec(new Runnable() {
String taskname = n;
public void run() {
if (fBar != null && fBar.getSelection() < 100)
fBar.setSelection(fBar.getSelection() + 10);
if (fBar.getSelection() == 60 || fBar.getSelection() == 80) {
if (imageIdx >= fImageList.size()) imageIdx = 0;
Image image = fImageList.get(imageIdx++);
bgcontainer.setBackgroundImage(image);
bgcontainer.setRedraw(true);
bgcontainer.update();
}
}
});
}
};
}
I haven't tried your code, but when you make changes to a Control, it is not enough to call Control.redraw(), but you must also call Control.update().
Control.redraw() requests that a control should be redrawn, Control.update() actually redraws it. The later is needed when your code runs on the UI thread!

Categories

Resources