When put all widgets in one container, the gridlayout could align normally.
But for some reason, I need to put some widgets to a sub-container such as the composite as below. The alignment is different.
So the question is: Is there a container that has no effect on the gridlayout?
Ps: I know that can use white space as a workaround, but...
Code:
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
GridLayoutFactory.fillDefaults().numColumns(2).margins(8, 3).applyTo(shell);
new Label(shell, 0).setText("Label1");
new Text(shell, 0);
new Label(shell, 0).setText("A long Label");
new Text(shell, 0);
Composite composite = new Composite(shell, 0);
GridDataFactory.fillDefaults().span(2, 1).applyTo(composite);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(composite);
new Label(composite, 0).setText("Label22");
new Text(composite, 0);
new Label(composite, 0).setText("Label223");
new Text(composite, 0);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
Result:
There is no container that can used like this. Sticking to a single composite is by far the easiest way to aligh the labels.
It is possible to specify the widthHint of the GridData for a label to specify the width. You would have to calculate the width required using something like:
List<Control> labels = ... list of Label controls
final int width = labels.stream()
.mapToInt(label -> label.computeSize(SWT.DEFAULT, SWT.DEFAULT).x)
.max()
.getAsInt();
final var labelData = GridDataFactory.swtDefaults().hint(width, SWT.DEFAULT);
labels.forEach(labelData::applyTo);
Related
I am trying to create a Simple UI which contains a combo, a text box and a browse button. The combo will be containing two values: Execution Times and Execute with File.
When the Execution Times option is selected, the combo box followed by a text box should be displayed.
when the Execute with File option is selected, the combo box, a text box, and a browse button should be displayed.
When I am switching between these options, the widgets are not getting aligned properly. Refer to the below image. The text box size is not getting expanded to the available space.
public class TestUI {
public static void main(String[] args)
{
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new GridLayout(1, true));
Composite composite = new Composite(shell, SWT.NONE);
composite.setLayout(new GridLayout(3, false));
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
Combo combo = new Combo(composite, SWT.READ_ONLY);
String[] input = { "Execution Times", "Execute with File" };
combo.setItems(input);
Text loopText = new Text(composite, SWT.SINGLE | SWT.BORDER);
GridData gridData = new GridData(SWT.BEGINNING | GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = 2;
loopText.setLayoutData(gridData);
loopText.setEnabled(false);
Button browseButton = new Button(composite, SWT.PUSH);
browseButton.setText("Browse...");
browseButton.setVisible(false);
combo.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
String text2 = combo.getText();
System.out.println(text2);
if (text2.equals("Execution Times")) {
loopText.setEnabled(true);
loopText.setText("1");//$NON-NLS-1$
GridData gridData1 = new GridData(SWT.BEGINNING, SWT.TOP, false, false);
gridData1.grabExcessHorizontalSpace = true;
gridData1.horizontalSpan = 2;
loopText.setLayoutData(gridData1);
browseButton.setVisible(false);
loopText.getParent().layout();
}
if (text2.equals("Execute with File")) {
GridData gridData1 = new GridData(SWT.BEGINNING, SWT.TOP, false, false);
gridData1.grabExcessHorizontalSpace = true;
loopText.setLayoutData(gridData1);
gridData.exclude= false;
browseButton.setVisible(true);
browseButton.setFocus();
loopText.setText("");
loopText.setEnabled(false);
loopText.getParent().layout();
}
}
});
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
Can any one help me on this?
From what I understand, depending on the combo selection, the text field and text field plus button serve different purposes:
when Execution Times is selected, the number of times is to be entered
otherwise Execute with File requires a file name to be entered or browsed for
Therefore, I would use a Composite next to the combo widget to hold either a text field to enter a number (or even a Spinner) or a text field and button to enter/select a file name.
Composite composite = new Composite( parent, SWT.NONE );
Text executionTimesText = new Text( composite, SWT.BORDER );
composite.setLayout( new StackLayout() );
Composite executionFileComposite = new Composite( composite, SWT.NONE );
// use a GridLayout to position the file name text field and button within the executionFileComposite
combo.addListener( SWT.Selection, event -> {
StackLayout layout = ( StackLayout )composite.getLayout();
if( combo.getSelectionIndex() == 0 ) {
layout.topControl = executionTimesText;
} else if( combo.getSelectionIndex() == 1 ) {
layout.topControl = executionFileComposite;
}
composite.layout();
}
The StackLayout allows you to stack the different input fields and switch betwen them as needed (i.e. according to the combo's selection).
For starters, you don't need to recreate the GridData for the Text widget every time. Instead, just modify the original via gridData.horizontalSpan, or if in practice you don't have access to the GridData instance, you can get at it via ((GridData) gridData.getLayoutData()).horizontalSpan, etc.
The reason you're seeing the blank space at the bottom of the Shell is because you've created a layout with 3 columns, and then added the following:
The Combo
The Text (with horizontalSpan set to 2, so this uses 2 columns)
The Button
The Combo and the Text take up all 3 columns, so a new row is added for the Button. Then you call pack(), and the preferred size is calculated, which will be for 2 rows, and the first row only sized for 2 widgets.
Instead of calling pack() and shrinking the size of the Shell down to the preferred size, we can just set a size on the Shell via Shell.setSize(...). In general you don't want to mix setSize(...) and layouts, but you've tagged your post with "RCP", so your Shell will already have a size and you won't be manually calling pack() and open().
Full example:
public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
shell.setSize(300, 80);
shell.setText("StackOverflow");
shell.setLayout(new GridLayout(1, true));
Composite composite = new Composite(shell, SWT.NONE);
composite.setLayout(new GridLayout(3, false));
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
final Combo combo = new Combo(composite, SWT.READ_ONLY);
String[] input = {"Execution Times", "Execute with File"};
combo.setItems(input);
final Text loopText = new Text(composite, SWT.SINGLE | SWT.BORDER);
final GridData textGridData = new GridData(SWT.FILL, SWT.FILL, true, false);
textGridData.horizontalSpan = 2;
loopText.setLayoutData(textGridData);
loopText.setEnabled(false);
final Button browseButton = new Button(composite, SWT.PUSH);
browseButton.setText("Browse...");
browseButton.setVisible(false);
combo.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
String text2 = combo.getText();
System.out.println(text2);
if (text2.equals("Execution Times")) {
loopText.setEnabled(true);
loopText.setText("1");
// Can also do ((GridData) textGridData.getLayoutData())...
textGridData.grabExcessHorizontalSpace = true;
textGridData.horizontalSpan = 2;
browseButton.setVisible(false);
loopText.getParent().layout();
}
if (text2.equals("Execute with File")) {
loopText.setEnabled(false);
loopText.setText("");
textGridData.grabExcessHorizontalSpace = true;
textGridData.horizontalSpan = 1;
browseButton.setVisible(true);
browseButton.setFocus();
loopText.getParent().layout();
}
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
Alternatively, if you are actually creating and opening a new Shell, then call pack() (to get the preferred size) prior to making the Text widget take up two columns:
shell.pack();
// Move these two lines down to the end
textGridData.horizontalSpan = 2;
browseButton.setVisible(false);
shell.layout(true, true);
shell.open();
What we've done is add all 3 widgets without adjusting the horizontalSpan. Then, call pack() to set the size of the Shell assuming that all 3 widgets appear in a single row. After calling pack(), set the horizontalSpan to 2, and hide the Button. When the Shell is opened, you will see:
It seems that NorthSouthContainer can ajust the height of north widget.
Can BorderLayoutContainer do the same one?
(gxt version: 3.1.1)
public void onModuleLoad() {
final BorderLayoutContainer cont = new BorderLayoutContainer();
// final NorthSouthContainer cont = new NorthSouthContainer();
final ToolBar bar = new ToolBar();
bar.add(new TextButton("tool bar"));
cont.setNorthWidget(bar);
final ContentPanel panel = new ContentPanel();
panel.setHeadingText("content panel");
cont.setCenterWidget(panel);
// cont.setSouthWidget(panel);
final Viewport vp = new Viewport();
vp.add(cont);
RootPanel.get().add(vp);
}
NorthSouthContainer:
BorderLayoutContainer:
I know there are display bugs with that view. I'm not sure if it can be dynamically sized, we specifically set the height for it.
final BorderLayoutData northData = new BorderLayoutData(<height>);
cont.setNorthWidget(bar, northData);
You may have to add the toolbar into another container that deals with size better, ours is a HorizontalLayoutContainer inside of a ContentPanel.
I created a Window Trim - Top
now I add 3 Tool Control
first only should contain a SWT-Text and not resize ever...
however, when I type some text and resize my window, it automatically resizes the SWT-Text to fit the text, which it should not.
So how can I give that Tool Control, or the Composite, or the Text the right Size and tell it, NOT to resize!?
public class TrimBarSearch {
#Inject
ISearchService searchService;
private Text txtSearch;
private Composite composite;
#Inject
public TrimBarSearch() {
}
#PostConstruct
public void createGui(final Composite parent) {
parent.setLayoutData(new GridLayout(3, false));
composite = new Composite(parent, SWT.NONE);
Point xy = new Point(300, 15);
Point sizeComposite = new Point(310, 25);
composite.setLayout(new GridLayout(1, false));
composite.setSize(sizeComposite);
txtSearch = new Text(composite, SWT.FILL);
txtSearch.setSize(xy);
txtSearch.setText("");
// TODO fix resizing-problem
parent.getShell().addListener(SWT.Resize, e -> {
//maybe here?!
});}
Never try and mix Layouts with setSize - it does not work, the layout will override your size.
Instead you can specify a width hint for the text in the GridData for the text. Instead of:
txtSearch.setSize(xy);
use:
GridData data = new GridData(SWT.BEGINNING, SWT.CENTER, false, false);
data.widthHint = 300;
txtSize.setLayoutData(data);
There is situation that I have a ComboViewer which will have different content in different time.Thus, it will sometimes need to relayout the ComboViewer so that it can show the full content. Is there any way to define the max length of ComboViewer in beginning? I will very appreciate if you can give me some idea.
The following code is the demo I try according to the rudiger.It works well in windows 7, while the length of the comboviewer is still short when it switches to "abcedfgabcedfg" in linux
.
public class ComboViewerTest {
/**
* #param args
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("Comboviewer Test");
shell.setLayout(new GridLayout(1, false));
Composite composite = new Composite(shell,SWT.None);
composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));
composite.setLayout(new GridLayout(2, true));
final String[] txtStrings = {"a","abc"};
final String[] txtStrings2 = { "abcedfg", "abcedfgabcedfg"};
Label label = new Label(composite, SWT.NONE);
label.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true, 1, 1));
label.setText("comboviewer");
final ComboViewer comboViewer = new ComboViewer(composite,SWT.NONE | SWT.READ_ONLY);
Combo combo = comboViewer.getCombo();
combo.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true, 1, 1));
comboViewer.setContentProvider(new ArrayContentProvider());
comboViewer.setInput(txtStrings);
comboViewer.setLabelProvider(new LabelProvider() {
#Override
public String getText(Object element) {
return super.getText(element);
}
});
Composite composite2 = new Composite(shell,SWT.None);
composite2.setLayout(new GridLayout(2, true));
Button btnNewButton = new Button(composite2, SWT.RADIO);
btnNewButton.setBounds(0, 0, 84, 29);
btnNewButton.setText("change the comboviewr");
btnNewButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
comboViewer.setInput(txtStrings2);
comboViewer.getCombo().select(0);
}});
Button btnNewButton2 = new Button(composite2, SWT.RADIO);
btnNewButton2.setBounds(0, 0, 84, 29);
btnNewButton2.setText("reset");
btnNewButton2.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
comboViewer.setInput(txtStrings);
comboViewer.getCombo().select(0);
}});
comboViewer.getCombo().select(0);
setComboViewerLength(comboViewer);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private static void setComboViewerLength(ComboViewer comboViewer) {
String string = "abcedfgabcedfg";
Combo control = comboViewer.getCombo();
GC gc = new GC( control );
Point stringExtent = gc.stringExtent( string );
gc.dispose();
Rectangle bounds = control.computeTrim( 0, 0, stringExtent.x, stringExtent.y );
GridData gridData = new GridData();
gridData.widthHint = bounds.width;
control.setLayoutData( gridData );
}
}
If I understand your question correctly, the problem is twofold.
1. Determining the necessary size to fully display a string of a certain length
The ComboViewer uses SWT's Combo or CCombo widget to display its data. Given the string to display, you can determine the necessary size of the combo in pixels as follows:
String string = "abc";
ComboViewer comboViewer = ...;
Combo control = comboViewer.getCombo();
GC gc = new GC( control );
Point stringExtent = gc.stringExtent( string );
gc.dispose();
Rectangle bounds = control.computeTrim( 0, 0, stringExtent.x, stringExtent.y );
The returned bounds describe a rectangle that if the combo's bounds were set to that rectangle, is large enough to display the string and trimmings (the drop-down button, borders, etc.).
2. Configuring the layout to use the above calculated size for the combo box
How to control the size of a widget depends on which layout manager you are using. The layout manager that is used is set on the parent of your combo.
Some - but not all - layouts allow to give hints or explicitly set the desired width and height of a control.
If you are using a GridLayout, for example, define a GridData for the combo to control its size.
Combo control = comboViewer.getCombo();
GridData gridData = new GridData();
gridData.widthHint = bounds.width;
control.setLayoutData( gridData );
For more on layouts and a description of the SWT standard layouts I recommend reading the Understanding Layouts in SWT article.
This is the full working code:
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(400, 300);
shell.setLayout(new GridLayout());
ExpandBar expandBar = new ExpandBar(shell, SWT.V_SCROLL);
expandBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
for (int i = 0; i < 3; i++) {
Group group = new Group(expandBar, SWT.NONE);
GridData layoutData = new GridData(GridData.FILL_BOTH);
layoutData.minimumHeight = 225;
layoutData.minimumWidth = 225;
layoutData.grabExcessVerticalSpace = true;
group.setLayoutData(layoutData);
group.setLayout(new GridLayout());
new Label(group, SWT.NONE).setText("Text " + i);
ExpandItem expandItem = new ExpandItem(expandBar, SWT.NONE);
expandItem.setControl(group);
expandItem.setText("Group " + i);
expandItem.setHeight(group.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
expandItem.setExpanded(true);
}
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
If you run this program and try to resize the window, ExpandItems will be resized horizontally, but not vertically:
(Note the empty space at the bottom).
How to make them be resized vertically too?
The problem lies in this line:
expandItem.setHeight(group.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
Computed sized will be based on controls within a group + related layout information, like margins. So, since your group contains only one label, computed size height cannot be more then the size of the label. Even if you add more controls if will always compute the size to fit all the controls without adding any extra space.
What you could is could provide a height hint to computeSize method. Something like this:
expandItem.setHeight(group.computeSize(SWT.DEFAULT, 500).y);
Otherwise there is no way for SWT to understand how big you want your expand items to be.