I created TreeViewer and I put setAutoExapandLevel for the tree
treeViewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
treeViewer.setContentProvider(new TreeContentProvider());
treeViewer.setLabelProvider(new TreeLabelProvider());
treeViewer.setAutoExpandLevel(3);
treeViewer.setInput(new Model());
the problem that it is not auto expand for the tree
Do you have any idea why it is not working ?
Are you sure the model contains all the data when setInput() is called?
internalExpandToLevel(Widget widget, int level) (where expanding takes place) is called on inputChanged(Object input, Object oldInput). If at the time setInput is called the model is empty, no node will be expanded. Even if you later add nodes and call refresh.
To prove this, I changed my snippet from an answer for another question.
Run this code as it is, then run it with the empty field initialized to true. You will see the difference.
static boolean empty = false;
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
TreeViewer treeViewer = new TreeViewer(shell, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
treeViewer.setContentProvider(new DummyContentProvider());
treeViewer.setAutoExpandLevel(3);
treeViewer.setInput("root");
empty = true;
treeViewer.refresh();
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private static class DummyContentProvider implements ITreeContentProvider {
#Override
public Object[] getElements(Object inputElement) {
return this.getChildren(inputElement);
}
#Override
public Object[] getChildren(Object parentElement) {
if (!empty) {
return new Object[0];
}
switch ((String) parentElement) {
case "root":
return new String[]{"a", "b"};
case "a":
return new String[]{"1"};
case "b":
return new Object[]{"1", "2"};
case "1":
return new Object[]{"x", "y"};
default:
return new String[0];
}
}
#Override
public Object getParent(Object element) {
return null;
}
#Override
public boolean hasChildren(Object element) {
return this.getChildren(element).length > 0;
}
#Override
public void dispose() {
}
#Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
Related
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.
I wish to use org.eclipse.swt.widgets.List just to present some data. User should not be allowed to select any item.
I could just:
List list = new List(this, SWT.V_SCROLL);
list.setEnabled(false);
But then I will loose scrolling feature. How can I just make list items unselectable?
Another alternative is to use a Table instead of List and disable selection painting like this:
table.addListener(SWT.EraseItem, new Listener() {
#Override
public void handleEvent(Event event) {
event.detail &= ~SWT.SELECTED;
event.detail &= ~SWT.HOT;
}
});
You could try to clear selection each time user selects an item. The selection will be visible for a short time interval, though.
list.addListener(SWT.Selection, new Listener() {
#Override
public void handleEvent(Event event) {
list.setSelection(new String[0]);
}
});
If you don't like my other answer with clearing selection, you could try to keep the list disabled, but inside a ScrolledComposite. It will look disabled, but scrolling will work. Here is a snippet:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
final ScrolledComposite scrolledComposite = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL);
scrolledComposite.setExpandHorizontal(true);
scrolledComposite.setExpandVertical(true);
scrolledComposite.setBackground(display.getSystemColor(SWT.COLOR_CYAN));
final List list = new List(scrolledComposite, SWT.NONE);
list.setEnabled(false);
scrolledComposite.setContent(list);
scrolledComposite.addListener(SWT.Resize, new Listener() {
#Override
public void handleEvent(Event event) {
final Point size = list.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
scrolledComposite.setMinSize(size);
}
});
for (int i = 0; i < 1000; i++) {
list.add(Integer.toString(i));
}
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
Arrow keys and page up/down down do not work, so you will have to register key listeners and implement scrolling with keyboard.
I'm using a custom Dialog with a CheckboxTreeViewer inside my GMF Editor, which works fine so far, as you can see below:
After closing the Dialog, the selected element are saved so far. Now my Problem:
When I open the dialog again, all elements are unchecked. So I thought it would be easy to tell the treeViewer that specific elements should be initially checked.
But it turned out that it's not that easy, as the Tree initially consist of the root element. The other elements are not added until the tree expands. Elements are added by calling the getChildren(Object parentElement) of the ContentProvider.
So it seems that I can't check specific elements initially, but rather have to provide a dynamically approach. I'm looking for something like an element added listener, but there seems none to exist.
Here is the part, where I'm creating the CheckboxTreeViewer
Composite container = (Composite) super.createDialogArea(parent);
tv = new CheckboxTreeViewer(container, SWT.MULTI | SWT.H_SCROLL
| SWT.V_SCROLL);
tv.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
tv.setAutoExpandLevel(2);
tv.setContentProvider(new FeaturePropertyDialogContentProvider(this));
tv.setLabelProvider(new FeaturePropertyDialogLabelProvider());
tv.setInput(productLine);
tv.setExpandPreCheckFilters(true);
return container;
And here is the getChildren method of my ContentProvider:
#Override
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof PL) {
PL p = (PL) parentElement;
return new Object[] { p.getPropertyList() };
}
else if (parentElement instanceof PropertyList) {
PropertyList propertyList = (PropertyList) parentElement;
return propertyList.getGeneralPlatforms().toArray();
} else if (parentElement instanceof GeneralPlatform) {
GeneralPlatform platform = (GeneralPlatform) parentElement;
return platform.getHardwareElements().toArray();
}
} else {
return null;
}
}
Any ideas on this?
--------------------Solution---------------------
Found the following solution by myself, which works fine for me so far:
tv.expandAll();
tv.setCheckedElements(preSelectedProperties.toArray());
tv.collapseAll();
tv.expandToLevel(2);
You should add a listener on the tree viewer to get a notification when a node gets expanded (method addTreeListener() on TreeViewer). At that time, the nodes are already in the tree, and you can check the check-box.
Here is a snippet of a tree that sets the check state when the tree is expanded:
public class Snippet {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
final Map<String, Boolean> userChecks = new HashMap<>();
final CheckboxTreeViewer tv = new CheckboxTreeViewer(shell, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
GridData gridData = new GridData(GridData.FILL_BOTH);
tv.getTree().setLayoutData(gridData);
final FeaturePropertyDialogContentProvider provider = new FeaturePropertyDialogContentProvider(tv);
tv.setContentProvider(provider);
tv.setInput("root");
tv.addCheckStateListener(new ICheckStateListener() {
#Override
public void checkStateChanged(CheckStateChangedEvent event) {
userChecks.put((String) event.getElement(), event.getChecked());
}
});
tv.addTreeListener(new ITreeViewerListener() {
#Override
public void treeCollapsed(TreeExpansionEvent event) {
}
#Override
public void treeExpanded(TreeExpansionEvent event) {
final Object element = event.getElement();
final Object[] children = provider.getChildren(element);
for (Object child : children) {
if (userChecks.containsKey(child)) {
tv.setChecked(child, userChecks.get(child));
} else if (child.equals("b")) {
tv.setChecked(child, true);
}
}
}
});
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private static class FeaturePropertyDialogContentProvider implements ITreeContentProvider {
final CheckboxTreeViewer tv;
private FeaturePropertyDialogContentProvider(CheckboxTreeViewer tv) {
this.tv = tv;
}
#Override
public Object[] getElements(Object inputElement) {
return this.getChildren(inputElement);
}
#Override
public Object[] getChildren(Object parentElement) {
switch ((String) parentElement) {
case "root":
return new String[]{"1"};
case "1":
return new String[]{"a", "b", "c"};
default:
return new String[0];
}
}
#Override
public Object getParent(Object element) {
return null;
}
#Override
public boolean hasChildren(Object element) {
return this.getChildren(element).length > 0;
}
#Override
public void dispose() {
}
#Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
}
In this example, I only compare the node value with the string "b".
Edit: in this context, elements are immutable (for some reason they cannot be changed), and the solution with wrapping objects in tree nodes is not accepted (see comments).
In that case, you can save user check actions in a map, and when setting checked/unchecked state, search for any previous user check actions. I think it is reasonable to assume the map is simple and will not grow too much. User has to check a lot of nodes to get it big :)
I updated the snippet to keep track of user checks.
I recently implemented a CheckboxTreeViewer in my own Dialog. This works fine so far except that the tree doesn't allow me to expand nodes by default. It only works when I check the checkbox, as you can see in the following images:
This is by default. As you can see, it's not possible to expand the node, though it has children:
After checking the check box, it works:
I already tried to use setExpandPreCheckFilters , but with no success:
Composite container = (Composite) super.createDialogArea(parent);
tv = new CheckboxTreeViewer(container, SWT.MULTI | SWT.H_SCROLL| SWT.V_SCROLL);
GridData gridData = new GridData(GridData.FILL_BOTH);
tv.getTree().setLayoutData(gridData);
tv.setContentProvider(new FeaturePropertyDialogContentProvider());
tv.setLabelProvider(new FeaturePropertyDialogLabelProvider());
tv.setAutoExpandLevel(2);
tv.setExpandPreCheckFilters(true);
Any ideas?
-----------------------------------Update-------------------------------------
I found the reason of the problem. I forgott to check every element in the hasChildren method. The following code is working now for me:
public boolean hasChildren(Object element) {
if (element instanceof ProductLine) {
ProductLine productLine = (ProductLine) element;
if (productLine.getPropertyList() != null) {
return true;
} else {
return false;
}
}
if (element instanceof PropertyList) {
PropertyList propertyList = (PropertyList) element;
if (!(propertyList.getGeneralPlatforms().isEmpty())) {
return true;
} else {
return false;
}
} else if (element instanceof GeneralPlatform) {
GeneralPlatform platform = (GeneralPlatform) element;
if (!(platform.getHardwareElements().isEmpty())) {
return true;
} else {
return false;
}
} else if (element instanceof HardwareElement) {
HardwareElement hw = (HardwareElement) element;
if (!(hw.getHardwareElements().isEmpty())
|| !(hw.getProperties().isEmpty())) {
return true;
} else {
return false;
}
} else {
return false;
}
}
Thx for your help!!
From the SWT javadoc of setAutoExpandLevel:
The value 0 means that there is no auto-expand;
1 means that the invisible root element is expanded (since most
concrete subclasses do not show the root element, there is usuallyno
practical difference between using the values 0 and 1);
2 means that top-level elements are expanded, but not their children;
3 means that top-level elements are expanded, and their children, but
not grandchildren;
So you should set auto expand level to 3, not 2.
Since the code you posted is not complete, I would like to also mention that it is important also when you call setAutoExpandLevel(). Internally it is called when input is changed. So it should be called before setRoot().
Below is a sample code that builds a tree like yours and expands the nodes:
public class CheckTreeSnippet {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
CheckboxTreeViewer tv = new CheckboxTreeViewer(shell, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
GridData gridData = new GridData(GridData.FILL_BOTH);
tv.getTree().setLayoutData(gridData);
tv.setAutoExpandLevel(3);
tv.setContentProvider(new FeaturePropertyDialogContentProvider());
tv.setInput("root");
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private static class FeaturePropertyDialogContentProvider implements ITreeContentProvider {
#Override
public Object[] getElements(Object inputElement) {
return this.getChildren(inputElement);
}
#Override
public Object[] getChildren(Object parentElement) {
switch ((String) parentElement) {
case "root":
return new String[]{"Platform XYZ12", "Platform ZUPP"};
case "Platform XYZ12":
return new String[]{"Microcontroller TPU23"};
case "Platform ZUPP":
return new Object[]{"Sensor", "Precaler IO"};
case "Sensor":
return new Object[]{"unknown child 1", "unknown child 3"};
default:
return new String[0];
}
}
#Override
public Object getParent(Object element) {
return null;
}
#Override
public boolean hasChildren(Object element) {
return this.getChildren(element).length > 0;
}
#Override
public void dispose() {
}
#Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
}
So I have a drop down menu built below:
new Label(shell, SWT.NONE).setText("Bet Type:");
betType = new Combo(shell, SWT.SINGLE | SWT.BORDER);
betType.setItems(new String[] {" ", "NFL", "NBA", "CFB"});
betType.setLayoutData(gridData);
What I want is for when somebody selects one of the dropdown options, a function that I will write later will be called.
I've tried doing things like:
betType.addSelectionListener(new SelectionAdapter()) { ... }
Or:
betType.addSelectionListener(new SelectionListener()) { ... }
Or:
betType.addModifyListener(new ModifyListener()) { ... }
And I keep getting errors saying "Cannot Instantiate the type ModifyListener or SelectionListener" etc. How would one go about correcting this?
The problem with your code is that you close the first (-bracket too early.
This:
betType.addSelectionListener(new SelectionListener()) { ... }
should be:
betType.addSelectionListener(new SelectionListener() { ... });
The following code does exactly what you want:
public static void main(String[] args)
{
Display d = new Display();
final Shell shell = new Shell(d);
shell.setLayout(new GridLayout(1, false));
new Label(shell, SWT.NONE).setText("Bet type:");
final Combo betType = new Combo(shell, SWT.SINGLE | SWT.BORDER);
betType.setItems(new String[] {" ", "NFL", "NBA", "CFB"});
betType.addListener(SWT.Selection, new Listener()
{
#Override
public void handleEvent(Event arg0)
{
System.out.println(betType.getText());
}
});
shell.pack();
shell.open();
while (!shell.isDisposed())
while (!d.readAndDispatch())
d.sleep();
}
Alternatively, this works as well:
betType.addSelectionListener(new SelectionListener()
{
#Override
public void widgetSelected(SelectionEvent arg0)
{
System.out.println(betType.getText());
}
#Override
public void widgetDefaultSelected(SelectionEvent arg0)
{
}
});