How to prevent vanishing of shapes in SWT Scrollable Composite - swt

Im trying to create a little Telnet Client for a MUD. In this program i want to have a scrollable map. I already made this and it works pretty good. But as soon as i reach the borders it deletes the rectangles (painted with GC) outside the window. If i go back to them, the shapes are not there anymore.
Little Gif to show the problem:
https://gifyu.com/image/vhnq
Im scrolling with the the ScrolledComposite.setOrigin(Point p) function inside an async Runnable.
Canvas declaration + parents (room is an int with value 10):
Composite container = new Composite(mapShell, SWT.FILL);
container.setLayout(new GridLayout(2, false));
scrolledComposite = new ScrolledComposite(container, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
scrolledComposite.setVisible(true);
scrolledComposite.setAlwaysShowScrollBars(false);
scrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 1, 4));
int width = 10000, height = 10000;
Canvas mapCanvas = new Canvas(scrolledComposite, SWT.NONE);
mapCanvas.setBackground(mapShell.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
mapCanvas.setSize(width, height);
mapCanvas.setLocation(0, 0);
final ScrollBar hBar = scrolledComposite.getHorizontalBar();
final ScrollBar vBar = scrolledComposite.getVerticalBar();
hBar.setIncrement(room * 2);
vBar.setIncrement(room * 2);
gc = new GC(mapCanvas);
mapCanvas.setLayout(null);
scrolledComposite.setContent(mapCanvas);
scrolledComposite.setMinSize(new Point(300, 400));
Function to draw the rooms:
public void changeCurrentRoom(Room newRoom) {
mapShell.getDisplay().asyncExec(new Runnable() {
#Override
public void run() {
gc.setBackground(currentRoom.getColor());
gc.fillRectangle(currentRoom.getRectangle());
currentRoom = newRoom;
gc.setBackground(ACTIVE_ROOM_COLOR);
gc.fillRectangle(currentRoom.getRectangle());
}
});
mapShell.getDisplay().asyncExec(new Runnable() {
#Override
public void run() {
scrolledComposite.setOrigin(getScrollPosition(currentRoom));
roomText.setText(currentRoom.getName());
}
});
}
Thanks for your help!

Related

Layout problems with customized FieldEditor (Eclipse Preference Page)

I try to create my own FieldEditor (as I have to fill combobox values dynamically). So my class extends 'FieldEditor'. My preference page needs 3 of these fields which then look like this (2nd,3rd and 4th field-editors; the 'select kernel' ones).
Obviously something goes wrong with the layout. All fields should look like the 3rd field - using the full space.
#Override
protected void adjustForNumColumns(int numColumns) {
((GridData) c_top.getLayoutData()).horizontalSpan = numColumns;
}
#Override
protected void doFillIntoGrid(Composite parent, int numColumns) {
/* Layout comments:
*
* component are sequentially filled into numColumns
* by default each component will use 1 column
* GridData can be set to use more that one columns
*/
GridData gd = new GridData(SWT.FILL, SWT.TOP, true, false);
gd.horizontalSpan = numColumns;
c_top = parent;
c_top.setLayoutData(gd);
c_group = new Composite(c_top, SWT.BORDER);
GridLayout newgd = new GridLayout(2, false);
c_group.setLayout(newgd);
c_group.setLayoutData(gd);
// kernel spec combo
Label comboLabel = new Label(c_group, SWT.NONE);
comboLabel.setText("Select kernel");
gd = new GridData(SWT.LEFT, SWT.TOP, false, false);
gd.horizontalSpan = numColumns - 1;
comboLabel.setLayoutData(gd);
c_kernelCombo = new Combo(c_group, SWT.READ_ONLY);
gd = new GridData(SWT.FILL, SWT.TOP, true, false);
//gd.horizontalSpan = 1;
c_kernelCombo.setLayoutData(gd);
}
I even tried a simpler layout without using a group but then all my field-editors only used 2 cells of the grid (which looks a bit funny with 3 columns given by the other field editors.
I have no idea how to fix it . Can anybody please help?
You are setting the same instance of GridData (gd) on two controls - this is not allowed. You must create a new GridData for each control.
In any case you should not be setting the layout data on the parent Composite - that doesn't belong to your code.
I got a solution but I don't know whether it's correct:
1) I made the mistake to create all FieldEditors of that page with the same parent, though the docs say to retrieve a new parent for each field editor with getFieldEditorParent()
2) I guess, I misunderstood the meaning of adjustForNumColumns(int numColumns). I asume, it should adapt the horizontalSpan of the controls which are affected by a change of the number of columns. Now my code looks like this:
#Override
protected void adjustForNumColumns(int numColumns) {
((GridData) c_kernelCombo.getLayoutData()).horizontalSpan = numColumns-1;
}
#Override
protected void doFillIntoGrid(Composite parent, int numColumns) {
// kernel spec combo
Label comboLabel = new Label(parent, SWT.NONE);
comboLabel.setText("Select kernel");
GridData gd = new GridData(SWT.LEFT, SWT.TOP, false, false);
gd.horizontalSpan = 1;
comboLabel.setLayoutData(gd);
c_kernelCombo = new Combo(parent, SWT.READ_ONLY);
gd = new GridData(SWT.FILL, SWT.TOP, true, false);
gd.horizontalSpan = numColumns - 1;
c_kernelCombo.setLayoutData(gd);
}

