I must be missing something stupid. The docs clearly state that the RowData object for the RowLayout layout lets you specify a minimum size (width and height), which makes sense. However, when the underlying widget exceeds this size, the size does not increases and the widget is cropped. Is it really a minimum?
Example
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("Example");
shell.setBounds(100, 100, 325, 200);
shell.setLayout(new FillLayout());
Composite comp = new Composite(shell, SWT.BORDER);
comp.setLayout(new RowLayout(SWT.VERTICAL));
Label label1 = new Label(comp, SWT.CENTER);
label1.setLayoutData(new RowData(20,20));
label1.setText("Trying with bounded rowdata...");
Label label2 = new Label(comp, SWT.CENTER);
label2.setText("Trying with no rowdata...");
comp.layout(true,true); // no difference
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
Result:
The javadoc of the constructor RowData(int, int) must be wrong! If you read carrefully the header of the RowData javadoc, it is said that RowData are used to set an initial size for Controls, not the minimum. That's why your Labelis croped by a square of 20x20 px!
Try turning packing off on the layout:
Composite comp = new Composite(shell, SWT.BORDER);
RowLayout layout = new RowLayout(SWT.VERTICAL);
layout.pack = false;
comp.setLayout(layout);
On the other hand you can also consider using a GridLayout if you want the controls to resize with respect to their parents but not less than a minimum width. The minimum width works with GridData.
Related
I'm making an application that is some sort of drawing program, and to that end I am attempting to use SWT with a GLCanvas widget in the shell. This is a snippet of it that shows the problem I'm having:
shell = new Shell();
GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 2;
shell.setLayout(gridLayout);
shell.setSize(1000, 800);
shell.setText(APPLICATION_NAME);
Label label = new Label(shell, SWT.NONE);
label.setText("Test");
Composite composite = new Composite(shell, SWT.NONE);
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
composite.setLayoutData(gridData);
composite.setLayout(new FillLayout(SWT.HORIZONTAL));
GLData data = new GLData();
data.doubleBuffer = true;
canvas = new GLCanvas(composite, SWT.NO_BACKGROUND, data);
When I resize the window from this code, it does not display properly. The GLCanvas flickers, but it's also as if there's a step in the drawing where it draws the GLCanvas to the screen before it's been resized to properly fill the remaining white space. This has the effect where, for example, while the window is being resized to the left, the GLCanvas is smaller than it should be. Inversely, while the window is being resized to the right, the GLCanvas is larger than it should be and extends off into the right of the window.
I've tried setting the style of the canvas from SWT.NONE to SWT.NO_BACKGROUND to SWT.DOUBLE_BUFFERED to SWT.NO_REDRAW_RESIZE and it had no effect on this problem.
How can fix this behavior?
I have a simple SWT program like this:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
shell.setMinimumSize(300, 300);
// table
final Table table = new Table(shell, SWT.BORDER);
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
gridData.heightHint = 0; // "hack"
table.setLayoutData(gridData);
// example data
for (int i = 0; i < 50; i++) {
final TableItem item = new TableItem(table, SWT.NONE);
item.setText("item no." + i);
}
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
What I expect - I want the table to completely fill out the shells space without changing it's size. (Screenshot 1 and 3)
Problem - If I add rows to the table, the table automatically gets resized (and so also the shell). (Screenshot 2)
Workaround - To avoid this behaviour I added the line gridData.heightHint = 0; to the code. But this seems like a hack to me.
Question - What would be the correct way to avoid the enlargement of the table (and the shell) when data is added?
Regards, winklerrr
Screenshot 1
Without data, table and shell don't get resized, correct behaviour, in both versions
Screenshot 2
With data, table and shell are getting enlarged, wrong behaviour, only without the hack
Screenshot 3
With data, table and shell don't get resized, scrollbar is added, correct behaviour, only with the hack
call shell.setSize(int width, int height) at some point before adding data to the table?
You usually expect the table to have a certain logical height, say 20 rows. At least that's an approach I often choose.
To achieve that, I compute the expected initial height in pixels like this and use it as a height hint.
gridData.heightHint = table.getItemHeight() * 20;
To be more accurate, you would also want to add the table's trim.
shell.setSize(int width, int height)
add this code after the data to your table.
I am using a Gridlayout with 2 column. I have Labels and corresponding Text control with it. I wanted the Text control of first label to slip down the label instead of right next to it (since its a gridlayout). For this I thought the moveBelow method would work but doesn't seem to be. Am i interpreting the use of the method wrongly?
Label label = Components.createLabel(myContainer, SWT.LEFT
| SWT.WRAP);
abel.setText("WC Plan Name");
textName = createTextControl(myContainer, SWT.LEFT);
textName.moveBelow(label);
private Text createTextControl(Composite parent, int horizontalAlignment)
{
final Text textControl = Components.createText(parent, SWT.SINGLE | SWT.BORDER);
final GridData layoutData = new GridData(horizontalAlignment, SWT.FILL, false, false);
layoutData.widthHint = 200;
textControl.setLayoutData(layoutData);
return textControl;
}
moveBelow() does exactly what it says in the documentation:
Moves the receiver below the specified control in the drawing order. If the argument is null, then the receiver is moved to the bottom of the drawing order. The control at the bottom of the drawing order will be covered by all other controls which occupy intersecting areas.
This means that it can be used to reorder children (if the layout of the parent allows it). For example, if you have a RowLayout and call moveBelow(null) on the last child, it will be moved to the top.
Now to solve your problem: You have a GridLayout with 2 columns. A GridLayout is filled from top left to bottom right. If you want two elements to appear below each other rather than next to each other, there are two options:
Add an empty Label in between, so that it can occupy the space to the right of your first element
Add a GridData to your first element and set GridData#horizontalSpan to 2. This way it will span two columns.
UPDATE
Here is an example of solution 2:
public static void main(String[] args)
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new GridLayout(4, false));
Text text = new Text(shell, SWT.BORDER);
text.setLayoutData(new GridData(SWT.BEGINNING, SWT.TOP, false, true, 4, 1));
text = new Text(shell, SWT.BORDER);
text.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true, 4, 1));
for (int i = 0; i < 8; i++)
{
new Button(shell, SWT.PUSH).setText("Button " + i);
}
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
Looks like this:
Is there any way to set maximal size of composite? Only what i have found methods
setMinimumSize(Point point)
setSize(Point point)
which allow me to set minimal and prefered size.
As far as I know, there is no Layout, that has a setting for maximal size, which is a good thing in my opinion.
Consider the following szenario: You set the maximal size of a Widget/Composite to a value that you think "looks good". Depending on the screen resolution and text size of the end-user, the chosen maximal size might just look wrong. This is why the layouts usually adapt to the available space.
Nevertheless, here is some code, that restricts the size:
public static void main(String[] args)
{
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new GridLayout(1, false));
final Button left = new Button(shell, SWT.PUSH);
left.setText("Restricted width");
left.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
left.addListener(SWT.Resize, new Listener()
{
#Override
public void handleEvent(Event arg0)
{
Point size = left.getSize();
if(size.x > 200)
{
left.setSize(200, size.y);
}
}
});
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
Before resizing:
After resizing:
i am curious about why you want to set a maximum size. can you give a concrete example? i had a situation where i wanted this option, but i came up with a solution, that was even better. just think of a widget in a layout that has a preferred size based on its contents, e.g. a text widget. now you want that widget to be as big as the available space allows it. but since that widget is claiming space based on its contents, it might claim more space than necessary. so what i needed was a maximum size, but if more space is available, that widget will still be able to take the space without claiming more.
but lets have a look at an example:
public static void main(final String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
final Text text = new Text(shell, SWT.WRAP | SWT.MULTI | SWT.V_SCROLL);
text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
text.setText(getLongText());
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
the call to shell.pack() will make the shell use the preferred size to display its contents. the layout will then ask the text widget to compute its preferred size. the text widget does not know, that the shell will be expanded as well and does not have a fixed size.
well this problem can be solved if we could give the text widget a maximum size. but it will cause another problem with the grid layout, since we don't want the text widget to be smaller in case that the shell has a minimum size which is bigger than the preferred size of the text widget. i cannot give you a code example of this case, since there is no maximum size, but just imagine the shell be of a fixed size, and the the text widget inside has a maximum size that is smaller.
the solution is to limit the preferred size computed by the widget to be of a maximum preferred size. i didn't find yet a method to set this value, but you can achieve this effect by overriding the computeSize method of the widget:
final Text text = new Text(shell, SWT.WRAP | SWT.MULTI | SWT.V_SCROLL) {
/** The maximum preferred size. */
private final Point maxSize = new Point(500, 400);
#Override
public Point computeSize(final int wHint, final int hHint, final boolean changed) {
final Point preferredSize = super.computeSize(wHint, hHint, changed);
return new Point(Math.min(maxSize.x, preferredSize.x), Math.min(maxSize.y, preferredSize.y));
}
#Override
protected void checkSubclass() {
// noop, allow subclassing, since we know what we are doing
}
};
now you are still able to increase the shells size by a user drag operation and the widget will still we able to grab more space above the maximum size.
This problem has been driving me CRAZY!!! Using SWT, I'd like to create a grid of numbers that I can tab traverse using the keyboard. I'd like to be able to select and click into each cell (not just on the numbers) to perform some action. In other words, I'm looking for a way to make a true FLAT button. The goal here is to make the grid accessible with screen readers such that when a cell has focus, the screen reader will read the number value in the middle of each cell.
Originally, I created a GridLayout with a set of button controls to display the number values. This actually worked but I didn't want the buttons to look like buttons. The SWT.FLAT style for button controls doesn't work on Windows operating systems. This is caused by an OS limitation.
Next I then tried converting all buttons to labels but since label controls cant take focus, I couldn't implement any type of tab traversal. Next I tried replacing all labels with read-only text controls. I was able to re-introduce the tab traversal/focusing but I can't get the text to display in the dead-center of each cell. This is actually caused by a SWT limitation. The SWT.CENTER style for text controls only affects the horizontal alignment. Text controls can't be vertically aligned.
So finally, someone told me to wrap each read-only text control in a Composite. This allowed me to center the read-only text controls but I don't know how to make the composite itself to be tab traversed.
Any ideas on how I can get this done or how I can make controls that typically dont take focus (like composite, canvas, label) actually take focus so I can tab traverse each control with my keyboard?
I'm fairly new to java and SWT so I apologize if some of this is confusing. Many thanks. This is how I've constructed each of my cells thus far (I've replaced the read-only text with CLabel controls):
Display display = new Display();
Shell shell = new Shell(display);
GridLayout gridLayout = new GridLayout(5, false);
gridLayout.marginWidth = 0;
gridLayout.marginHeight = 0;
gridLayout.horizontalSpacing = 1;
gridLayout.verticalSpacing = 1;
shell.setLayout(gridLayout);
Composite resetComp = new Composite(shell, SWT.BORDER);
GridData compgridData = new GridData(SWT.CENTER, SWT.CENTER, true, true);
GridData resetGD = new GridData(SWT.FILL, SWT.FILL, false, false);
resetGD.verticalSpan = 2;
resetComp.setLayoutData(resetGD);
resetComp.setLayout(new GridLayout(1, false));
CLabel resetCLabel = new CLabel(resetComp, SWT.SHADOW_OUT | SWT.CENTER);
resetCLabel.setText("Reset"); //$NON-NLS-1$
resetCLabel.setLayoutData(compgridData);
resetCLabel.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_RED)); //$NON-NLS-1$
resetComp.setToolTipText(resetCLabel.getText());
Here is a trick, maybe it will suits you: create each button inside a Composite, and set the size of the Button bigger than its parent Composite; This way, the border of button is not visible, because outside of its parent composite.
private static final int GRID_SIZE = 5;
private static final int CELL_SIZE = 40;
private static final int PADDING = 3;
public static void main (String [] args) {
Display display = new Display ();
Shell shell = new Shell (display);
shell.setLayout(new GridLayout(GRID_SIZE, true));
for (int i = 0; i < GRID_SIZE * GRID_SIZE; i++) {
createButton(shell, i+1);
}
shell.pack ();
shell.open ();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
}
private static void createButton(Shell shell, final int number) {
Composite c = new Composite(shell, SWT.NONE);
c.setLayoutData(new GridData(CELL_SIZE, CELL_SIZE));
Button button = new Button(c, SWT.NONE);
button.setText(Integer.toString(number));
button.setBounds(-PADDING, -PADDING, CELL_SIZE + 2 * PADDING, CELL_SIZE + 2 * PADDING);
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
System.err.println("click on " + number);
}
});
}
It fulfills your requirement: focus, centered. The result may be more or less nice depending on the Windows version (try to change the padding, or add a border to the Composite, it may look nicer).