programmatically scroll ScrolledComposite TableViewer item - swt

I have a dialog with large table viewer that lays on ScrolledComposite.
I need programmatically scroll ScrolledComposite to select item from TableViewer.
Looks like a easy task but I really got stack.
I tried number of thinks and non of them are working.
There is my sample code:
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
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.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableItem;
/**
* Scroll a Viewer 99th element
*
*/
public class Snippet008RevealElement {
public class MyModel {
public int counter;
public MyModel(int counter) {
this.counter = counter;
}
#Override
public String toString() {
return "Item " + this.counter;
}
}
public Snippet008RevealElement(Shell shell) {
ScrolledComposite scrolledComposite = new ScrolledComposite(shell, SWT.V_SCROLL | SWT.H_SCROLL);
GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
scrolledComposite.setLayoutData(data);
scrolledComposite.setExpandHorizontal(true);
scrolledComposite.setExpandVertical(true);
Composite main = new Composite(scrolledComposite, SWT.NONE);
main.setLayout(new GridLayout());
main.setLayoutData(new GridData(GridData.FILL_BOTH));
final TableViewer v = new TableViewer(main);
v.setLabelProvider(new LabelProvider());
v.setContentProvider(ArrayContentProvider.getInstance());
MyModel[] model = createModel();
v.setInput(model);
v.getTable().setLinesVisible(true);
// v.reveal(model[99]);
// v.getTable().setSelection(99);
TableItem[] items = v.getTable().getItems();
TableItem item = items[99];
scrolledComposite.getVerticalBar().setSelection(item.getBounds().y);
scrolledComposite.setContent(main);
scrolledComposite.setMinSize(main.computeSize(SWT.DEFAULT, SWT.DEFAULT));
}
private MyModel[] createModel() {
MyModel[] elements = new MyModel[100];
for( int i = 0; i < 100; i++ ) {
elements[i] = new MyModel(i);
}
return elements;
}
/**
* #param args
*/
public static void main(String[] args) {
Display display = new Display ();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
new Snippet008RevealElement(shell);
shell.open ();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
}
}
the real challenge or a bug is to find real bounds for TableItem item = items[99]; that not visible on composite.

You can use the setOrigin method of ScrolledComposite for this using something like:
scrolledComposite.setContent(main);
scrolledComposite.setMinSize(main.computeSize(SWT.DEFAULT, SWT.DEFAULT));
// Need to run the calculations after all size calculations have been done
// So do asynchronously.
final Display display = scrolledComposite.getDisplay();
display.asyncExec(() ->
{
final Table table = v.getTable();
final TableItem item = table.getItem(99);
Rectangle itemBounds = item.getBounds();
// Convert to be relative to scrolled composite
itemBounds = display.map(viewer.getTable(), scrolledComposite, itemBounds);
scrolledComposite.setOrigin(0, itemBounds.y);
});
Note: The bounds calculations are not accurate if you call this code during the initialization of the controls so I have shown it being done asynchronously here. The asyncExec is not needed if you run the code from a Button or something like that.

Related

How to bind SWT objects to the center of the application window?

