Eclipse RCP application - custom splash screen - java

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!

Related

Barcode Google Vision API check if detected barcode is inside area

I have problem with detecting if barcode is inside specified area. For testing purposes camera source preview and surface view has same size 1440x1080 to prevent scaling between camera and view. I get positive checks even if I see QR Code isn't in box what represents image. Whats wrong?
False positive check
ScannerActivity
public class ScannerActivity extends AppCompatActivity {
private static final String TAG = "ScannerActivity";
private SurfaceView mSurfaceView; // Its size is forced to 1440x1080 in XML
private CameraSource mCameraSource;
private ScannerOverlay mScannerOverlay; // Its size is forced to 1440x1080 in XML
#Override
protected void onCreate(Bundle savedInstanceState) {
// .. create and init views
// ...
BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.ALL_FORMATS)
.build();
mCameraSource = new CameraSource.Builder(this, barcodeDetector)
.setRequestedPreviewSize(1440, 1080)
.setRequestedFps(20.0f)
.setFacing(CameraSource.CAMERA_FACING_BACK)
.setAutoFocusEnabled(true)
.build();
barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {
}
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
parseDetections(detections.getDetectedItems());
}
});
}
private void parseDetections(SparseArray<Barcode> barcodes) {
for (int i = 0; i < barcodes.size(); i++) {
Barcode barcode = barcodes.valueAt(i);
if (isInsideBox(barcode)) {
runOnUiThread(() -> {
Toast.makeText(this, "GOT DETECTION: " + barcode.displayValue, Toast.LENGTH_SHORT).show();
});
}
}
}
private boolean isInsideBox(Barcode barcode) {
Rect barcodeBoundingBox = barcode.getBoundingBox();
Rect scanBoundingBox = mScannerOverlay.getBox();
boolean checkResult = barcodeBoundingBox.left >= scanBoundingBox.left &&
barcodeBoundingBox.right <= scanBoundingBox.right &&
barcodeBoundingBox.top >= scanBoundingBox.top &&
barcodeBoundingBox.bottom <= scanBoundingBox.bottom;
Log.d(TAG, "isInsideBox: "+(checkResult ? "YES" : "NO"));
return checkResult;
}
}
Explanation to your issue is simple, but the solution is not trivial to explain.
The coordinates of the box from your UI will mostly not the be the same like the imaginary box on each preview frame. You must transform the coordinates from the UI box to scanBoundingBox.
I open sourced an example which implement the same usecase you are trying to accomplish. In this example I took another approach, I cut the box out of each frame first before feeding it to Google Vision, which is also more efficient, since Google Vision don't have to analyse the whole picture and waste tons of CPU...
I decied to cropp frame by wrapping barcode detector however I don't know why but cropped frame is rotated by 90 degress even smarphone is upright orientation.
Box Detector class
public class BoxDetector extends Detector<Barcode> {
private Detector<Barcode> mDelegate;
private int mBoxWidth;
private int mBoxHeight;
// Debugging
private CroppedFrameListener mCroppedFrameListener;
public BoxDetector(Detector<Barcode> delegate, int boxWidth, int boxHeight) {
mDelegate = delegate;
mBoxWidth = boxWidth;
mBoxHeight = boxHeight;
}
public void setCroppedFrameListener(CroppedFrameListener croppedFrameListener) {
mCroppedFrameListener = croppedFrameListener;
}
#Override
public SparseArray<Barcode> detect(Frame frame) {
int frameWidth = frame.getMetadata().getWidth();
int frameHeight = frame.getMetadata().getHeight();
// I assume that box is centered.
int left = (frameWidth / 2) - (mBoxWidth / 2);
int top = (frameHeight / 2) - (mBoxHeight / 2);
int right = (frameWidth / 2) + (mBoxWidth / 2);
int bottom = (frameHeight / 2) + (mBoxHeight / 2);
YuvImage yuvImage = new YuvImage(frame.getGrayscaleImageData().array(), ImageFormat.NV21, frameWidth, frameHeight, null);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(left, top, right, bottom), 100, outputStream);
byte[] jpegArray = outputStream.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.length);
Frame croppedFrame = new Frame.Builder()
.setBitmap(bitmap)
.setRotation(frame.getMetadata().getRotation())
.build();
if(mCroppedFrameListener != null) {
mCroppedFrameListener.onNewCroppedFrame(croppedFrame.getBitmap(), croppedFrame.getMetadata().getRotation());
}
return mDelegate.detect(croppedFrame);
}
public interface CroppedFrameListener {
void onNewCroppedFrame(Bitmap bitmap, int rotation);
}
}
Box Detector usuage
BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.ALL_FORMATS)
.build();
BoxDetector boxDetector = new BoxDetector(
barcodeDetector,
mBoxSize.getWidth(),
mBoxSize.getHeight());
boxDetector.setCroppedFrameListener(new BoxDetector.CroppedFrameListener() {
#Override
public void onNewCroppedFrame(final Bitmap bitmap, int rotation) {
Log.d(TAG, "onNewCroppedFrame: new bitmap, rotation: "+rotation);
runOnUiThread(new Runnable() {
#Override
public void run() {
mPreview.setImageBitmap(bitmap);
}
});
}
});
Cropped frame is rotated

