Java SWT Resize Tripple SashForm constant middle smoothly - java

I implemented a Java SWT SashForm with 3 panes:
SashForm oSash = new SashForm(cmptParent, SWT.NONE);
GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 3;
oSash.setLayout(gridLayout);
oSash.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
Composite oPaneLeft = new Composite(oSash, SWT.NONE);
...
Composite oPaneMiddle = new Composite(oSash, SWT.NONE);
...
Composite oPaneRight = new Composite(oSash, SWT.NONE);
The idea is to have a fixed size middle partition. Setting up initial widths is simple.
I want to be be able to resize the form by dragging the middle. The user clicks on the middle and drags left or right, thereby keeping the middle pane fixed, just sliding left or right. I am able to implement this functionality as follows:
private static Boolean sisResizeSashMiddle = false;
private static int siPosSashMiddleOffset = 0;
...
cmptPaneMiddle = new Composite(cmptParent, SWT.NONE);
cmptPaneMiddle.addMouseListener(new MouseAdapter()
{
#Override
public void mouseDown(MouseEvent arg0)
{
// The user wishes to resize the sash.
AppMain.sisResizeSashMiddle = true;
AppMain.siPosSashMiddleOffset = arg0.x - AppMain.siPosSashMiddleStart;
}
#Override
public void mouseUp(MouseEvent arg0)
{
// The user finished resizing the sash.
AppMain.sisResizeSashMiddle = false;
}
});
cmptPaneMiddle.addMouseMoveListener(new MouseMoveListener()
{
public void mouseMove(MouseEvent arg0)
{
// Only resize the sashes if user hold down the mouse while dragging.
if (true == AppMain.sisResizeSashMiddle)
{
// Compute the width of each sash.
int icxShell = shell.getSize().x;
int icxLeft = arg0.x - AppMain.siPosSashMiddleOffset;
int icxMiddle = AppMain.BrowserSash_Pane_Middle_Width;
int icxRight = shell.getSize().x - icxLeft - icxMiddle;
// Compute the weights.
int iWeightLeft = 10000 * icxLeft / icxShell;
int iWeightMiddle = 10000 * icxMiddle / icxShell;
int iWeightRight = 10000 * icxRight / icxShell;
// Set the weights.
int[] weights = new int[] {iWeightLeft, iWeightMiddle, iWeightRight};
oSash.setWeights(weights);
}
}
});
My issue is that sliding implementation is jerky and jittery, definitely not smooth. Is there a better way to get the same effect, just smooth with no jerky behavior?

Try using the SWT.SMOOTH flag on the SashForm:
SashForm oSash = new SashForm(cmptParent, SWT.SMOOTH);

Related

How to configure this GridLayout correctly?

