I have an application that displays a ScrolledComposite. Users are complaining that the horizontal scrolling increment is too fine, i.e. each click on the horizontal scroll arrow currently moves the bar one pixel at a time. They want individual clicks to cause greater horizontal movement. Could someone explain how I could implement this? A snippet of the code follows:
ScrolledComposite myScrolledComposite = new ScrolledComposite(parent,
SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
if ( myScrolledComposite == null) {
throw new NullPointerException("ScenePreView.java: " +
"Method createPartControl() " +
"ScrolledComposite myScrolledComposite == null.");
}
Composite myComposite = new Composite(myScrolledComposite, SWT.NONE);
if ( myComposite == null) {
throw new NullPointerException("ScenePreView.java: " +
"Method createPartControl() " +
"Composite myComposite == null.");
}
myScrolledComposite.setContent(myComposite);
This should work pretty well and provide usable defaults. It should update automatically when the control inside the ScrolledComposite is resized.
myComposite.addControlListener( new ControlAdapter() {
#Override
public void controlResized( ControlEvent e ) {
ScrollBar sbX = scrolledComposite.getHorizontalBar();
if ( sbX != null ) {
sbX.setPageIncrement( sbX.getThumb() );
sbX.setIncrement( Math.max( 1, sbX.getThumb() / 5 ) );
}
}
});
Get the scrollbar from the composite and set it's increment.
myScrolledComposite.getVerticalBar().setIncrement(10);
Use the setIncrement() method of the SWT Scrollbar class. This lets you modify the amount by which the scroll region moves when the arrow buttons are pressed.
See API Reference for SWT
I know it's more than you asked for, but I highly recommend checking out the SWT animation toolkit which has an implementation of smooth scrolling. It will make your application way cooler.
You can check it out and see the sources - it's a good example (yet, a bit advanced) of how to play with the scrolling.
Related
We have a case where we need to fire a server call to fetch next 100 records as soon as the user scrolls down to see the last element in a scroll bar. Please share any pointers.
The ScrollBar fires a SelectionEvent when it is changed. By listening to this event and comparing the scrollbar position + thumb size with the maximum size you should be able to tell when it is scrolled to its end.
final ScrollBar scrollBar = scrolledComposite.getHorizontalBar();
scrollBar.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent event ) {
if( scrollBar.getSelection() + scrollbar.getThumb() == scrollBar.getMaximum() ) {
// spawn thread to fetch further data
}
}
} );
You likely want to refine the condition so that new data is fetched before the end of the scrollbar is reached, e.g.
if( scrollBar.getSelection() + scrollbar.getThumb() > scrollBar.getMaximum() - scrolledComposite.getClientArea().y ) {
...
}
I need to calculate the minimum or default size of a Composite where it can display all components without clipping.
I only seem to find methods to calculate the preferred size of the Composite. This means that a Table or other scrolled composite will have a preferred size which displays the full contents without scrolling. The ScrolledComposite will immediately go into scroll mode, which is not what I want.
GridLayout manages to do this by treating the GridData hints as minimum width/height, allowing grabbing any extra space available.
The problem is related to this one: SWT - computingSize for Multi-line textfield inside ScrolledComposite
Control#computeSize(int, int) should be what you are searching for:
Point size = comp.computeSize(SWT.DEFAULT, SWT.DEFAULT);
System.out.println(size.x + " " + size.y);
I've managed to find the solution.
The key was two different things:
Make sure to set the resize listener on both the content (if CHILDREN are added and layout() is called) and the ScrolledComposite (if it is resized from outside its children)
Make sure to set both GridData.grab and GridData.hint. The hint will make sure the composite assumes this size when you do computeSize(), while grab makes sure it will grab any extra space that is available.
Code sample is below:
public static void main (String [] args) {
Display display = new Display ();
Shell shell = new Shell(display);
ScrolledComposite sc = new ScrolledComposite(shell, SWT.NONE);
Composite foo = new Composite(sc, SWT.NONE);
foo.setLayout(new GridLayout(1, false));
StyledText text = new StyledText(foo, SWT.NONE);
text.setText("Ipsum dolor etc... \n etc... \n etc....");
GridDataFactory.fillDefaults().grab(true, true).hint(40, 40).applyTo(text);
Listener l = new Listener() {
public void handleEvent(Event e) {
Point size = sc.getSize();
Point cUnrestrainedSize = content.computeSize(SWT.DEFAULT, SWT.DEFAULT);
if(size.y >= cUnrestrainedSize.y && size.x >= cUnrestrainedSize.x) {
content.setSize(size);
return;
}
// does not fit
Rectangle hostRect = getBounds();
int border = getBorderWidth();
hostRect.width -= 2*border;
hostRect.width -= getVerticalBar().getSize().x;
hostRect.height -= 2*border;
hostRect.height -= getHorizontalBar().getSize().y;
c.setSize(
Math.max(cUnrestrainedSize.x, hostRect.width),
Math.max(cUnrestrainedSize.y, hostRect.height)
);
}
}
sc.addListener(SWT.Resize, l);
foo.addListener(SWT.Resize, l);
shell.open ();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
}
I would like to customize JTableHeader so it would offer serval actions (for example 2 buttons which one of them would sort column and second show properties of this column etc). Unfortunately it is not possible to set CellEditor for JTableHeader so i'm stuck with using mouse adapter. But maybe it is possible to dispatch event from this particular JTableHeader component so it will show up a popup menu which will contains all options i desire and it would dispatch event if option other than sorting would be chosen. This way standard JTable sorting operation will be available, along with my operations and it will maintain a decent visual apperance. So my question is - Is it possible and how it should be done.
In response to trashgod comment - i understand that you mean to treat defaultheader as an ordinary component and just use "add" function to add Components. It doesnt work well with JTableHeader. After reading trashgod example i wrote this:
private class mouseList extends MouseAdapter {
#Override
public void mouseClicked(MouseEvent e) {
TableColumnModel thisColumnModel = thisTable.getColumnModel();
int xCor = e.getX();
//int Cols = thisColumnModel.getColumnCount();
int thisColNum = thisColumnModel.getColumnIndexAtX(xCor);
int prevWidth=0;
for(int i = 0 ;i<thisColNum;i++)
{
prevWidth+=thisColumnModel.getColumn(i).getWidth();
}
int width = xCor-prevWidth;
/////////////////////////////////////////////////////////////////////////////////////
customHeader thisHeader = (customHeader)((JTableHeader)e.getSource()).getDefaultRenderer();
System.out.println(thisHeader.mainB.getText() + " text of thisHeader");
//////////////////////////////////////////////////
test thisTest = new test(null,false,thisHeader);
thisTest.setVisible(true);
///////////////////////////////////////////////////////////////
//System.out.println(width + " width of the header");
Object thisComp = thisHeader.getComponentAt(width, e.getY());
System.out.println(thisComp + "\n" + width + " + " + e.getY() +"\n" + thisHeader.getMainButton().getText());
((JTableHeader)e.getSource()).repaint();
if(thisComp instanceof JButton)
{
//System.out.println("sdfdsf");
String name = ((JButton)thisComp).getName();
if(name.equals("mainB"))
{
System.out.println("its working on main");
((JButton)thisComp).doClick(1000);
}else{
System.out.println("its working on menu");
((JButton)thisComp).doClick(1000);
}
}
((JTableHeader)e.getSource()).repaint();
}
}
MouseListener is applied to JTableHeader. HeaderRender is an extension of JPanel that contains 2 JButtons. Strange thing happens in line
Object thisComp = thisHeader.getComponentAt(width, e.getY());
When i left lines
test thisTest = new test(null,false,thisHeader);
thisTest.setVisible(true);
(This dialog shows selected component)
uncommented, function "getComponentAt" seems to work allmost fine (allmost because it never goes for else condition even when mouse is targeting second button, and it does not repaint clicked buttons[Strangely its repainting buttons in test dialog window]),otherwise it allways returns null object.
I dont know if it is important but i set Header renderer globally by invoking "setDefaultRenderer" on JTableHeader.
Im pretty much running out of ideas so i would appreciate any help.
This example shows the basic infrastructure, while this answer offers several important caveats regarding usability. This example shows how to change the RowFilter dynamically, but changing the RowSorter is similar. Both examples use JToggleButton to manage two states, but a JComboBox could be used to select from among more alternatives.
To disable vertical scroll bar i used the following syntax
table.getHorizontalBar().setEnabled(false);
But it is not working. It is ruining my application ui. How can i disable it?
Use option SWT.NO_SCROLL and SWT.V_SCROLL while constructing the table as following:
new Table (shell, SWT.NO_SCROLL | SWT.V_SCROLL);
You can't prevent the Table from showing its scrollbars if it wants to. However, if you give the table the space it requires, it should not have to display any scrollbars.
Note:
You can simply use SWT.NO_SCROLL in the constructor but if you want to update it later it won't be possible.
ScrollBar / Table position synchronization in Java SWT turorial
Probably, if you you want to disable a scrollbar, it means you want to synchronize the content with something else. Here is example how to do it with two tables, where content of main table called tableExcel is mirrored in extra table called tableRow (please, be aware the code may not be perfect, because I am beginner):
*Note: the code is not complete & shows only key things (beginners, please use Window Builder and then edit/add code):
1) As ankur.trapasiya mentioned, do this:
tableRow = new Table(sashFormExcel, SWT.BORDER | SWT.VIRTUAL | SWT.NO_SCROLL);
2) And (SWT.VIRTUAL will be required to do the workaround, and to load tables fast, it will load what you see & where you scroll)
tableExcel = new Table(sashFormExcel, SWT.BORDER | SWT.VIRTUAL);
3) Because I used sash-form for better navigation, insert this above point 1:
SashForm sashFormExcel = new SashForm(sashForm_Main, SWT.NONE);
4) Then implement this (after point 3):
synchronizer synchronize = new synchronizer(tableRow, tableExcel); tableExcel.getVerticalBar().addSelectionListener(synchronize);
5) Add this class (will synchronize the tables content position):
class synchronizer implements SelectionListener
{
Table t1, t2;
public synchronizer(Table tableRow, Table tableMain)
{
t1 = tableRow;
t2 = tableMain;
}
#Override
public void widgetSelected(SelectionEvent e) {
t1.setTopIndex(t2.getTopIndex());
}
#Override
public void widgetDefaultSelected(SelectionEvent e) {
// TODO Auto-generated method stub
}
}
6) And after point 2, add this (it will make to load main table fast, and will also synchronize your table where scroll bar is disabled):
tableExcel.addListener( SWT.SetData, new Listener() {
public void handleEvent( Event event ) {
TableItem item = (TableItem) event.item;
int index = event.index;
int page = index / PAGE_SIZE;
int start = page * PAGE_SIZE;
int end = start + PAGE_SIZE;
end = Math.min (end, virtTableExcel.size());
for (int i = start; i < end; i++) {
item = tableExcel.getItem (i);
item.setText (virtTableExcel.get(i));
tableRow.getItem(i).setText(Integer.toString(i));
}
}
});
And on top of code, add this:
private static Table tableExcel;
ArrayList<String[]> virtTableExcel = new ArrayList<String[]>();
final int PAGE_SIZE = 64;
private Table tableRow;
As it is mentioned in point 7, you take data from array list virtTableExcel, but to trigger point 6, use this (somewhere in code, after you generated virtTableExcel with data), where rowMax is integer which is equal to virtTableExcel.size(); :tableExcel.setItemCount(rowMax);
tableRow.setItemCount(rowMax);
Please, don't blame me for code, I used it from my application. But, all these bits might be useful for other beginners.
What work for me:
When declaring the TableViewer I do this:
this.viewer.getTable().getHorizontalBar().setVisible(false);
this.viewer.getTable().pack();
this.viewer.getTable().getParent().layout();
this.viewer.getTable().getParent().getParent().layout();
and when i am changing the viewer input i also call the three last lines.
I got this solution from: https://bugs.eclipse.org/bugs/show_bug.cgi?id=304128
Try
table.getHorizontalBar().setVisible(false);
Is't simple:
leftTable.getVerticalBar().addListener(SWT.Selection, event -> {
rightTableViewer.getTable().setTopIndex(leftTableViewer.getTable().getTopIndex());
});
and vice versa.
I want to draw a top border on a Composite with such code :
final Composite c = new Composite(parent, SWT.NONE);
c.setLayout(new FormLayout());
c.addPaintListener(new PaintListener(){
#Override
public void paintControl(PaintEvent e) {
int x = c.getBounds().x;
int y = c.getBounds().y;
e.gc.setForeground(SWTResourceManager.getColor(0));
e.gc.drawLine(x, y-23, x + c.getBounds().width, y-23);
}
});
but how can I make the border has same look & feel as the default borders? and how can I get the right Y coordinate of the composite ?
I want the composite only has a top border, is there any other way to do so ?
Check Detect system settings snippet, which shows, how could you get system colors.
In your case
Color borderColor = display.getSystemColor(SWT.COLOR_WIDGET_BORDER);
1)
You could use 3 Composites for this.
1 Composite in which the other 2 are placed.
Like:
MainComposite
TopComposite (Which is the border and very small)
CenterComposite (In Which your information is placed)
2)
You could use a LayoutData for the inner Composite, with spacing informations. But than you would see the Parent Composite at the top and the bottom.
Take a look at
GridData.verticalIndent
GridData.heightHint
This is a non-trivial issue :-)
Have a look at UIForms in Eclipse - especially org.eclipse.ui.forms.widgets.FormToolkit.BorderPainter...