How to tell a FieldEditorPreferencePage to invalidate/redraw programatically?

I defined a custom FieldEditorPreferencePage. In createFieldEditors method I construct a simple interface with a custom FieldEditor that holds button that loads a file. When a user loads the file the interface region (where the button stands) need to change and show other specific gui. How to invalidate the FieldEditorPreferencePage? I used the layout() method of the parent composite but nothing happens. What am I doing wrong here?
public class MyPage extends FieldEditorPreferencePage {
...
private Composite fieldEditorParent;
private boolean fileLoaded = false;
#Override
protected void createFieldEditors() {
fieldEditorParent = this.getFieldEditorParent();
MyFieldEditor compositeFieldEditor = new MyFieldEditor(fieldEditorParent) {
if(fileLoaded) {
//draw file content
} else {
Button chooseButton = new Button(buttonsComposite, SWT.NONE);
chooseButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
//choose file
fileLoaded = true;
//invalidate page <-- THIS DOES NOT WORK!
fieldEditorParent.layout(true, true);
}
}
}
}
}

Java SWT - listen if new children are added to the Composite?

I have a Composite.
In SWT the children are added, by children, no by parents:
Composite parent = new Composite(shell, SWT.none);
Composite child = new Composite(parent, SWT.none);
That means, that inside of the parent I do not know, in which way and when the children are added to their parents.
QUESTION:
Inside of the parent I need to know, when new children are added to the parent.
Is there any way to register an onChildAddListener or any add() method to override?
The only way to add custom MyComposite and create custom ChildEvent as well as ChildEventListener interface. MyComposite is capable of registering listeners of ChildEvent and fire this event when a child Composite is created.
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.TypedEvent;
import org.eclipse.swt.internal.SWTEventListener;
import org.eclipse.swt.widgets.*;
/*
* This example demonstrates the minimum amount of code required
* to open an SWT Shell and process the events.
*/
public class HelloWorld1 {
public static void main (String [] args) {
Display display = new Display ();
Shell shell = new HelloWorld1 ().open (display);
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
}
public Shell open (Display display) {
Shell shell = new Shell (display);
MyComposite parent = new MyComposite(shell, SWT.NONE);
parent.addChildEventListener(new ChildEventListener() {
#Override
public void add(ChildEvent e) {
System.out.println("Child added.");
}
});
MyComposite child = new MyComposite(parent, SWT.NONE);
// shell.open ();
return shell;
}
}
class MyComposite extends Composite {
ChildEventListener[] childEventListeners = new ChildEventListener[0];
public MyComposite(Composite parent, int style) {
super(parent, style);
if (parent instanceof MyComposite){
((MyComposite)parent).fireChildEvent(new ChildEvent(this));
}
}
public void addChildEventListener (ChildEventListener listener) {
checkWidget();
if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
ChildEventListener[] newChildEventListeners = new ChildEventListener[childEventListeners.length + 1];
System.arraycopy(childEventListeners, 0, newChildEventListeners, 0, childEventListeners.length);
childEventListeners = newChildEventListeners;
childEventListeners[childEventListeners.length - 1] = listener;
}
public void removeChildEventListener (ChildEventListener listener) {
if (childEventListeners.length == 0) return;
int index = -1;
for (int i = 0; i < childEventListeners.length; i++) {
if (listener == childEventListeners[i]){
index = i;
break;
}
}
if (index == -1) return;
if (childEventListeners.length == 1) {
childEventListeners = new ChildEventListener[0];
return;
}
ChildEventListener[] newChildEventListeners = new ChildEventListener[childEventListeners.length - 1];
System.arraycopy (childEventListeners, 0, newChildEventListeners, 0, index);
System.arraycopy (childEventListeners, index + 1, newChildEventListeners, index, childEventListeners.length - index - 1);
childEventListeners = newChildEventListeners;
}
public void fireChildEvent(ChildEvent event){
for (int i = 0; i < childEventListeners.length; i++) {
childEventListeners[i].add (event);
}
}
}
interface ChildEventListener extends SWTEventListener {
public void add(ChildEvent e);
}
class ChildEvent extends TypedEvent {
public ChildEvent(Widget widget) {
super(widget);
// TODO Auto-generated constructor stub
}
}
The purpose for which I wanted to know about child addition - is for layoing out the children
(adding LayoutData e.g. GridData) when the child is added to a child, which is layed out with a particular Layout (e.g. GridLayout).
Since it is not possible to layout children on addition - check their layout on every widget resize:
/*
* To make the forms fill the group - laying out the children is necessary.
* Unfortunately it is not possible to listen for children addition, in order to layout the children addition automatically.
* This means that the user will have to remember to layout the children, which is a nogo.
*
* Solution:
* istead of adding right layout on child addition - check if there are new children every time the widget is resized.
* if a widget without layoutData is found (new child not layed out) - add a layout
*/
this.addControlListener(new ControlAdapter() {
#Override
public void controlResized(ControlEvent e) {
layoutChildren();
}
});
}
private void layoutChildren(){
for(Control child:getChildren()){
if(child.getLayoutData() == null){
child.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
}
}
}
public void addToGroup(Composite child){
child.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
}