I'm sadly far from being an expert in SWT and RCP, but I really tried my best here... I can't figure out how to configure the widgets to get this layout (just a Photoshopped screen, never worked this way):
This is what I get if I set the column number of the GridLayout to 2:
Here is the Refresh and the Blacklist button in the wrong row, but at least everything is visible...
And this is what I get if I set the column number of the GridLayout to 3:
This is total messed up... Most of the widgets are pushed outside the visible area. DatePicker, Refresh, Whitelist and the Calculate buttons are not visible, they are somewhere outside on the right.
This is the codepart for this screen area:
resultingProductsGroup = new Group(propProdGroup, SWT.NONE);
final GridData gd_resultingProductsGroup = new GridData(SWT.FILL,
SWT.CENTER, true, false);
gd_resultingProductsGroup.widthHint = 240;
resultingProductsGroup.setLayoutData(gd_resultingProductsGroup);
resultingProductsGroup.setText("Resulting products");
final GridLayout gridLayout_4 = new GridLayout();
gridLayout_4.numColumns = 2;
resultingProductsGroup.setLayout(gridLayout_4);
Label refDateLabel = new Label(resultingProductsGroup, SWT.NONE);
refDateLabel.setText("Reference date:");
refDateInput = new DateInput(resultingProductsGroup, SWT.BORDER);
refDateInput.setLayoutData(new GridData());
refDateInput.setValue(new Date());
calculateProductsButton1 = new Button(resultingProductsGroup, SWT.NONE);
setupImageButton(calculateProductsButton1, Images.getButtonRefresh());
calculateProductsButton1.setLayoutData(new GridData());
GridDataFactory.swtDefaults().hint(18, 18).applyTo(
calculateProductsButton1);
resultingProductsTable = new TableListWidget<Product>(
resultingProductsGroup, SWT.BORDER, ListWidgetMode.MULTI);
resultingProductsTable.setLinesVisible(true);
resultingProductsTable.setHeaderVisible(true);
final GridData rpTableProperty = new GridData(SWT.FILL, SWT.FILL, true,
true, 3, 1);
resultingProductsTable.setLayoutData(rpTableProperty);
GridDataFactory.swtDefaults().hint(230, 240).applyTo(
resultingProductsTable);
setupResultingProductsTableColumns();
resultingProductsTable.sortByComparator(new Comparator<Product>() {
#Override
public int compare(Product o1, Product o2) {
return o1.getPartNum().getExternalId().compareTo(
o2.getPartNum().getExternalId());
}
});
resultingProductsTable.addOpenListener(new IOpenListener() {
#Override
public void open(OpenEvent event) {
doResultingProductsTableOpen();
}
});
calculateProductsButton2 = new Button(resultingProductsGroup, SWT.NONE);
calculateProductsButton2.setText("Calculate");
whitelistAddButton = new Button(resultingProductsGroup, SWT.NONE);
whitelistAddButton.setText("Whitelist");
whitelistAddButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
doAddToWhitelist();
}
});
blacklistAddButton = new Button(resultingProductsGroup, SWT.NONE);
blacklistAddButton.setText("Blacklist");
blacklistAddButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(final SelectionEvent e) {
doAddToBlacklist();
}
});
What am I not seeing here? I'm stuck with this GUI bug for over 2 days now... Please, help me :)
You could design the whole composite with one GridLayout and 3 columns, while using horizontal span of 3 on the table. That doesn't give you the desired mocked up screen though, because reference date controls and buttons at the bottom would be aligned in columns.
Try instead using 3 composites
reference date: row layout
table: fill layout
button list: row layout

How to get contents to show up inside a ScrolledComposite

I am creating a legend view and inside the shell is supposed to have a rectangle followed by a label describing the color. I was able to get the view to work using just a normal composite but the legend continues beyond the screen and no way of see it without making the window larger. I am trying to use a scrolledComposite view for my shell but when I execute the program, nothing appears.
public void createPartControl(Composite parent)
{
display = parent.getDisplay();
parent.setLayout(new FillLayout());
sc = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL);
LegendView.composite = new Composite(sc, SWT.NONE);
RowLayout layout = new RowLayout();
layout.wrap = true;
layout.spacing = 5;
composite.setLayout(layout);
}
public static void addRectangle(String legendMessage)
{
final String propId = legendMessage;
final String[] s = propId.split(",");
if (display != null)
{
display.syncExec(new Runnable()
{
#Override
public void run()
{
// Creating the color using the RBG values
final Color color =
new Color(display, Integer.parseInt(s[0]), Integer.parseInt(s[1]), Integer.parseInt(s[2]));
// Creating a canvas for which the rectangle can be drawn on
Canvas canvas = new Canvas(composite, SWT.NONE);
// Maybe set the bounds of the canvas
canvas.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent e)
{
e.gc.drawRectangle(1, 1, 50, 60);
e.gc.setBackground(color);
e.gc.fillRectangle(2, 2, 49, 59);
}
});
// Disposing the color after it has been used
canvas.addDisposeListener(new DisposeListener()
{
public void widgetDisposed(DisposeEvent e)
{
color.dispose();
}
});
// Creating a label and setting the font
Label label = new Label(composite, SWT.NULL);
Font boldFont = new Font( label.getDisplay(), new FontData( "Arial", 12, SWT.BOLD ) );
label.setFont( boldFont );
label.setText(s[3]);
composite.redraw();
composite.layout(true);
sc.setContent(composite);
}
});
}
}
I am calling add rectangle in a different class. I am fairly new at using SWT and after looking at examples and reading the docs for scrolled Composite, this is what I interpreted it as. Any help would be very appreciated.
You haven't told the ScrolledComposite how to manage the size. You must either call setSize or setMinSize. For this you probably want:
sc.setExpandHorizontal(true);
sc.setExpandVertical(true);
sc.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));

Frame inside custom view

