I'm trying to dispose of columns and add new ones to a Nebula Grid, the data in the table won't change I just want to be able to change the columns used.
I am getting a bug where the Grid is throwing index out of bounds exceptions as it's iterating through a list of existing columns but using a value "endColumnIndex" to stop the loop, but the endColumnIndex value is bigger than the list of new columns.
I believe this is due to using Visual Range Support, and the value for the current on screen columns is not being updated as I am removing them.
I have written a class to reproduce this bug here, and am hoping someone has a workaround for this issue:
import org.eclipse.nebula.jface.gridviewer.GridTableViewer;
import org.eclipse.nebula.jface.gridviewer.GridViewerColumn;
import org.eclipse.nebula.widgets.grid.GridColumn;
import org.eclipse.nebula.widgets.grid.GridItem;
import org.eclipse.nebula.widgets.grid.GridVisibleRangeSupport;
import org.eclipse.nebula.widgets.grid.GridVisibleRangeSupport.RangeChangedEvent;
import org.eclipse.nebula.widgets.grid.GridVisibleRangeSupport.VisibleRangeChangedListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class GridRangeChangeBug {
public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
shell.setSize(800, 800);
shell.setLayout(new GridLayout(1, true));
Button go = new Button(shell, SWT.PUSH);
go.setText("Reproduce Bug");
final GridTableViewer viewer = new GridTableViewer(shell, SWT.H_SCROLL
| SWT.V_SCROLL | SWT.BORDER);
viewer.getGrid().setLayoutData(
new GridData(SWT.FILL, SWT.FILL, true, true));
viewer.getGrid().setHeaderVisible(true);
GridVisibleRangeSupport rangeSupport = GridVisibleRangeSupport.createFor(viewer.getGrid());
rangeSupport.addRangeChangeListener(new VisibleRangeChangedListener() {
#Override
public void rangeChanged(RangeChangedEvent event) {
}
});
for (int i = 0; i < 100; i++) {
GridViewerColumn col = new GridViewerColumn(viewer, SWT.NONE);
col.getColumn().setWidth(30);
col.getColumn().setText("" + i);
}
go.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
for (GridColumn c : viewer.getGrid().getColumns()) {
c.dispose();
}
for (int i = 0; i < 10; i++) {
GridViewerColumn col = new GridViewerColumn(viewer,
SWT.NONE);
col.getColumn().setWidth(30);
col.getColumn().setText("" + i);
}
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
Related
I have been working on fixing a bug where adding around 2500 items to an SWT List was causing layouts to break, I believe this is a bug with the rendering in SWT because there was very little to go wrong, but when you scrolled down the list using a scrolled composite, at some point the next item in the composite would render over the list and the scroll would just stop (at around 2100) and items from the list just disappear. you can see this effect yourself if you comment out lines near 151 or my code.
However i have realised that if I add a height hint to the layout data of the List it will add it's own Scroll Bar and this will fix the rendering issue, but introduces a new issue, which is that I can't get the List to Greedily occupy the horizontal space, so that the scroll bar is on the right of the panel, Does anyone know of a way to get the List to stretch in this way?
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.Widget;
public class FilterLayoutDialog extends Dialog {
private ListDisplayer keyWordListDisplay;
private ScrolledComposite scroll;
private Composite parent;
public FilterLayoutDialog(final Shell parentShell) {
super(parentShell);
}
#Override
protected void configureShell(final Shell shell) {
super.configureShell(shell);
shell.setSize(new Point(450, 550));
shell.setText("FML"); //$NON-NLS-1$
}
#Override
public Control createDialogArea(final Composite comp) {
scroll = new ScrolledComposite(comp, SWT.V_SCROLL);
parent = new Composite(scroll, SWT.NONE);
parent.setLayout(new GridLayout(1, true));
scroll.setContent(parent);
scroll.setExpandHorizontal(true);
scroll.setExpandVertical(true);
scroll.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
final ToolBar keywordBar = new ToolBar(parent, SWT.RIGHT | SWT.FLAT);
ToolItem addText = new ToolItem(keywordBar, SWT.RIGHT | SWT.FLAT);
addText.setToolTipText("Add 3000");
addText.setText("Add 3000");
addText.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
keyWordListDisplay
.setContent(IntStream.range(0, 3000).mapToObj(i -> i + "").collect(Collectors.toList()));
parent.layout();
setScrollSize();
}
});
addText = new ToolItem(keywordBar, SWT.RIGHT | SWT.FLAT);
addText.setToolTipText("Add 12");
addText.setText("Add 12");
addText.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
keyWordListDisplay
.setContent(IntStream.range(0, 12).mapToObj(i -> i + "").collect(Collectors.toList()));
parent.layout();
setScrollSize();
}
});
final ToolItem reset = new ToolItem(keywordBar, SWT.RIGHT | SWT.FLAT);
reset.setToolTipText("Reset");
reset.setText("Reset");
reset.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
keyWordListDisplay.setEmpty();
parent.layout();
setScrollSize();
}
});
final GridData barData = new GridData(SWT.LEFT, SWT.CENTER, true, false);
keywordBar.setLayoutData(barData);
Label sep = new Label(parent, SWT.HORIZONTAL | SWT.SEPARATOR);
sep.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).span(1, 1).create());
final Composite keywordList = new Composite(parent, SWT.NONE);
keywordList.setLayout(new GridLayout(1, true));
keyWordListDisplay = new ListDisplayer(keywordList, "None Selected");
sep = new Label(parent, SWT.HORIZONTAL | SWT.SEPARATOR);
sep.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).span(1, 1).create());
setScrollSize();
return scroll;
}
public static void main(final String[] args) {
new Display();
final FilterLayoutDialog fml = new FilterLayoutDialog(new Shell());
fml.open();
}
private void setScrollSize() {
scroll.setMinSize(parent.computeSize(SWT.DEFAULT, SWT.DEFAULT));
}
private class ListDisplayer {
String emptyIndicator;
Composite parent;
Widget w;
public ListDisplayer(final Composite parent, final String emptyIndicator) {
this.parent = parent;
this.emptyIndicator = emptyIndicator;
setEmpty();
}
void setContent(final Collection<String> content) {
disposeWidget();
Composite fill = new Composite(parent, SWT.NONE);
fill.setLayout(new FillLayout());
final GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
// Comment this out
if (content.size() > 20) {
GC gc = new GC(parent);
gd.heightHint = gc.getFontMetrics().getHeight() * 20;
}
// End of comment
fill.setLayoutData(gd);
final org.eclipse.swt.widgets.List box = new org.eclipse.swt.widgets.List(fill, SWT.V_SCROLL | SWT.SINGLE);
box.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
box.setSelection(new int[] {});
}
});
for (final String row : content) {
box.add(row);
}
w = fill;
}
void setEmpty() {
disposeWidget();
final Label a = new Label(parent, SWT.NONE | SWT.WRAP);
a.setText(emptyIndicator);
w = a;
}
void disposeWidget() {
if (w != null) {
w.dispose();
}
}
}
}
You haven't set layout data on the keywordList Composite, so it is being layed out as small as possible.
keywordList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
works.
Note: It often helps to specify SWT.BORDER as the style for Composites when debugging the layout so you can see the space they are occupying (o set the background colour).
I would like to draw a String with Path and center it inside a Rectangle.
The problem is that I don't know how to evaluate the size/bounds of the path.
I have tried to use the corresponding size of the the same String drawn in a normal way (gc.drawString...) and after using gc.textExtent(String), but apparently the two size are different so the result is not ok....
Do you have any idea how to evaluate the size of the path in order to draw it centered in a rectangle?
The problem is that drawing a string with path is bigger that drawing a string in the normal way. You can verify it with this simple code.
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
public class ShapeText
{
static Path path=null;
public static void main(String[] args)
{
final Display display = new Display();
Font font = new Font(display, "Times", 50, SWT.BOLD);
final Color blue = display.getSystemColor(SWT.COLOR_BLUE);
final Color red = display.getSystemColor(SWT.COLOR_RED);
try {
} catch (SWTException e) {
System.out.println(e.getMessage());
display.dispose();
return;
}
Shell shell = new Shell(display);
shell.addListener(SWT.Paint, new Listener()
{
public void handleEvent(Event e)
{
path = new Path(display);
e.gc.setFont(font);
path.addString("Path is different", 0, 0, font);
GC gc = e.gc;
gc.setAntialias(SWT.ON);
gc.setTextAntialias(SWT.ON);
gc.setForeground(blue);
gc.setBackground(blue);
//gc.fillPath(path);
gc.drawPath(path);
gc.setForeground(red);
gc.drawString("Path is different", 0, 0,true);
}
});
shell.setSize(530,120);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
path.dispose();
font.dispose();
display.dispose();
}
}
This is the result:
As you can see the String drawn with Path (in blue) is longer than the other (in red)...
At present all my Java GUI applications have SWT.SWT as their window class. I would like for some of them to be linked as sub-windows in menu applications such as Cairo-Dock. This is the third column of the out put from wmctrl -lx.
I have tried using the Display.setAppName() method in an attempt to set this name. Neither Display.setAppName or display.SetAppname will change the app class from SWT.SWT to the class name I'm tring to set.
When I use the lower case display.setAppName it produces this warning in the Eclipse IDE:
Description Resource Path Location Type
The static method setAppName(String) from the type Display should be accessed in a static way WBTest.java /javaTools/src/javaTools line 31 Java Problem
Code Sample:
package javaTools;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.wb.swt.SWTResourceManager;
public class WBTest {
private Table table;
/**
* Launch the application.
* #param args
*/
public static void main(String[] args) {
try {
WBTest window = new WBTest();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Open the window.
*/
public void open() {
Display display = Display.getDefault();
display.setAppName("myapplication");
Shell shell = new Shell();
shell.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
shell.setSize(560, 426);
shell.setText("SWT Application");
table = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
table.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLUE));
// table.setBounds(49, 21, 241, 158);
table.setHeaderVisible(true);
table.setLinesVisible(true);
TableItem row = new TableItem(table, SWT.NONE);
row.setText("This is a test.");
shell.open();
// shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
My research shows how to do this in Python, which works:
#!/usr/bin/python
from gi.repository import Gtk
win = Gtk.Window()
win.connect("delete-event", Gtk.main_quit)
win.set_wmclass ("Hello World", "Hello World")
win.set_title ("Hello World")
win.show_all()
Gtk.main()
I'm trying to do the same thing with SWT/Java.
Is there something else I need to add to this function to make it work, or is there a differernt function that is specific to setting the application's class name?
I don't know whether to remove this question or provide the answer. I had worked on it since yesterday and was still trying lots of variations.
One finally works. Apparently, the line has to appear in the code before declaring the Display.
This works:
package javaTools;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.wb.swt.SWTResourceManager;
public class WBTest {
private Table table;
/**
* Launch the application.
* #param args
*/
public static void main(String[] args) {
try {
WBTest window = new WBTest();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Open the window.
*/
public void open() {
Display.setAppName("myapplication");
Display display = Display.getDefault();
Display.setAppName("myapplication");
Shell shell = new Shell();
shell.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
shell.setSize(560, 426);
shell.setText("SWT Application");
table = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);
table.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLUE));
// table.setBounds(49, 21, 241, 158);
table.setHeaderVisible(true);
table.setLinesVisible(true);
TableItem row = new TableItem(table, SWT.NONE);
row.setText("This is a test.");
shell.open();
// shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
For my plugin, I try to get the active Eclipse dialog with these lines:
String shellTitle = Display.getCurrent().getActiveShell().getTitle();
System.out.println("Opened dialog: " + shellTitle);
If e.g. I open the search dialog, these lines print me
Opened dialog: Search
in my console. But I would also want to print the keyword in the search field, for example
Opened dialog: Search (with the search word 'ChatSession')
I have read the API reference and there, I just can found the getTitle() and some other methods for getting bounds and so on.
Is my idea realizable? And if not, is it realizable with these so-called extension points? I have never used them but heard of them.
Mistakes in your question:
You are calling getTitle() method on Shell array object. It is wrong.
You are mixing dialog and Shell
Assuming you are talking about Shell. You can use the below code to get the controls on active Shell.
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class ShellControlsGetting {
public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
Button button = new Button(shell, SWT.PUSH);
button.setText("Open 3 Shells");
final Shell[] shells = new Shell[3];
button.addSelectionListener(new SelectionListener() {
#Override
public void widgetSelected(SelectionEvent e) {
for (int i = 0; i < 3; i++) {
shells[i] = new Shell(shell);
shells[i].setText("Shell" + (i + 1));
shells[i].setLayout(new FillLayout());
shells[i].setSize(250, 50);
shells[i].setLocation(100, 200 + (i + 1) * 100);
Label label = new Label(shells[i], SWT.LEFT);
label.setText("Search Box" + (i + 1));
Text search = new Text(shells[i], SWT.SINGLE | SWT.BORDER);
search.setText("search key" + (i + 1));
shells[i].open();
}
Shell currentActiveShell = Display.getCurrent().getActiveShell();
String shellTitle = currentActiveShell.getText();
Control[] children = currentActiveShell.getChildren();
for (int i = 0; i < children.length; i++) {
Control child = children[i];
if (child instanceof Text) {
System.out.println("Opened dialog: " + shellTitle + "(with the search word '" + ((Text)child).getText()
+ "')");
}
}
}
#Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
If this not answers you question then edit your post add some code and clarify what exactly you are expecting.
So I have a problem, when I add an image to any column of a JFace table the first column also behaves like it has an image in and the text is indented by the size of that image.
Here's a screenshot illustrating my point with the code needed to produce it. Is there anyway to stop this from happening because it's really getting on my wick?
Regards,
Glen x
package widgets;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.StyledCellLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class ComponentTest {
private static Image image;
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, true));
TableViewer viewer1 = getViewer(shell, true);
TableViewer viewer2 = getViewer(shell, false);
List<String> rows = new ArrayList<String>();
rows.add("Row 1");
rows.add("Row 2");
viewer1.setInput(rows);
viewer2.setInput(rows);
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private static TableViewer getViewer(final Shell shell, boolean addImage) {
TableViewer viewer = new TableViewer(shell, SWT.FULL_SELECTION
| SWT.H_SCROLL | SWT.V_SCROLL | SWT.NONE);
viewer.setContentProvider(ArrayContentProvider.getInstance());
viewer.getTable().setLayoutData(
new GridData(SWT.FILL, SWT.FILL, true, true));
TableViewerColumn col = new TableViewerColumn(viewer, SWT.NONE);
col.getColumn().setWidth(100);
col.getColumn().setText("Text Column");
col.setLabelProvider(new StyledCellLabelProvider() {
#Override
public void update(ViewerCell cell) {
cell.setText((String) cell.getElement());
}
});
col = new TableViewerColumn(viewer, SWT.NONE);
col.getColumn().setWidth(100);
col.getColumn().setText("Second Text Column");
col.setLabelProvider(new StyledCellLabelProvider() {
#Override
public void update(ViewerCell cell) {
cell.setText((String) cell.getElement());
}
});
if (addImage) {
col = new TableViewerColumn(viewer, SWT.NONE);
col.getColumn().setWidth(100);
col.getColumn().setText("Image Column");
col.setLabelProvider(new StyledCellLabelProvider() {
#Override
public void update(ViewerCell cell) {
cell.setImage(getImage(shell.getDisplay()));
}
});
}
viewer.getTable().setHeaderVisible(true);
return viewer;
}
// make a little green square
private static Image getImage(Display display) {
if (image == null) {
PaletteData palette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
ImageData imageData = new ImageData(16, 16, 24, palette);
for (int x = 0; x < 16; x++) {
for (int y = 0; y < 16; y++) {
imageData.setPixel(x, y, 0xFF00);
}
}
;
image = new Image(display, imageData);
}
return image;
}
}
That is a quite annoying bug when using Windows. You can use a dirty fix by skipping the first column (not using it) and setting its width to zero.
As far as I remember correctly, this will introduce some minor glitches when using MacOS.
I had the same problem and worked around it by using a StyledCellLabelProvider with owner draw and overriding the paint method to paint the image. The point is that you should not set the image of the viewer cell because this will give the bug. I posted example code to the Eclipse bug report.
TableItem line:301: I see a problem with SWT code here.
if (code == 0) return new RECT ();
if (!getImage) {
RECT iconRect = new RECT ();
iconRect.left = OS.LVIR_ICON;
parent.ignoreCustomDraw = true;
code = OS.SendMessage (hwnd, OS. LVM_GETITEMRECT, row, iconRect);
parent.ignoreCustomDraw = false;
if (code != 0) rect.left = iconRect.right;
//****problem
code = OS.SendMessage (hwnd, OS. LVM_GETITEMRECT, row, iconRect);
for the first table viewer with image, here code is 1 that why drawing text started iconRect right coordinate.
for the second table viwer with no image, code is zero. so it always starts from the actual bounds.
If you are really keen on fix it at CellStyleStyledCellLabelProvider i would suggest you to override paint method there.