Java JFace databinding: Update SWT widget from background thread

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(....)

Eclipse RCP Dialog: Large Text box won't scroll - instead creates a huge dialog window!

I've been banging away at this for a while now and I can't seem to get anywhere. I've tried all of the examples I can find online and nothing seems to work! I haven't been able to find much on this problem which leads me to think I'm missing something basic. . .
In my Eclipse RCP program I want to display a dialog that will show a list of errors that occurred while loading a data file. I have overridden TitleAreaDialog and simply want to display a scrollable Text containing the list of errors and an OK button.
The problem is that the Text vertical scroll bars don't become active - the Text just grows taller to fit the text. This makes the dialog window height increases until it either fits the Text box or until it reaches the height of the screen - and then it just cuts off the bottom of the Text box.
How do I prevent the Dialog/Text box from growing too large? What am I missing?
Thanks for your help!!
-Christine
...
Here is a simple program showing my Dialog:
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.swt.*;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
public class ScrollableDialogRunner {
public static void main(String[] args) {
System.out.println("starting");
Display display = new Display ();
Shell shell = new Shell (display);
String errors = "one\ntwo\nthree\nfour\nfive\n";
for(int i = 0; i < 5; i++){
errors += errors;
}
ScrollableDialog dialog = new ScrollableDialog(shell, "Errors occurred during load", "The following errors occurred while loaded file 'x.data'", errors);
dialog.open();
}
}
class ScrollableDialog extends TitleAreaDialog {
private String title;
private String text;
private String scrollableText;
public ScrollableDialog(Shell parentShell, String title, String text, String scrollableText) {
super(parentShell);
this.title = title;
this.text = text;
this.scrollableText = scrollableText;
}
#Override
protected Control createDialogArea(Composite parent) {
GridLayout layout = new GridLayout();
layout.numColumns = 1;
parent.setLayout(layout);
GridData gridData = new GridData();
gridData.grabExcessHorizontalSpace = true;
gridData.horizontalAlignment = GridData.FILL;
Text scrollable = new Text(parent, SWT.BORDER | SWT.V_SCROLL);
scrollable.setLayoutData(gridData);
scrollable.setText(scrollableText);
return parent;
}
#Override
public void create() {
super.create();
setTitle(title);
setMessage(text, IMessageProvider.ERROR);
}
#Override
protected void createButtonsForButtonBar(Composite parent) {
Button okButton = createButton(parent, OK, "OK", true);
okButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
close();
}
});
}
#Override
protected boolean isResizable() {
return false;
}
}
Assign a size to the dialog; otherwise, the dialog will layout the children asking them for their "preferred" size (which is infinite for the text widget) and will resize itself accordingly.
[EDIT] This version works. See my comments for details.
class ScrollableDialog extends TitleAreaDialog {
private String title;
private String text;
private String scrollableText;
public ScrollableDialog(Shell parentShell, String title, String text, String scrollableText) {
super(parentShell);
this.title = title;
this.text = text;
this.scrollableText = scrollableText;
}
#Override
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea (parent); // Let the dialog create the parent composite
GridData gridData = new GridData();
gridData.grabExcessHorizontalSpace = true;
gridData.horizontalAlignment = GridData.FILL;
gridData.grabExcessVerticalSpace = true; // Layout vertically, too!
gridData.verticalAlignment = GridData.FILL;
Text scrollable = new Text(composite, SWT.BORDER | SWT.V_SCROLL);
scrollable.setLayoutData(gridData);
scrollable.setText(scrollableText);
return composite;
}
#Override
public void create() {
super.create();
// This is not necessary; the dialog will become bigger as the text grows but at the same time,
// the user will be able to see all (or at least more) of the error message at once
//getShell ().setSize (300, 300);
setTitle(title);
setMessage(text, IMessageProvider.ERROR);
}
#Override
protected void createButtonsForButtonBar(Composite parent) {
Button okButton = createButton(parent, OK, "OK", true);
okButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
close();
}
});
}
#Override
protected boolean isResizable() {
return true; // Allow the user to change the dialog size!
}
}

Categories

Resources