So the case is that I have a SWT composite A which aggregates composite B and C.
The content of B and C consists of multiple rows that consists of Label and Text.
Within composite B or C rows are aligned properly ( you can draw a straight vertical line in the place where label border ends and text starts). But if you compare B and C then C content looks like it is indented against B.
For example:
Does anyone have an idea how to achieve it ?
The only way I can think of to align the first column of each Composite is to set the GridData#widthHint to the same value. This value would have to be the maximal width of any of the elements in the first column.
I gave it a try and came up with this solution (it's not optimized and consequently might not be the most efficient way to do it):
private static Random random = new Random(System.currentTimeMillis());
public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new GridLayout(1, false));
Composite first = createComposite(shell);
Composite second = createComposite(shell);
synchronizeFirstColumn(2, first, second);
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
private static Composite createComposite(Shell shell)
{
Composite comp = new Composite(shell, SWT.BORDER);
comp.setLayout(new GridLayout(2, false));
comp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
for (int i = 0; i < 3; i++)
{
String content = UUID.randomUUID().toString();
content = content.substring(0, Math.round(random.nextFloat() * content.length()));
Label label = new Label(comp, SWT.RIGHT);
label.setText(content);
label.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
Text text = new Text(comp, SWT.BORDER);
text.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
}
return comp;
}
private static void synchronizeFirstColumn(int nrOfColumns, Composite... comps)
{
if (comps == null || comps.length == 0)
return;
int maxWidth = 0;
for (Composite comp : comps)
{
Control[] controls = comp.getChildren();
for (int i = 0; i < controls.length; i += nrOfColumns)
{
int width = controls[i].computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
if (width > maxWidth)
maxWidth = width;
}
}
for (Composite comp : comps)
{
Control[] controls = comp.getChildren();
for (int i = 0; i < controls.length; i += nrOfColumns)
{
Object data = controls[i].getLayoutData();
if(data instanceof GridData)
{
GridData grid = (GridData) data;
grid.widthHint = maxWidth;
}
}
}
}
Looks like this:
Related
i have a problem with my Java SWT ScrolledComposite:
In a (centered) ScrolledComposite are displayed many pictures previews (see picture images). If the images in the ScrolledComposite are loaded, it takes a long time. After that the previews lags on scolling.
Quick: it has a really poor performance.
So my idea: i calculate the scoll bar and load only the displayed pictures. If the user scoll down, it will be load the other pictures.
My (test) code:
Composite center = new Composite(form, SWT.NONE);
center.setLayout(new FillLayout());
ScrolledComposite centerScrolledComposite = new ScrolledComposite(center, SWT.V_SCROLL | SWT.BORDER);
Display display = getDisplay();
Image image1 = display.getSystemImage(SWT.ICON_WORKING);
Image image2 = display.getSystemImage(SWT.ICON_QUESTION);
Image image3 = display.getSystemImage(SWT.ICON_ERROR);
Composite wrappedScrolledComposite = new Composite(centerScrolledComposite, SWT.NONE);
for (int i = 0; i <= 5000; i++)
{
Label label = new Label(wrappedScrolledComposite, SWT.NONE);
if (i % 3 == 0)
label.setImage(image1);
if (i % 3 == 1)
label.setImage(image2);
if (i % 3 == 2)
label.setImage(image3);
}
RowLayout layout = new RowLayout(SWT.HORIZONTAL);
layout.wrap = true;
wrappedScrolledComposite.setLayout(layout);
centerScrolledComposite.setContent(wrappedScrolledComposite);
centerScrolledComposite.setExpandHorizontal(true);
centerScrolledComposite.setExpandVertical(true);
centerScrolledComposite.addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
Rectangle r = centerScrolledComposite.getClientArea();
centerScrolledComposite.setMinSize(wrappedScrolledComposite.computeSize(r.width, SWT.DEFAULT));
}
});
But.. i don't know if it's possible. Have anybody a similar problem? Thanks
PS: i need a view very simular to the Windows 10 File Browser with "Big Icos" as preview.... and the same performance :)
Replace all those labels with a Table or TableViewer - just a single control.
Since tables can scroll themselves you also don't need the ScrolledComposite.
Table table = new Table(form, SWT.V_SCROLL | SWT.H_SCROLL | SWT.SINGLE);
for (int i = 0; i <= 5000; i++)
{
TableItem label = new TableItem(table, SWT.NONE);
if (i % 3 == 0)
label.setImage(image1);
if (i % 3 == 1)
label.setImage(image2);
if (i % 3 == 2)
label.setImage(image3);
}
For even better performance you can make the table "Virtual" and populate the contents as required:
Table table = new Table(composite, SWT.VIRTUAL | SWT.V_SCROLL | SWT.H_SCROLL | SWT.SINGLE);
table.setItemCount(5000);
table.addListener(SWT.SetData, event -> {
TableItem label = (TableItem)event.item;
int i = table.indexOf(label);
if (i % 3 == 0)
label.setImage(image1);
if (i % 3 == 1)
label.setImage(image2);
if (i % 3 == 2)
label.setImage(image3);
});
I found a custom SWT-Column-Ratio Layout on the internet which puts the children of a composite/control into a user-defined ratio. Unfortunately I cannot find the source of the implementation of the Column-Ratio Layout, but here's how the code looks like:
public class ColumnRatioLayout extends Layout {
int[] percentages;
public ColumnRatioLayout(int... percentages) {
this.percentages = percentages;
}
#Override
protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
Control[] children = composite.getChildren();
int height = hHint;
int width = wHint;
int consumedPercent = 0;
for (int i = 0; i < children.length; i++) {
int percent = 0;
calculatePercentAndConsumedPercent(percent, consumedPercent, children, i);
Point childSize = children[i].computeSize(wHint == -1 ? -1 : wHint * percent / 100, hHint);
if (wHint == SWT.DEFAULT) {
width = Math.max(width, childSize.x * (100 - percent) / 100);
}
if (hHint == SWT.DEFAULT) {
height = Math.max(height, childSize.y);
}
}
return new Point(width, Math.max(height, 0));
}
protected void calculatePercentAndConsumedPercent(int percent, int consumedPercent, Control[] children, int i) {
if (i >= percentages.length) {
percent = (100 - consumedPercent) / (children.length - percentages.length);
} else {
percent = percentages[i];
consumedPercent += percent;
}
}
#Override
protected void layout(Composite composite, boolean flushCache) {
Control[] children = composite.getChildren();
Rectangle available = composite.getClientArea();
int x = available.x;
int consumedPercent = 0;
for (int i = 0; i < children.length - 1; i++) {
int percent;
if (i >= percentages.length) {
percent = (100 - consumedPercent) / (children.length - percentages.length);
} else {
percent = percentages[i];
consumedPercent += percent;
}
int w = available.width * percent / 100;
children[i].setBounds(x, available.y, w, available.height);
x += w;
}
if (children.length > 0) {
children[children.length - 1].setBounds(x, available.y,
available.width - (x - available.x), available.height);
}
}
}
I want to test this layout. I am writing a JUnit test to test if the ratio is true when using this layot. I have done this, but it gives me no useful output - Point {0, 0}:
public class ColumnRatioLayoutTest {
private static Display _display;
private static Shell _shell;
private static Composite _comp;
#BeforeAll
public static void setUpAll() {
_display = new Display();
_shell = new Shell(_display);
_comp = new Composite(_shell, SWT.NONE);
}
#Test
public void setLayoutTest() {
int[] colRatio = {20, 80};
ColumnRatioLayout colLayout = new ColumnRatioLayout(colRatio);
_comp.setLayout(colLayout);
_comp.setSize(_comp.computeSize(SWT.DEFAULT, SWT.DEFAULT));
Composite comp1 = new Composite(_comp, SWT.NONE);
comp1.setLayout(new FillLayout());
comp1.setSize(comp1.computeSize(SWT.DEFAULT, SWT.DEFAULT));
Composite comp2 = new Composite(_comp, SWT.NONE);
comp2.setLayout(new FillLayout());
comp2.setSize(comp2.computeSize(SWT.DEFAULT, SWT.DEFAULT));
System.out.println("Comp1 size: " + _comp.getSize());
}
}
I basically want to compare the size of the two composites and see that one is 4 times the size of the other. This will fulfill my test. How do I do that? Thanks in advance.
You can test the layout like this:
public class ColumnRatioLayoutTest {
private Display display;
private Shell shell;
#BeforeEach
public void setUp() {
display = new Display();
shell = new Shell(display);
}
#AfterEach
public void tearDown() {
display.dispose();
}
#Test
public void testLayout() {
shell.setSize(shell.computeSize(100, SWT.DEFAULT));
Control control20 = new Label(shell, SWT.NONE);
Control control80 = new Label(shell, SWT.NONE);
shell.setLayout(new ColumnRatioLayout(20, 80));
shell.layout();
assertEquals(100, shell.getSize().x);
assertEquals(20, control20.getSize().x);
assertEquals(80, control80.getSize().x);
}
}
The test creates a shell with a client area width of 100 pixels and then ensures that two controls that should occupy 20% and 80% of the width actually are 20 and 80 pixels wide.
There is no need to declare static Display and Shell, re-creating them for each test ensures that tests remain isolated.
BTW, widgets that are managed by a layout must not call setSize or otherwise modify their bounds, i.e. your code must not call comp1.setSize(...);
And, please, follow the Java Naming conventions, don't prefix variables with underscores
I need to print out a grid in a windows and I need button under the grid. So that I can control the action on the grid, but at the moment I don't get the grid printed out only the buttons
// Create and initialize cell
public Cell[][] cell = new Cell[rows][cols];
protected BorderPane getPane() {
HBox paneForButtons = new HBox(20);
//button start
startB.setOnAction(e -> {
if( startB.isPressed() == false){
System.out.println("start");
}
});
//button stop
stopB.setOnAction(e -> {
if( stopB.isPressed() == false){
System.out.println("stop");
}
});
//button left
leftB.setOnAction(e -> text.getTransforms().add(new Rotate(-rotate, text.getX(), text.getY())));
//button right
rightB.setOnAction(e -> text.getTransforms().add(new Rotate(rotate, text.getX(), text.getY())));
//fiel to get the moves
moveFeld.setPromptText("1,2 or 3 steps");
Button absenden = new Button();
absenden.setOnAction(e -> {
ReadInput2();
if( moveFeld.getText() != null && !moveFeld.getText().isEmpty()){
System.out.println("Moves are " + moveFeld.getText().toString());
}
});
absenden.setText("enter");
paneForButtons.getChildren().addAll(startB, stopB, leftB, rightB, moveFeld, absenden);
paneForButtons.setAlignment(Pos.CENTER);
paneForButtons.setStyle("-fx-border-color: green");
BorderPane pane = new BorderPane();
pane.setBottom(paneForButtons);
//pane.setBottom(paneForButtons);
// Pane to hold cell
GridPane pane2 = new GridPane();
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
pane2.add(cell[i][j] = new Cell(), j, i);
pane2.setAlignment(Pos.CENTER);
pane.setCenter(pane2);
return pane;
}
public static class Cell extends Pane {
public Cell() {
setStyle("-fx-border-color: black");
this.setPrefSize(800, 800);
}
}
I'm calling the method getPane in my void so I think there is not problem with that you guys have any idea how I get the grid above my buttons.
Now to part two the grid can be painted however the user wants I putted in 5 for now but in the future it should be mutable
I need to do the following using Java SWT:
Display a list of Pixels as an Image
Allow the user to select a subset of Pixels
Display a Grid over the image as a guide for the user. The Image still needs to handle mouse events
1) and 2) are straightforward, however I don't know how to achieve 3).
Reading up on SWT, I do not see a way to put a Transparent Overlay over an image. Is this possible? Is there another method?
Just draw the grid on top of the Image. Set GG#setAlpha(int) to a low value to make the lines transparent. This will not interfere with mouse events:
public static void main(String[] args)
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("Stackoverflow");
shell.setLayout(new FillLayout());
Image image = new Image(display, "baz.png");
Label label = new Label(shell, SWT.NONE);
label.addListener(SWT.Paint, new Listener()
{
#Override
public void handleEvent(Event event)
{
GC gc = event.gc;
gc.drawImage(image, 0, 0);
gc.setAlpha(30);
int interval = image.getBounds().height;
for (int i = 0; i < 10; i++)
{
int y = (int) Math.floor(i * (interval / 10.0));
gc.drawLine(0, y, image.getBounds().width, y);
}
interval = image.getBounds().width;
for (int i = 0; i < 10; i++)
{
int x = (int) Math.floor(i * (interval / 10.0));
gc.drawLine(x, 0, x, image.getBounds().width);
}
gc.setAlpha(255);
}
});
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
image.dispose();
}
Looks like this:
I am using Eclipse.org's Nebula Grid and want to access an individual cell. Not an individual GridItem, which can be accomplished by grid.select(...) but a cell. So lets say i have a grid like this:
final Grid grid = new Grid(shell,SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
grid.setCellSelectionEnabled(true);
grid.setHeaderVisible(true);
GridColumn column = new GridColumn(grid, SWT.None);
column.setWidth(80);
GridColumn column2 = new GridColumn(grid, SWT.None);
column2.setWidth(80);
for(int i = 0; i<50; i++)
{
GridItem item = new GridItem(grid, SWT.None);
item.setText("Item" + i);
}
Like i said, grid.select selects the whole row, which is not what i want. I also tried grid.selectCell(...), but for some reason that wont work either. The coordinates used are with a high likeliness correct:
Button btn = new Button(shell, SWT.PUSH);
btn.setText("test");
btn.addSelectionListener(new SelectionAdapter(){
public void widgetSelected(SelectionEvent e){
Point pt = new Point(400,300);
grid.selectCell(pt);
}
});
Any Ideas?
For a Grid, the Point co-ordinates represent the intersecting column and the row item. i.e, x co-ordinate represents the index of the column and y co-ord is the row item index.
Button btn = new Button (shell, SWT.PUSH);
btn.setText ("test");
btn.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
// Here the x co-ordinate of the Point represents the column
// index and y co-ordinate stands for the row index.
// i.e, x = indexOf(focusColumn); and y = indexOf(focusItem);
Point focusCell = grid.getFocusCell();
grid.selectCell(focusCell);
// eg., selects the intersecting cell of the first column(index = 0)
// in the second row item(rowindex = 1).
Point pt = new Point(0, 1);
grid.selectCell(pt);
}
});