I am using SWT to create an application GUI, and I don't really need to resize the components, but it does bother me that when the window is maximized, the components stay left-aligned. Is there a way to fix this with SWT or do I need to utilize a different set of GUI tools?
Thanks in advance. I am using SWT 4.8 for this application.
EDIT: Images
Small: https://imgur.com/CPbAlaZ
Maximized: https://imgur.com/4d6YXcl
Provided images are a basic application using the following code
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
public class TestWindow {
protected Shell shlSwtApplicationExample;
private Text text;
/**
* Launch the application.
* #param args
*/
public static void main(String[] args) {
try {
TestWindow window = new TestWindow();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Open the window.
*/
public void open() {
Display display = Display.getDefault();
createContents();
shlSwtApplicationExample.open();
shlSwtApplicationExample.layout();
while (!shlSwtApplicationExample.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
/**
* Create contents of the window.
*/
protected void createContents() {
shlSwtApplicationExample = new Shell();
shlSwtApplicationExample.setSize(705, 529);
shlSwtApplicationExample.setText("SWT Application Example");
Composite composite = new Composite(shlSwtApplicationExample, SWT.NONE);
composite.setBounds(10, 10, 669, 465);
text = new Text(composite, SWT.BORDER);
text.setBounds(22, 10, 334, 295);
Button btnNewButton = new Button(composite, SWT.NONE);
btnNewButton.setBounds(49, 384, 137, 26);
btnNewButton.setText("New Button");
Button button = new Button(composite, SWT.NONE);
button.setText("New Button");
button.setBounds(300, 384, 137, 26);
}
}
I would not recommend using setBounds since it does not resize the components when you resize the application. Use Layouts, like for example below I have used GridLayout for both the Shell and the Composite which will properly arrange the UI when resize happens.
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
public class TestWindow {
protected Shell shlSwtApplicationExample;
private Text text;
/**
* Launch the application.
* #param args
*/
public static void main(String[] args) {
try {
TestWindow window = new TestWindow();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Open the window.
*/
public void open() {
Display display = Display.getDefault();
createContents(display);
shlSwtApplicationExample.open();
shlSwtApplicationExample.layout();
shlSwtApplicationExample.setLayout(new GridLayout(1, false));
while (!shlSwtApplicationExample.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
/**
* Create contents of the window.
* #param display
*/
protected void createContents(Display display) {
shlSwtApplicationExample = new Shell(display);
shlSwtApplicationExample.setLayout(new GridLayout(1, false));
Composite txtcomposite = new Composite(shlSwtApplicationExample, SWT.NONE);
txtcomposite.setLayout(new GridLayout(1, false));
txtcomposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
Composite btncomposite = new Composite(shlSwtApplicationExample, SWT.NONE);
btncomposite.setLayout(new GridLayout(2, false));
btncomposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
text = new Text(txtcomposite, SWT.BORDER);
text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
Button btnNewButton = new Button(btncomposite, SWT.NONE);
btnNewButton.setText("New Button");
Button button = new Button(btncomposite, SWT.NONE);
button.setText("New Button");
shlSwtApplicationExample.setText("SWT Application Example");
//shlSwtApplicationExample.setSize(705, 529);
}
}
Since you are using setBounds you will need to add a Control listener to the shell to be told about resize and move events. You will then have to recalculate the positions on each resize event.
shlSwtApplicationExample.addControlListener(
new ControlListener() {
#Override
public void controlMoved(ControlEvent event) {
// No action
}
#Override
public void controlResized(ControlEvent event) {
Rectangle rect = shlSwtApplicationExample.getClientArea();
// TODO Call new `setBounds` on each control based on the
// client area size
}
});
This might be a good time to learn about using Layouts instead of setBounds (see here). Layouts will automatically deal with resizes.

SmartGWT - can't click into items into windows modal

I have one problem using Window with setIsModal(true).
I have this code:
#Override
public void onModuleLoad() {
Button tester = new Button("Tester");
tester.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
#Override
public void onClick(ClickEvent event) {
final com.smartgwt.client.widgets.Window win = new com.smartgwt.client.widgets.Window();
win.setTitle("Ventana Tester");
win.setWidth(900);
win.setHeight(600);
win.setIsModal(true);
win.setShowModalMask(true);
win.centerInPage();
win.setMinimized(false);
win.addCloseClickHandler(new CloseClickHandler() {
#Override
public void onCloseClick(CloseClientEvent event) {
win.destroy();
}
});
PlanBoard pb = new PlanBoard();
win.addItem(pb);
win.show();
}
});
vlPrincipal.addMember(tester);
RootPanel.get("main").add(vlPrincipal);
}
and this is PlanBoard class:
public class PlanBoard extends VLayout{
private CaptionPanel contentDetallePlan = new CaptionPanel("DETALLES DEL PLAN");
private CaptionPanel contentAtributosPlan = new CaptionPanel("ATRIBUTOS DE PLAN");
private CaptionPanel contentSeccionesPlan = new CaptionPanel("SECCIONES");
public PlanBoard(){
contentDetallePlan.setStyleName("estiloCaptionPanel");
contentAtributosPlan.setStyleName("estiloCaptionPanel");
addMember(contentDetallePlan);
addMember(contentAtributosPlan);
addMember(contentSeccionesPlan);
preparaDetallePlan();
preparaAtributosPlan();
}
private void preparaDetallePlan(){
VLayout contenedorSeccion = new VLayout();
FlexTable table1 = new FlexTable();
FlexTable table2 = new FlexTable();
FlexTable table3 = new FlexTable();
Label np = new Label("Nombre de Plan:");
Label npText = new Label("Plan B");
Label tc = new Label("Tipo de Carta:");
DynamicForm tcForm = new DynamicForm();
ComboBoxItem tcBox = new ComboBoxItem();
tcBox.setWidth(250);
tcBox.setShowTitle(false);
tcForm.setItems(tcBox);
Label pr = new Label("Periodo:");
DynamicForm prForm = new DynamicForm();
ComboBoxItem prBox = new ComboBoxItem();
prBox.setWidth(150);
prBox.setShowTitle(false);
prForm.setItems(prBox);
Label dp = new Label("Descripcion:");
DynamicForm dpForm = new DynamicForm();
TextAreaItem dpText = new TextAreaItem();
dpText.setShowTitle(false);
dpText.setWidth(600);
dpForm.setItems(dpText);
table1.setWidget(0, 0, np);
table1.setWidget(0, 1, npText);
table2.setWidget(0, 0, tc);
table2.setWidget(0, 1, tcForm);
table2.setWidget(0, 2, pr);
table2.setWidget(0, 3, prForm);
table3.setWidget(0, 1, dp);
table3.setWidget(1, 1, dpForm);
contenedorSeccion.addMember(table1);
contenedorSeccion.addMember(table2);
contenedorSeccion.addMember(table3);
contentDetallePlan.add(contenedorSeccion);
}
private void preparaAtributosPlan(){
VLayout contenedorSeccion = new VLayout();
FlexTable table1 = new FlexTable();
Label fe = new Label("Firma Electornica:");
CheckboxItem feCheck = new CheckboxItem();
DateItem feFechaIni = new DateItem();
DateItem feFechaFin = new DateItem();
feFechaIni.setUseTextField(true);
feCheck.setShowTitle(false);
DynamicForm feForm = new DynamicForm();
feForm.setItems(feCheck,feFechaIni,feFechaFin);
table1.setWidget(0, 0, fe);
table1.setWidget(0, 1, feForm);
contenedorSeccion.addMember(table1);
contentAtributosPlan.add(contenedorSeccion);
}
The problem is when I try to click on CheckBoxItem or DateItem, I can't edit them, but when I don't use setIsModal(true), it works fine.
I don't know how to set the Window to modal(true), and have those items working on that window.
Here is your code cleaned (a little bit) and improved so that what you want to achieve (which is the modal window with selectable/actionable controls):
PlanBoard.java
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.CheckboxItem;
import com.smartgwt.client.widgets.form.fields.ComboBoxItem;
import com.smartgwt.client.widgets.form.fields.DateItem;
import com.smartgwt.client.widgets.form.fields.StaticTextItem;
import com.smartgwt.client.widgets.form.fields.TextAreaItem;
import com.smartgwt.client.widgets.layout.VLayout;
public class PlanBoard extends VLayout {
public PlanBoard(){
preparaDetallePlan();
preparaAtributosPlan();
preparaSecciones();
}
private void preparaDetallePlan(){
StaticTextItem np = new StaticTextItem("id2", "Nombre de Plan:");
StaticTextItem npText = new StaticTextItem("id2", "Plan B");
ComboBoxItem tcBox = new ComboBoxItem();
tcBox.setTitle("Tipo de Carta");
tcBox.setWidth(250);
ComboBoxItem prBox = new ComboBoxItem();
tcBox.setTitle("Periodo");
prBox.setWidth(150);
StaticTextItem dp = new StaticTextItem("id3", "Descripcion:");
TextAreaItem dpText = new TextAreaItem();
dpText.setShowTitle(false);
dpText.setWidth(600);
dpText.setStartRow(true);
dpText.setEndRow(true);
dpText.setColSpan(2);
DynamicForm form = new DynamicForm();
form.setItems(np, npText, tcBox, prBox, dp, dpText);
form.setIsGroup(true);
form.setGroupTitle("DETALLES DE PLAN");
addMember(form);
}
private void preparaAtributosPlan(){
StaticTextItem fe = new StaticTextItem("id4", "Firma Electornica:");
CheckboxItem feCheck = new CheckboxItem();
feCheck.setShowTitle(false);
DateItem feFechaIni = new DateItem();
DateItem feFechaFin = new DateItem();
feFechaIni.setUseTextField(true);
DynamicForm form = new DynamicForm();
form.setItems(fe, feCheck, feFechaIni, feFechaFin);
form.setIsGroup(true);
form.setGroupTitle("ATRIBUTOS DE PLAN");
addMember(form);
}
private void preparaSecciones(){
DynamicForm form = new DynamicForm();
form.setIsGroup(true);
form.setGroupTitle("SECCIONES");
addMember(form);
}
}
TestCases.java (rename to your EntryPoint class name, which you don't specify):
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.events.CloseClickEvent;
import com.smartgwt.client.widgets.events.CloseClickHandler;
import com.smartgwt.client.widgets.layout.VLayout;
import com.google.gwt.core.client.EntryPoint;
public class TestCases implements EntryPoint {
public void onModuleLoad() {
IButton tester = new IButton("Tester");
tester.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
final Window win = new Window();
win.setTitle("Ventana Tester");
win.setWidth(900);
win.setHeight(600);
win.setIsModal(true);
win.setShowModalMask(true);
win.centerInPage();
win.setMinimized(false);
win.addCloseClickHandler(new CloseClickHandler() {
#Override
public void onCloseClick(CloseClickEvent event) {
win.destroy();
}
});
PlanBoard pb = new PlanBoard();
win.addItem(pb);
win.show();
}
});
VLayout vlPrincipal = new VLayout();
vlPrincipal.addMember(tester);
vlPrincipal.draw();
}
}
Some notes:
Don't mix GWT and SmartGWT widgets unless absolutely necessary and only when you really know what you are doing (because it will generated unexpected results, as the one you are experiencing). In your case, the mixing is unnecessary!!
You can add the titles to the different controls you are using, and they will display as labels. You can specify if the title label appears above or to one side, per control.
Take a look at this SmartGWT demo to learn how to configure and use the different types of DynamicForm controls. Many of the things you were trying to do, you were doing more difficult than necessary.
On the "stylistic" aspect, don't write your code using Spanglish. I speak Spanish, so I understand, but it limits a lot the feedback you get, because your code is so much more difficult to understand. Use English (at least for code you intend to post in SO).

Android ActionBar error

package mavilla.paavaiinstitutions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.ActionBar;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
public class MainActivity extends Activity {
int mPosition = -1;
String mTitle = "";
// Array of strings storing country names
String[] mCountries ;
// Array of integers points to images stored in /res/drawable-ldpi/
int[] mFlags = new int[]{
R.drawable.home,
R.drawable.about,
R.drawable.ins,
R.drawable.campus,
R.drawable.compass,
R.drawable.gallery,
R.drawable.cap,
R.drawable.alumini,
R.drawable.tieup,
R.drawable.contact
};
// Array of strings to initial counts
String[] mCount = new String[]{
"", "", "", "", "",
"", "", "", "", "" };
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
private LinearLayout mDrawer ;
private List<HashMap<String,String>> mList ;
private SimpleAdapter mAdapter;
final private String COUNTRY = "country";
final private String FLAG = "flag";
final private String COUNT = "count";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Getting an array of country names
mCountries = getResources().getStringArray(R.array.countries);
// Title of the activity
mTitle = (String)getTitle();
// Getting a reference to the drawer listview
mDrawerList = (ListView) findViewById(R.id.drawer_list);
// Getting a reference to the sidebar drawer ( Title + ListView )
mDrawer = ( LinearLayout) findViewById(R.id.drawer);
// Each row in the list stores country name, count and flag
mList = new ArrayList<HashMap<String,String>>();
for(int i=0;i<10;i++){
HashMap<String, String> hm = new HashMap<String,String>();
hm.put(COUNTRY, mCountries[i]);
hm.put(COUNT, mCount[i]);
hm.put(FLAG, Integer.toString(mFlags[i]) );
mList.add(hm);
}
// Keys used in Hashmap
String[] from = { FLAG,COUNTRY,COUNT };
// Ids of views in listview_layout
int[] to = { R.id.flag , R.id.country , R.id.count};
// Instantiating an adapter to store each items
// R.layout.drawer_layout defines the layout of each item
mAdapter = new SimpleAdapter(this, mList, R.layout.drawer_layout, from, to);
// Getting reference to DrawerLayout
mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
// Creating a ToggleButton for NavigationDrawer with drawer event listener
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer , R.string.drawer_open,R.string.drawer_close){
/** Called when drawer is closed */
public void onDrawerClosed(View view) {
highlightSelectedCountry();
supportInvalidateOptionsMenu();
}
/** Called when a drawer is opened */
public void onDrawerOpened(View drawerView) {
getSupportActionBar().setTitle("Select a Country");
supportInvalidateOptionsMenu();
}
};
// Setting event listener for the drawer
mDrawerLayout.setDrawerListener(mDrawerToggle);
// ItemClick event handler for the drawer items
mDrawerList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3) {
// Increment hit count of the drawer list item
incrementHitCount(position);
if(position < 5) { // Show fragment for countries : 0 to 4
showFragment(position);
}else{ // Show message box for countries : 5 to 9
Toast.makeText(getApplicationContext(), mCountries[position], Toast.LENGTH_LONG).show();
}
// Closing the drawer
mDrawerLayout.closeDrawer(mDrawer);
}
});
// Enabling Up navigation
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
// Setting the adapter to the listView
mDrawerList.setAdapter(mAdapter);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
public void incrementHitCount(int position){
HashMap<String, String> item = mList.get(position);
String count = item.get(COUNT);
item.remove(COUNT);
if(count.equals("")){
count = " 1 ";
}else{
int cnt = Integer.parseInt(count.trim());
cnt ++;
count = " " + cnt + " ";
}
item.put(COUNT, count);
mAdapter.notifyDataSetChanged();
}
public void showFragment(int position){
//Currently selected country
mTitle = mCountries[position];
// Creating a fragment object
CountryFragment cFragment = new CountryFragment();
// Creating a Bundle object
Bundle data = new Bundle();
// Setting the index of the currently selected item of mDrawerList
data.putInt("position", position);
// Setting the position to the fragment
cFragment.setArguments(data);
// Getting reference to the FragmentManager
FragmentManager fragmentManager = getSupportFragmentManager();
// Creating a fragment transaction
FragmentTransaction ft = fragmentManager.beginTransaction();
// Adding a fragment to the fragment transaction
ft.replace(R.id.content_frame, cFragment);
// Committing the transaction
ft.commit();
}
// Highlight the selected country : 0 to 4
public void highlightSelectedCountry(){
int selectedItem = mDrawerList.getCheckedItemPosition();
if(selectedItem > 4)
mDrawerList.setItemChecked(mPosition, true);
else
mPosition = selectedItem;
if(mPosition!=-1)
getSupportActionBar().setTitle(mCountries[mPosition]);
}
}
i have extended Main Activity from Activity as shown to apply custom theme.
But I'm getting error below in actionBar code:
getSupportActionBar()
// Enabling Up navigation
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
Please help me as i am very new in stackoverflow and android..thanks in advance.
You are no longer using the support ActionBarActivity, but the normal Android Activity.
Thats why instead of
getSupportActionBar() you have to call getActionBar()
supportInvalidateOptionsMenu() you have to call invalidateOptionsMenu()
getSupportFragmentManager() you have to call getFragmentManager()
and so on..

ExpandBar in Eclipse View Part

I am trying to add an expand bar to an Eclipse viewpart. When I click the expand button I would like the viewpart to move items below the expand bar down and show the expanded items. What currently happens is the expand bar items just disappear below the items below the expand bar. Any thoughts?
final ExpandBar expandBar = new ExpandBar(parent, SWT.NONE);
expandBar.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_LIGHT_SHADOW));
expandBar.setSpacing(0);
fd_toolBar.top = new FormAttachment(expandBar, 6);
FormData fd_expandBar = new FormData();
fd_expandBar.top = new FormAttachment(0, 62);
fd_expandBar.left = new FormAttachment(0, 3);
expandBar.setLayoutData(fd_expandBar);
formToolkit.paintBordersFor(expandBar);
final ExpandItem xpndtmWarningDetails = new ExpandItem(expandBar, SWT.NONE);
xpndtmWarningDetails.setExpanded(true);
xpndtmWarningDetails.setText("Warning Details");
final Composite composite_1 = new Composite(expandBar, SWT.NONE);
composite_1.setBackground(SWTResourceManager.getColor(SWT.COLOR_YELLOW));
xpndtmWarningDetails.setControl(composite_1);
formToolkit.paintBordersFor(composite_1);
xpndtmWarningDetails.setHeight(xpndtmWarningDetails.getControl().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
Label lblTest = new Label(composite_1, SWT.NONE);
lblTest.setBounds(10, 10, 55, 15);
lblTest.setText("Test");
expandBar.addExpandListener(new ExpandListener(){
#Override
public void itemCollapsed(ExpandEvent e) {
expandBar.setSize(expandBar.getSize().x, xpndtmWarningDetails.getHeaderHeight());
parent.layout(true);
}
#Override
public void itemExpanded(ExpandEvent e) {
expandBar.setSize(expandBar.getSize().x, 300);
expandBar.layout(true);
parent.layout(true);
}
});
I think the ExpandBar works best when used like it is in this example...
http://git.eclipse.org/c/platform/eclipse.platform.swt.git/tree/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet343.java
... with several expand bars stacked on top of each other, and nothing else mixed in.
I think the functionality your looking for can be accomplished with an ExpandableComposite object. It depends on what else is going on in your ViewPart.
Here's a quick example of an ExpandableComposite.
package com.amx.designsuite.rcp;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.TableWrapLayout;
public class ExpandableCompositeExample extends Composite {
/**
* Create the composite.
* #param parent
* #param style
*/
public ExpandableCompositeExample(final Composite parent, int style) {
super(parent, style);
FormToolkit toolkit;
toolkit = new FormToolkit(parent.getDisplay());
final ScrolledForm form = toolkit.createScrolledForm(parent);
form.setText("Title for Form holding Expandable Composite (optional)");
TableWrapLayout layout = new TableWrapLayout();
form.getBody().setLayout(layout);
ExpandableComposite expandableCompsite = toolkit.createExpandableComposite(form.getBody(), ExpandableComposite.TREE_NODE | ExpandableComposite.SHORT_TITLE_BAR);
toolkit.paintBordersFor(expandableCompsite);
expandableCompsite.setText("Expandable Composite Title (Optional)");
expandableCompsite.setExpanded(true);
Text txtMyNewText = toolkit.createText(expandableCompsite, "Text to show when composite is expanded", SWT.NONE);
expandableCompsite.setClient(txtMyNewText);
}
#Override
protected void checkSubclass() {
// Disable the check that prevents subclassing of SWT components
}
}

How to make GWT Datagrid have its first column fixed and scroll horizontally and vertically

Currently GWT DataGrid header does this trick with a fixed header row during a vertical scroll. Is there a way to acheive the same on an entire (first) column?
I have implemented ScrolledGrid that freezes first column in DataGrid. You need to use it instead of DataGrid in order to make first column be frozen.
import com.google.gwt.dom.client.*;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.user.cellview.client.DataGrid;
import com.google.gwt.user.client.ui.HeaderPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
/**
*
* #author Yuri Plaksyuk
*/
public class ScrolledGrid extends DataGrid {
private final Text cssText;
private boolean addedClass = false;
private int currentScrollLeft = 0;
public ScrolledGrid() {
cssText = Document.get().createTextNode("");
StyleElement styleElement = Document.get().createStyleElement();
styleElement.setType("text/css");
styleElement.appendChild(cssText);
HeaderPanel headerPanel = (HeaderPanel) getWidget();
headerPanel.getElement().insertFirst(styleElement);
final ScrollPanel scrollPanel = (ScrollPanel) headerPanel.getContentWidget();
scrollPanel.addScrollHandler(new ScrollHandler() {
#Override
public void onScroll(ScrollEvent event) {
int scrollLeft = scrollPanel.getHorizontalScrollPosition();
if (scrollLeft != currentScrollLeft) {
StringBuilder css = new StringBuilder();
if (scrollLeft > 0) {
css.append(".ScrolledGrid-frozen {");
css.append("background-color: inherit;");
css.append("}");
css.append(".ScrolledGrid-frozen div {");
css.append("position: absolute;");
css.append("left: ").append(scrollLeft).append("px;");
css.append("width: ").append(getColumnWidth(getColumn(0))).append(";");
css.append("padding-left: 1.3em;");
css.append("padding-right: 0.5em;");
css.append("margin-top: -0.7em;");
css.append("white-space: nowrap;");
css.append("background-color: inherit;");
css.append("}");
}
else
css.append(".ScrolledGrid-frozen { }");
css.append("th.ScrolledGrid-frozen { background-color: white; }");
cssText.setData(css.toString());
if (!addedClass) {
NodeList<TableRowElement> rows;
TableRowElement row;
TableCellElement cell;
rows = getTableHeadElement().getRows();
for (int i = 0; i < rows.getLength(); ++i) {
row = rows.getItem(i);
cell = row.getCells().getItem(0);
cell.setInnerHTML("<div>" + cell.getInnerHTML() + "</div>");
cell.addClassName("ScrolledGrid-frozen");
}
rows = getTableBodyElement().getRows();
for (int i = 0; i < rows.getLength(); ++i) {
row = rows.getItem(i);
cell = row.getCells().getItem(0);
cell.addClassName("ScrolledGrid-frozen");
}
addedClass = true;
}
currentScrollLeft = scrollLeft;
}
}
});
}
}
Unfortunately, some CSS values are hard-coded.
I adapted Yuri's solution to achieve the following goals:
does not flicker
copes with arbitrary row-heights
works with SelectionModel
more uniform solution
It does not mess with the columns itself, but instead shows arbitrary "frozen" information on row-level.
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.*;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.user.cellview.client.DataGrid;
import com.google.gwt.user.cellview.client.DefaultCellTableBuilder;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.HeaderPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
/**
* #author Daniel Lintner
*
* A DataGrid extension with the ability to display some row-level-information
* when scrolling left (horizontal), hence important columns out of sight of the user.
*/
public class FrozenDataGrid extends DataGrid
{
//textnode getting updated dynamically when scolling horizontally
private Text cssText;
//the latest scroll-position
private int currentScrollLeft = 0;
//an object extracting String-info from your rowdata
private FrozenValueProvider valueProvider;
//inject basic styling into the document - once
//this is how the frozen row-info looks like
static
{
Text baseCss = Document.get().createTextNode("");
StyleElement styleElement = Document.get().createStyleElement();
styleElement.setType("text/css");
styleElement.appendChild(baseCss);
StringBuilder css = new StringBuilder();
css.append(".ScrolledGrid-base {");
css.append("position: absolute;");
css.append("background-color: gray;");
css.append("padding: .3em;");
css.append("padding-left: .5em;");
css.append("padding-right: .5em;");
css.append("border-radius: 3px 3px;");
css.append("transition: opacity 500ms;");
css.append("color: white;");
css.append("margin-top: 2px;");
css.append("white-space: nowrap;");
css.append("}");
baseCss.setData(css.toString());
Document.get().getBody().insertFirst(styleElement);
}
public FrozenDataGrid()
{
super();
init();
}
public FrozenDataGrid(int pageSize, DataGrid.Resources resources)
{
super(pageSize, resources);
init();
}
public void init()
{
//create a css textnode
cssText = Document.get().createTextNode("");
//create dynamic css Style
StyleElement styleElement = Document.get().createStyleElement();
styleElement.setType("text/css");
styleElement.appendChild(cssText);
//append the initial style condition
//todo the name of this style might be built dynamically per instance - if multiple grid-instances exist/not the use-case by now
StringBuilder css = new StringBuilder();
css.append(".ScrolledGrid-frozen {");
css.append("opacity:0;");
css.append("}");
cssText.setData(css.toString());
//set a custom CellTableBuilder in order to inject the info-div to the row
setTableBuilder(new DefaultCellTableBuilder(this)
{
#Override
public void buildRowImpl(final Object rowValue, final int absRowIndex)
{
//do what DefaultCellTableBuilder does
super.buildRowImpl(rowValue, absRowIndex);
//only do something if there is a valueProvider
if(valueProvider != null) {
//we do this deferred because this row has to created first in order to access it
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand()
{
#Override
public void execute()
{
createInfoDiv(getTableBodyElement().getRows().getItem(absRowIndex % getPageSize()), rowValue);
}
});
}
}
});
//fetch the ScrollPanel from the grid
HeaderPanel headerPanel = (HeaderPanel) getWidget();
headerPanel.getElement().insertFirst(styleElement);
final ScrollPanel scrollPanel = (ScrollPanel) headerPanel.getContentWidget();
//setup a timer handling the left-offset-css thing
//we use a timer to be able to cancel this operation -> e.g. continuous scroll
final Timer timer = new Timer(){
#Override
public void run() {
StringBuilder css = new StringBuilder();
//we need to left-offset the info-divs
if (scrollPanel.getHorizontalScrollPosition() > 100)
{
css.append(".ScrolledGrid-frozen {");
css.append("left: ").append(3 + scrollPanel.getHorizontalScrollPosition()).append("px;");
css.append("opacity: 1;");
css.append("}");
}
//we are close to the leftmost scroll position: info hidden
else
{
css.append(".ScrolledGrid-frozen {");
css.append("opacity:0;");
css.append("}");
}
cssText.setData(css.toString());
}
};
//track scrolling
scrollPanel.addScrollHandler(new ScrollHandler()
{
#Override
public void onScroll(ScrollEvent event)
{
//cancel previous actions to scroll events
if(timer.isRunning())
timer.cancel();
//actual horizontal scrollposition
int scrollLeft = scrollPanel.getHorizontalScrollPosition();
//a horizontal scroll takes places
if (scrollLeft != currentScrollLeft)
{
//first we hide the row-info
StringBuilder css = new StringBuilder();
css.append(".ScrolledGrid-frozen {");
css.append("opacity:0;");
css.append("}");
cssText.setData(css.toString());
//render left offset after a delay
timer.schedule(500);
//remember the current horizontal position
currentScrollLeft = scrollLeft;
}
}
});
}
private void createInfoDiv(TableRowElement row, Object value)
{
//create a div element and add value and style to it
DivElement div = Document.get().createDivElement();
div.setInnerText(valueProvider.getFrozenValue(value));
div.addClassName("ScrolledGrid-base");
div.addClassName("ScrolledGrid-frozen");
//we add it to the first child of the row, because added as child of the row directly
// confuses the CellTable with coordinating header positions
row.getFirstChildElement().insertFirst(div);
}
public void setFrozenValueProvider(FrozenValueProvider valueProvider) {
this.valueProvider = valueProvider;
}
public interface FrozenValueProvider<T>{
String getFrozenValue(T data);
}
}
Hope this helps developers on this rarely and unsatisfactorily solved problem.
And... there is still room for improvement left.
Cheers Dan