SWT - How to change the size of Text box dynamically

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:

Eclipse e4: creating a 3 part window trim without resizing text in tool control

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);

Have a way to set the length of JFace's ComboViewer?

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.

Cannot reduce size of RCP view when migrated to Eclipse 4

I'm currently working on migrating a set of eclipse RCP applications from 3.6 to 4.2.
I'm struggling with an issue with RCP perspectives that view height cannot be reduced below a certain size (looks like 10% from the window height).
The code works fine in eclipse 3.x and user can reduce the view height by dragging the border.
However, in 4.x the height of top most view (button view) can only be reduced upto a certain value.
Can anybody help with this, please?
public class Perspective implements IPerspectiveFactory {
public static final String ID = "im.rcpTest2.fixedperspective";
public void createInitialLayout(IPageLayout layout) {
String editorArea = layout.getEditorArea();
layout.setEditorAreaVisible(false);
layout.addStandaloneView(ButtonView.ID, false, IPageLayout.TOP,
0.1f, editorArea);
layout.addStandaloneView(View.ID, false, IPageLayout.LEFT,
0.25f, editorArea);
IFolderLayout folder = layout.createFolder("messages", IPageLayout.TOP,
0.5f, editorArea);
folder.addPlaceholder(View2.ID + ":*");
folder.addView(View2.ID+":2");
folder.addView(View2.ID+":3");
layout.getViewLayout(ButtonView.ID).setCloseable(false);
layout.getViewLayout(View.ID).setCloseable(false);
}
}
public class ButtonView extends ViewPart {
public ButtonView() {
}
public static final String ID = "im.rcptest2.ButtonView"; //$NON-NLS-1$
private Text text;
/**
* Create contents of the view part.
* #param parent
*/
#Override
public void createPartControl(Composite parent) {
Composite container = new Composite(parent, SWT.NONE);
container.setBackground(SWTResourceManager.getColor(SWT.COLOR_GRAY));
container.setLayout(new GridLayout(2, false));
text = new Text(container, SWT.BORDER);
text.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));
{
Button btnMybutton = new Button(container, SWT.NONE);
btnMybutton.setText("MyButton");
}
}
#Override
public void setFocus() {
// TODO Auto-generated method stub
}
}
This looks like the value
int minSashPercent = 10;
in org.eclipse.e4.ui.workbench.renderers.swt.SashLayout
There does not seem to be a way to change this value. So the only thing you could do would be to write a custom Sash Renderer class by providing your own Renderer Factory.