I have implemented a custom view in my Eclipse plugin project, where I want to display different graphs, which are selected by the user. I have no problem with creating a custom view, using org.eclipse.swt.graphics.GC and drawing the required parts but I would like to implement the following:
Inside the custom view I want to have some fixed area on the bounds of the view, where I can display the coordinate system (x- and y-axis with the corresponding labeling), which is fixed. Between these bounds I would like to display the graph, which is changing dynamically, depending on user selection.
So what I need is a custom view, that is built like the following:
Inside the grey area on the left and on the bottom I want to have the coordinate system axes (shown red) and inside the white area I want to draw the graph.
How do I create such an area inside my view? It should just be a filed, without any translations or scales, just a independend area, like a view inside a view...
#Override
public void init(IViewSite site) throws PartInitException {
super.init(site);
}
#Override
public void createPartControl(Composite parent) {
canvas = new Canvas(parent, SWT.NONE);
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
drawCoordinateSystem(e);
drawGraph(e);
});
public void drawCoordinateSystem(PaintEvent e) {
// 1. create area inside view
// 2. draw coordinate system
}
public void drawGraph() {
// 3. draw graph
}
I know how to solve point 2 and 3. But I don't know, how to create such an area inside my view.
I would appreciate any help!
I would suggest that you add multiple controls and handle drawing for different cases in a different way.
For example, instead of having just one monolithic Canvas that draws everything from graph to coordinates, to helpful labels. Add a bunch of label controls on top for showing coordinates, add a parent, or labels for coordinate systems etc.
Your createPartControl should look something like below:
Composite topBar = new Composite(parent, SWT.None);
topBar.setLayout(new GridLayout(3, false));
Label title = new Label(topBar, SWT.NONE);
title.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
Label x = new Label(topBar, SWT.NONE);
Label y = new Label(topBar, SWT.NONE);
Composite graphArea = new Composite(parent, SWT.NONE);
graphArea.setLayout(new GridLayout(2, false));
Canvas xAxis = new Canvas(graphArea, SWT.NONE);
GridData gd = new GridData(GridData.CENTER, GridData.FILL, false, true);
gd.widthHint = 10;
xAxis.setLayoutData(gd);
xAxis.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
drawXAxis();
}
});
Canvas graph = new Canvas(graphArea, SWT.NONE);
graph.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
drawGraph(e);
}
});
Label emptySpace = new Label(graphArea, SWT.NONE);
Canvas yAxis = new Canvas(graphArea, SWT.NONE);
GridData gd = new GridData(GridData.FILL, GridData.CENTER, true, false);
gd.heightHint = 10;
xAxis.setLayoutData(gd);
yAxis.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
drawYAxis();
}
});
You should draw everything in Your paintListener, if Your graph changes just redraw area of graph for example:
Rectangle rect = getGraphBoundries(); //you must implement this method
canvas.redraw(rect.x, rect.y, rect.width, rect.height, true);
this will redraw graph area. To avoid unnecessary computing of axes area in in paintListener paintEvent's gc has area that need to be redrawn called clipping. You can write condition like this:
public void paintControl(PaintEvent e) {
...
if(drawGraph(e.gc.getClipping().intersects(getGraphBoundries())) {
drawGraph(e);
}
...
}

SWT Table per-pixel scrolling

SWT Table has void setTopIndex(int index) and int getTopIndex().
I really need setTopPixel(int pixel) or setTopIndexFractional(double index).
I tried putting a Table into a ScrolledComposite, as such:
public class PixelTable extends ScrolledComposite {
private final Table table;
private final double itemHeight;
public PixelTable(Composite parent) {
super(parent, SWT.V_SCROLL | SWT.BORDER);
// setup the ScrolledComposite
table = new Table(this, SWT.VIRTUAL);
this.setExpandHorizontal(true);
this.setContent(table);
itemHeight = table.getItemHeight();
// setup the Table
table.setLinesVisible(true);
table.addListener(SWT.SetData, new Listener() {
#Override
public void handleEvent(Event e) {
int row = e.index;
TableItem item = (TableItem) e.item;
item.setText(Integer.toString(row));
}
});
}
/** Returns the fractional top index. */
public double getTopIndex() {
return getOrigin().y / itemHeight;
}
/** Sets the fractional top index. */
public void setTopIndex(double top) {
this.setOrigin(0, (int) Math.round(top * itemHeight));
}
/** Sets the item count. */
public void setItemCount(int count) {
table.setItemCount(count);
Point size = table.computeSize(SWT.DEFAULT, SWT.DEFAULT);
table.setSize(size);
}
}
This works for while, but once the inner Table's size gets bigger than ~65,000 pixels (~2,500 rows), the Table shows its scroll bar as well (probably an unsigned short somewhere on the native side). Additionally, it will be pretty tricky to get Table headers to work with this approach, since they'll scroll away.
Does anybody know what the issues would be (or how to get started) to add a per-pixel interface to the SWT API? I'm willing to branch the SWT source if necessary. I only care about the latest APIs for Win / OS X / Linux (e.g. I don't care if I have to break compatibility with old stuff).
If you want per-pixel scrolling, then just do the scrolling yourself. All you need to do is listen for SWT.MouseWheel, set Event#doit to false and then set the selection of the ScrollBar according to the scroll direction (increase/decrease by 1 (<-- that's the one pixel)).
Here is an example:
public static void main(String[] args)
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout());
final Table table = new Table(shell, SWT.V_SCROLL);
for (int i = 0; i < 100; i++)
new TableItem(table, SWT.NONE).setText("Item: " + i);
table.addListener(SWT.MouseWheel, new Listener()
{
#Override
public void handleEvent(Event e)
{
int increment = table.getVerticalBar().getSelection();
if (e.count < 0)
increment++;
else if (e.count > 0)
increment--;
table.getVerticalBar().setSelection(increment);
e.doit = false;
}
});
shell.pack();
shell.setSize(400, 200);
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}

