Using wizard and ScrolledForm(jface and forms api) - java

I'm new to eclipse plugin - SWT development. I'm trying to create wizard page having number of text fields and combo boxes. For better look n feel I'm trying to use FormToolkit for creating components and add them in ScrolledForm. But with this nothing is rendered on wizard page at runtime and there is no error also.
Questions:
Is it possible to have scrolled container inside wizard page?
Can we mix JFace and forms api?
(removed unwanted code)
Here is wizard page code:
public class ContactWizardPage extends WizardPage {
private static int counter;
private Form form;
public ContactWizardPage() {
super("New Contact Wizard" + ++counter, "New Contact Wizard" + counter, null);
setMessage("Please enter contact info." + counter);
}
public void createControl(final Composite parent) {
createControlWithoutToolkit(parent);
// commenting out toolkit code
// createControlWithToolkit(parent);
}
public void createControlWithoutToolkit(final Composite parent) {
Composite composite = new Composite(parent, SWT.DEFAULT);
composite.setLayout(new GridLayout(2, true));
Label lblFirstName = new Label(composite, SWT.FLAT);
lblFirstName.setText("First Name");
Label lblLastName = new Label(composite, SWT.FLAT);
lblLastName.setText("Last Name");
Text txtFirstName = new Text(composite, SWT.FLAT);
Text txtLastName = new Text(composite, SWT.FLAT);
Label lblEmail = new Label(composite, SWT.FLAT);
lblEmail.setText("Email");
GridDataFactory.swtDefaults().span(2, 1).align(
SWT.FILL,
SWT.BEGINNING).applyTo(lblEmail);
Text txtEmail = new Text(composite, SWT.FLAT);
GridDataFactory.swtDefaults().span(2, 1).align(
SWT.FILL,
SWT.BEGINNING).applyTo(txtEmail);
setControl(composite);
}
public void createControlWithToolkit(final Composite parent) {
FormToolkit toolkit = new FormToolkit(Display.getCurrent());
ScrolledForm form = toolkit.createScrolledForm(parent);
Composite composite = form.getBody();
composite.setLayout(new GridLayout(2, true));
Label lblFirstName = toolkit.createLabel(composite, "First Name");
Label lblLastName = toolkit.createLabel(composite, "Last Name");
Text txtFirstName = toolkit.createText(composite, "");
Text txtLastName = toolkit.createText(composite, "");
Label lblEmail = toolkit.createLabel(composite, "Email");
GridDataFactory.swtDefaults().span(2, 1).align(
SWT.FILL,
SWT.BEGINNING).applyTo(lblEmail);
Text txtEmail = toolkit.createText(composite, "");
GridDataFactory.swtDefaults().span(2, 1).align(
SWT.FILL,
SWT.BEGINNING).applyTo(txtEmail);
setControl(composite);
}
}
Here is Wizard code:
public class SampleNewWizard extends Wizard implements INewWizard {
public SampleNewWizard() {
super();
setNeedsProgressMonitor(true);
}
#Override
public IWizardPage getNextPage(IWizardPage page) {
return super.getNextPage(page);
}
public void addPages() {
addPage(new ContactWizardPage());
addPage(new ContactWizardPage());
addPage(new ContactWizardPage());
addPage(new ContactWizardPage());
}
public boolean performFinish() {
return true;
}
public void init(IWorkbench workbench, IStructuredSelection selection) {
}
}
With this code first page of wizard shows fine but second page is never rendered properly. :(
here are screenshots:
first page:
second page:

The line
parent.getShell().setSize(240, 320);
is upsetting something (and is not something you should do in a wizard page as the Wizard class deals with sizing). Testing here it works fine without it (and I get your problem with it).

Make sure that you do not dispose the FormToolKit as long as the wizard is open. Paint events need the toolkit after createControl() has finished.
My solution is to create and dispose the FormToolKit in the wizard:
#Override
public void createPageControls(Composite pageContainer) {
toolkit = new FormToolkit(pageContainer.getDisplay());
super.createPageControls(pageContainer);
}
#Override
public void dispose() {
super.dispose();
if (toolkit != null) {
try { toolkit.dispose(); } catch (Exception e) {}
}
}
public FormToolkit getToolkit() {
return toolkit;
}
In the wizard pages you can than use ((FormWizard) getWizard).getToolkit() to get a reference to the wizard's form toolkit.
#Override
public void createControl(Composite parent) {
FormToolkit toolkit = ((FormWizard) getWizard()).getToolkit();
...
Hope this helps ...

Related

get apply button in preference page + swt eclipse

I have MyPreferencePage which extends PreferencePage. Inside the PreferencePage there is a method getApplyButton() I am overriding that method to get the apply button.
I need the apply button because there are some validators that I put on the data in the preference dialog and till the all the data is not correct I dont want the apply button to be enabled.
My code
public class DefaultColorsPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
#Override
protected Control createContents(Composite parent) {
this.container = new Composite(parent, SWT.NONE);
this.container.setLayout(new GridLayout(1, false));
GridData gd_area = new GridData(SWT.FILL, SWT.FILL, true, true);
this.container.setLayoutData(gd_area);
this.defalutColoringGroup = new Group(container, SWT.NONE);
this.defalutColoringGroup.setLayout(new GridLayout(1, false));
this.defalutColoringGroup.setLayoutData(gd_area);
this.defalutColoringGroup.setText(Constants.DESCRIPTION_TEXT);
this.defaultColoringCheckBox = new Button(defalutColoringGroup, SWT.CHECK);
this.defaultColoringCheckBox.setText(Constants.DEFAULT_COLORING_BUTTON_TEXT);
errorLabel = new Label(defalutColoringGroup, SWT.NONE);
errorLabel.setText("Expression is not valid, enter a valid expression and try again!");
errorLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
errorLabel.setVisible(false);
this.viewer = tableviewerComposite.createTableViewer(defalutColoringGroup);
this.viewer.setContentProvider(new ArrayContentProvider());
try {
contentProvider = new ContentProvider();
this.viewer.setInput(contentProvider.getScenarios());
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
return container;
}
#Override
protected Button getApplyButton() {
super.getApplyButton();
}
}
//Method to create columns of the table
private void createTableColumns(final TableViewer viewer,final Composite defalutColoringGroup) {
TableViewerColumn scenariosColumn = createTableViewerColumn(viewer,Constants.SCENARIOS_COLUMN_NAME,Constants.SCENARIOS_COLUMN_NUMBER);
ScenariosLabelProvider scenariosLabelProvider = new ScenariosLabelProvider();
scenariosColumn.setLabelProvider(scenariosLabelProvider);
scenariosColumn.setEditingSupport(new ScenariosEditingSupport(viewer));
//more columns
}
//Editing Support for column
public class ScenariosEditingSupport extends EditingSupport {
private final TableViewer viewer;
private final CellEditor editor;
private final DefaultColorsPreferencePage preferencePage;
public ScenariosEditingSupport(TableViewer viewer) {
super(viewer);
this.viewer = viewer;
this.editor = new TextCellEditor(viewer.getTable());
this.preferencePage = new DefaultColorsPreferencePage();
}
#Override
protected CellEditor getCellEditor(Object element) {
return editor;
}
#Override
protected boolean canEdit(Object element) {
return true;
}
#Override
protected Object getValue(Object element) {
return ((Content) element).getExpression();
}
#Override
protected void setValue(Object element, Object changedExpression) {
String expression = String.valueOf(changedExpression);
if(Repository.isExpressionValid(expression)){
((Content) element).setExpression(expression);
viewer.update(element, null);
}
else{
preferencePage.setValid(false);
preferencePage.setErrorMessage("Expression is not valid, enter a valid expression and try again!");
((Content) element).setExpression(expression);
viewer.update(element, null);
}
}
}
You don't access the Apply button to enable / disable the preference page. Instead call the
setValid(false);
method of PreferencePage to disable Apply and OK.
Call setValid(true) when the page is OK.
You might also want to call the setErrorMessage or setMessage methods to set a message while the page is invalid.

How to validate a Text with Jface Dialog?

i created a Dialog with two input fields with the following Code.
public class CCIDDialog extends TitleAreaDialog {
private Text ccidText;
private Text descriptionText;
private String CCID;
private String description;
public CCIDDialog(Shell parentShell) {
super(parentShell);
}
public void create() {
super.create();
setTitle(_title);
setMessage("Bitte geben Sie die CCID "+firstchar+"xxxxxxx und eine Beschreibung ein (max. 7-stellig): ", IMessageProvider.INFORMATION); }
#Override
protected Control createDialogArea(Composite parent) {
Composite area = (Composite) super.createDialogArea(parent);
Composite container = new Composite(area, SWT.NONE);
container.setLayoutData(new GridData(GridData.FILL_BOTH));
GridLayout layout = new GridLayout(2, false);
container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
container.setLayout(layout);
createCCID(container);
createDescription(container);
return area;
}
private void createCCID(Composite container) {
Label lbtFirstName = new Label(container, SWT.NONE);
lbtFirstName.setText("CCID (ohne "+firstchar+"): ");
GridData dataCCID = new GridData();
dataCCID.grabExcessHorizontalSpace = true;
dataCCID.horizontalAlignment = GridData.FILL;
ccidText = new Text(container, SWT.BORDER);
ccidText.setLayoutData(dataCCID);
}
private void createDescription(Composite container) {
Label lbtLastName = new Label(container, SWT.NONE);
lbtLastName.setText("Beschreibung: ");
GridData dataDescription = new GridData();
dataDescription.grabExcessHorizontalSpace = true;
dataDescription.horizontalAlignment = GridData.FILL;
descriptionText = new Text(container, SWT.BORDER);
descriptionText.setLayoutData(dataDescription);
}
#Override
protected boolean isResizable() {
return true;
}
// save content of the Text fields because they get disposed
// as soon as the Dialog closes
private void saveInput() {
CCID = ccidText.getText();
description = descriptionText.getText();
}
#Override
protected void okPressed() {
saveInput();
super.okPressed();
}
public String getCCID() {
return CCID;
}
public String getDescription() {
return description;
}
}
Is there a way to validate the ccidtext?
If the user type more then 7 chars, he must get a notification and should not be able to continue the dialog. I read so lot at the internet but can`t find a solution for this problem.
Thank u so much for your help.
JonasInt
You can use Text.addModifyListener to add a ModifyListener which will be called each time the text is changed. You can also use Text.addVerifyListener to add VerifyListener which can actually prevent text being entered.
For TitleAreaDialog you can call setMessage or setErrorMessage to display a message in the title area.
You can disable the OK button on the dialog using:
getButton(IDialogConstants.OK_ID).setEnabled(false);
Note: getButton(xxx) can return null if you call it too early in the dialog construction. Buttons are created during the createContents method after the createDialogArea method has been called.
So you can access the buttons by overriding createContents like this:
#Override
protected Control createContents(final Composite parent)
{
Control control = super.createContents(parent);
// TODO access buttons here
return control;
}

Create a Composite that adapt to my data in Eclipse SWT

My First try is:
public MultiLangugeText(Composite parent, int style) {
super(parent, style);
setLayout(new RowLayout(SWT.HORIZONTAL));
Map<Locale, String> texts = new HashMap<Locale, String>();
texts.put(Locale.GERMAN, "Hey du");
texts.put(Locale.ENGLISH, "Hey you");
texts.put(Locale.FRENCH, "Bon Jour");
setTexts(texts);
public void setTexts(Map<Locale, String> texts) {
for (Locale locale : texts.keySet()) {
createTextComposite(locale, texts.get(locale));
}
}
private void createTextComposite(Locale locle, String localizedString) {
Composite composite = formToolkit.createComposite(this, SWT.BORDER);
formToolkit.paintBordersFor(composite);
composite.setLayout(new RowLayout(SWT.HORIZONTAL));
CLabel label = new CLabel(composite, SWT.NONE);
label.setText(locle.toString());
formToolkit.adapt(label);
formToolkit.paintBordersFor(label);
Text txtString = new Text(composite, SWT.BORDER);
txtString.setText(localizedString);
formToolkit.adapt(txtString, true, true);
}
But this code will not draw anything on my UI. At least when I try to render it in the Deisigner and in the Preview. I have to tests if this works, when I use it in my application. But I don't get where error is.
Okay it only fails in the designer, not when you actually use the composite elsewehre.

How to update/refresh a view in an eclipse plug-in?

I have an eclipse plug-in with a single view (like the eclipse helloworld-view-plugin-project). In the view-file I get an event when I want to update the view.
In this view I have a GridData in a Group with multiple labels. I have several services which register to the programe and whose status should be shown in this GridData.
Edit: In order to better show my problem I updated this post and added the whole code:
CreatePartControl():
public void createPartControl(Composite _parent) {
parent = _parent;
createContents();
addBindings();
makeActions();
contributeToActionBars();
}
CreateContents():
protected void createContents() {
// fixed
checkIcon = //...
errorIcon = //...
smallFont = SWTResourceManager.getFont("Segoe UI", 7, SWT.NORMAL);
// content
gl_shell = new GridLayout(1, false);
//margins, etc. for gl_shell
parent.setLayout(gl_shell);
final Label lblGreeting = new Label(parent, SWT.NONE);
lblGreeting.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
lblGreeting.setText("Hi " + Preferences.getPreName());
// -- GROUP YOUR STATS (show all services)
createStatusGroupBox();
}
createStatusGroupBox():
private Group grpYourStatus = null; // outside the method for access in listener (below)
private void createStatusGroupBox() {
grpYourStatus = new Group(parent, SWT.NONE);
grpYourStatus.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));
grpYourStatus.setText("Your upload status");
grpYourStatus.setLayout(new GridLayout(3, false));
// add message if no service is registered
if ( r.getServiceList().size() == 0 ) {
Label status = new Label(grpYourStatus, SWT.NONE);
status.setText("No service registered.");
new Label(grpYourStatus, SWT.NONE); //empty
new Label(grpYourStatus, SWT.NONE); //empty
}
// add labels (status, message, name) for each registered service
for ( IRecorderObject service : r.getServiceList() ) {
Label name = new Label(grpYourStatus, SWT.NONE);
Label status = new Label(grpYourStatus, SWT.NONE);
Label message = new Label(grpYourStatus, SWT.NONE);
message.setFont(smallFont);
message.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
service.getServiceViewItem().setLabelsAndIcons(name, status, message, checkIcon, errorIcon); //this also sets the values of the labels (label.setText(...) via data binding)
}
Unfortunately, I don't know what the right way is to update/reset it. I tried the following:
listener (which should update the view / the services-list):
r.addPropertyChangeListener(BindingNames.SERVICE_ADDED, new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
// This "redraws" the view, but just places the whole content (generated in createStatusGroupBox()) above the other parts.
//Display.getCurrent().update();
//createStatusGroupBox();
//parent.layout(true);
//parent.redraw();
// disposes grpYourStatus-Group but doesn't show anything then
grpYourStatus.dispose();
createStatusGroupBox();
grpYourStatus.layout();
grpYourStatus.redraw();
}
});
}
});
I also tried the following statements (individually); all without success:
parent.redraw();
parent.update();
parent.layout();
parent.layout(true);
parent.refresh();
In this post I read the following:
createPartControls is that time of the life cycle of a view, where its
contained widgets are created (when the view becomes visible
initially). This code is only executed once during the view life
cycle, therefore you cannot add anything here directly to refresh your
view.
Eclipse parts typically update their content as a reaction to a
changed selection inside of the workbench (e.g. the user might click
on another stack frame in the debug view).
Unfortunately, I don't know what to else I could try and I didn't find anything helpful with searches... thank's for your help and suggestions!
I finally found the answer (together with AndreiC's help!):
my listener now looks like this:
r.addPropertyChangeListener(BindingNames.SERVICE_ADDED, new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
// remove grpYourStatus from parent
grpYourStatus.dispose();
// add grpYourStatus (with updated values) to parent
createStatusGroupBox();
// refresh view
parent.pack();
parent.layout(true);
}
});
}
});
The rest is the same like the code above.
I do not know the API by heart, but have you tried parent.update()?

Eclipse RCP: Generating views from form values

I want to build a user interface similar to the sketch below:
When the user fills out the form on the right and clicks the 'Plot!' button, a new closeable tab opens on the left with a chart.
I am new to RCP and have been following this tutorial. I am able to bring up tabs with charts triggered from a menu item. How do I go about:
creating the tab (view?) with the form
open a new chart tab when the user clicks the button
Edit
Here is my current code. It satisfies the basic requirements outlined in this question, but I am not sure if that is the best approach. I would be delighted if someone here can guide me in the right direction.
A view with the form; the button's listener invokes a command.
public class FormView extends ViewPart {
public static final String ID =
FormView.class.getPackage().getName() + ".Form";
private FormToolkit toolkit;
private Form form;
public Text text;
#Override
public void createPartControl(Composite parent) {
toolkit = new FormToolkit(parent.getDisplay());
form = toolkit.createForm(parent);
form.setText("Pie Chucker");
GridLayout layout = new GridLayout();
form.getBody().setLayout(layout);
layout.numColumns = 2;
GridData gd = new GridData();
gd.horizontalSpan = 2;
Label label = new Label(form.getBody(), SWT.NULL);
label.setText("Chart Title:");
text = new Text(form.getBody(), SWT.BORDER);
text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Button button = new Button(form.getBody(), SWT.PUSH);
button.setText("Plot");
gd = new GridData();
gd.horizontalSpan = 2;
button.setLayoutData(gd);
button.addMouseListener(new MouseAdapter() {
#Override
public void mouseDown(MouseEvent e) {
IHandlerService handlerService = (IHandlerService) getSite()
.getService(IHandlerService.class);
try {
handlerService.executeCommand(ShowChartHandler.ID, null);
} catch (Exception ex) {
throw new RuntimeException(ShowChartHandler.ID +
" not found");
}
}
});
}
#Override
public void setFocus() {
}
}
The command invoked by the button from the form. This opens a new view with a chart.
public class ShowChartHandler extends AbstractHandler implements IHandler {
public static final String ID =
ShowChartHandler.class.getPackage().getName() + ".ShowChart";
private int count = 0;
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
try {
window.getActivePage().showView(ChartView.ID,
String.valueOf(++count), IWorkbenchPage.VIEW_ACTIVATE);
} catch (PartInitException e) {
e.printStackTrace();
}
return null;
}
}
The view with the chart. It looks up the form view and reads a value from a text field in the form (?!):
public class ChartView extends ViewPart {
public static final String ID =
ChartView.class.getPackage().getName() + ".Chart";
private static final Random random = new Random();
public ChartView() {
// TODO Auto-generated constructor stub
}
#Override
public void createPartControl(Composite parent) {
FormView form =
(FormView) Workbench.getInstance()
.getActiveWorkbenchWindow()
.getActivePage()
.findView(FormView.ID);
String title = form == null? null : form.text.getText();
if (title == null || title.trim().length() == 0) {
title = "Pie Chart";
}
setPartName(title);
JFreeChart chart = createChart(createDataset(), title);
new ChartComposite(parent, SWT.NONE, chart, true);
}
#Override
public void setFocus() {
// TODO Auto-generated method stub
}
/**
* Creates the Dataset for the Pie chart
*/
private PieDataset createDataset() {
Double[] nums = getRandomNumbers();
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setValue("One", nums[0]);
dataset.setValue("Two", nums[1]);
dataset.setValue("Three", nums[2]);
dataset.setValue("Four", nums[3]);
dataset.setValue("Five", nums[4]);
dataset.setValue("Six", nums[5]);
return dataset;
}
private Double[] getRandomNumbers() {
Double[] nums = new Double[6];
int sum = 0;
for (int i = 0; i < 5; i++) {
int r = random.nextInt(20);
nums[i] = new Double(r);
sum += r;
}
nums[5] = new Double(100 - sum);
return nums;
}
/**
* Creates the Chart based on a dataset
*/
private JFreeChart createChart(PieDataset dataset, String title) {
JFreeChart chart = ChartFactory.createPieChart(title, // chart title
dataset, // data
true, // include legend
true, false);
PiePlot plot = (PiePlot) chart.getPlot();
plot.setSectionOutlinesVisible(false);
plot.setLabelFont(new Font("SansSerif", Font.PLAIN, 12));
plot.setNoDataMessage("No data available");
plot.setCircular(false);
plot.setLabelGap(0.02);
return chart;
}
}
The perspective that ties it all together:
public class Perspective implements IPerspectiveFactory {
public void createInitialLayout(IPageLayout layout) {
layout.setEditorAreaVisible(false);
layout.addStandaloneView(FormView.ID, false,
IPageLayout.RIGHT, 0.3f,
IPageLayout.ID_EDITOR_AREA);
IFolderLayout charts = layout.createFolder("Charts",
IPageLayout.LEFT, 0.7f, FormView.ID);
charts.addPlaceholder(ChartView.ID + ":*");
}
}
I would recommend a different aproach. Eclipse has viewparts (views) and editors. It is easy to open multiple editors. Views are not so much for open multiple ones.
So my suggestion is, that you implement the part you call "FormView" as a StandAloneView and implement the "ChartView" as an editor.
I would also recommend to use a different listener for the button, so also the code will be executed when using the keyboard to click the button.
My proposal:
public class FormView extends ViewPart {
...
button.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
// this below can also be called by a command but you need to take care about the data, which the user put into the fields in different way.
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
IWorkbenchPage page = window.getActivePage();
ChartEditorInput input = new ChartEditorInput(text.getText(),...<other data you need to pass>);
try {
page.openEditor(input, ChartEditor.ID);
} catch (PartInitException e) {
e.printStackTrace();
}
}
});
ChartView needs to be changed to ChartEditor. See here http://www.vogella.de/articles/RichClientPlatform/article.html#editor_editorinput how that is done.
ChartEditorInput hereby is a class you need to implement aside the editor class, which holds the data.
In your perspective you call:
public void createInitialLayout(IPageLayout layout) {
String editorArea = layout.getEditorArea();
layout.setFixed(false);
layout.setEditorAreaVisible(true);
layout.addStandaloneView("your.domain.and.FormView", true,IPageLayout.RIGHT, 0.15f, editorArea);
Hope this helps!

Categories