Jface: custom FieldEditor bad layout

I'd like to create a custom FieldEditor for a preference page. the aim is to override ScaleFieldEditor to provide a Scale with two labels over it (one to display the min value, the other to display the max).
It made one. It is working but the layout is not good when I add a FileFieldeditor to preference page.
It's even worst if I add the FileFieldEditor immediately after the custom ScaleFieldEditor:
http://imageshack.us/g/844/customscalelayoutok.png/
(Sorry, I cannot add images to this post).
I made a Composite which contains the 2 Labels and the Scale. I used a GridLayout:
public class ScaleWithLabelFieldEditor extends ScaleFieldEditor {
/**
* The maximum value label
*/
private Label maxLabel;
/**
* The minimum value label
*/
private Label minLabel;
/**
* A composite that contains the scale and the min & max values label
*/
private Composite controls;
public ScaleWithLabelFieldEditor(String name, String labelText,
Composite parent) {
super(name, labelText, parent);
}
public ScaleWithLabelFieldEditor(String name, String labelText,
Composite parent, int min, int max, int increment, int pageIncrement) {
super(name, labelText, parent, min, max, increment, pageIncrement);
}
#Override
protected void doFillIntoGrid(Composite parent, int numColumns) {
Control labelControl = getLabelControl(parent);
GridData gd = new GridData();
labelControl.setLayoutData(gd);
controls = getControls(parent, 2);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = numColumns -1;
gd.grabExcessHorizontalSpace = true;
controls.setLayoutData(gd);
updateControls();
parent.layout();
}
/**
* Initialize (if not done yet) the controls composite
*
* #param parent
* the parent composite
* #return the controls composite that contains the scaler and the min/max
* labels
*/
protected Composite getControls(Composite parent, int numColumns) {
if (controls == null) {
controls = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(numColumns, false);
layout.numColumns = numColumns;
controls.setLayout(layout);
// Initialize the min value label
minLabel = getMinLabel(controls);
minLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
// Initialize the max value label
maxLabel = getMaxLabel(controls);
maxLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
// Initialize the scale
scale = getScale(controls);
scale.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false, numColumns, 1));
}
return controls;
}
/**
* Nothing to do, already handle with controls composite
*/
#Override
protected void adjustForNumColumns(int numColumns) {
// Nothing to do, already handle with controls composite
}
/**
* Update the scale and the labels above
*/
protected void updateControls() {
if (controls != null && !controls.isDisposed()) {
// Update scale
scale.setMinimum(getMinimum());
scale.setMaximum(getMaximum());
scale.setIncrement(getIncrement());
scale.setPageIncrement(getPageIncrement());
// Update labels
maxLabel.setText(Integer.toString(getMaximum()));
minLabel.setText(Integer.toString(getMinimum()));
}
}
What I should do to make this field layout work? Did I miss something in GridLayout/GridData use?
The problem seems to be, that you did not implement the adjustForNumColumns(int numColumns) method. When you add the FileFieldEditor the number of columns changes from 2 to 3. And your field editor must adapt to that which it currently does not.
It seems like the horizontalSpan is not spanning until the end? So, may be you should try to remove -1 in gd.horizontalSpan = numColumns -1;

Categories

Resources