How to always show vertical scroll bar in SWT table?

Claude picture Claude · Oct 15, 2013 · Viewed 11.3k times · Source

Is it possible to always show the vertical scroll bar in a SWT table even if the table is empty? By always showing a (possible disabled) vertical scroll bar one can avoid that the last column get partially hidden when the columns use ColumnWeightData for layouting.

I tried to initialize the table with SWT.V_SCROLL or to use table.getVerticalBar().setVisible(true) - both without success.

There is a method setAlwaysShowScrollBars in ScrollableComposite. What I am looking for is a similar method in Table.

UPDATE: I suppose that the scroll bars which are visible when the table contains enough data are not those scroll bars which Table inherits from Scrollable. I have debugged ScrollBar.setVisible(boolean) and it seems not be called on table layout updates. Is this observation correct?

UPDATE 2: Here is a snippet for a table construction. It would be great to have the vertical scrollbar visible even if the table is empty and to have the column headers visible even if the table data are scrolled down. Note: The snippet has left out some details as the label provider and some other controls arranged at the same parent composite.

protected void createMasterPart(final IManagedForm managedForm, Composite parentComposite)
{
  FormToolkit toolkit = managedForm.getToolkit();

  Composite contentComposite = toolkit.createComposite(parentComposite, SWT.NONE);
  contentComposite.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));
  toolkit.paintBordersFor(contentComposite);

  contentComposite.setLayout(new GridLayout(2, false));
  GridData gd;

  Composite tableComposite = new Composite(contentComposite, SWT.NONE);
  TableColumnLayout tableColumnLayout = new TableColumnLayout();
  tableComposite.setLayout(tableColumnLayout);
  gd = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 3);
  tableComposite.setLayoutData(gd);

  speakerTableViewer = new TableViewer(tableComposite, SWT.BORDER | SWT.FULL_SELECTION);
  speakerTableViewer.setContentProvider(ArrayContentProvider.getInstance());
  Table speakerTable = speakerTableViewer.getTable();
  speakerTable.setHeaderVisible(true);
  speakerTable.setLinesVisible(true);
  toolkit.paintBordersFor(speakerTable);

  TableViewerColumn tableViewerAudiosampleColumn = new TableViewerColumn(speakerTableViewer, SWT.NONE);
  TableColumn audiosampleColumn = tableViewerAudiosampleColumn.getColumn();
  tableColumnLayout.setColumnData(audiosampleColumn, new ColumnWeightData(60, true));
  audiosampleColumn.setText("Sample");

  TableViewerColumn tableViewerSpeakerColumn = new TableViewerColumn(speakerTableViewer, SWT.NONE);
  TableColumn speakerColumn = tableViewerSpeakerColumn.getColumn();
  tableColumnLayout.setColumnData(speakerColumn, new ColumnWeightData(60, true));
  speakerColumn.setText("Speaker");

  TableViewerColumn tableViewerRemarkColumn = new TableViewerColumn(speakerTableViewer, SWT.NONE);
  TableColumn remarkColumn = tableViewerRemarkColumn.getColumn();
  tableColumnLayout.setColumnData(remarkColumn, new ColumnWeightData(120, true));
  remarkColumn.setText("Remark");
}

Answer

Baz picture Baz · Apr 2, 2014

It's not possible to force the Table to always show scroll bars, the OS decides when to show them.

Alternatives

Right, I came up with a solution very similar to my answer to this question:

Is it possible to get the vertical/horizontal scroll bar visible when the SWT List is in disabled state?


The idea is to use a ScrolledComposite (as the other answer already suggested) to take care of the scrolling. The Table itself won't scroll. However, this won't make any difference, because the user won't be able to tell the difference.

ScrolledComposite has a method called setAlwaysShowScrollBars(boolean) with which you can force it to always show the scroll bars, even if they aren't required.

Here is some sample code, that will illustrate what I just talked about:

public static void main(String[] args)
{
    final Display display = new Display();
    final Shell shell = new Shell(display);
    shell.setLayout(new GridLayout());

    final ScrolledComposite composite = new ScrolledComposite(shell, SWT.V_SCROLL);
    composite.setLayout(new GridLayout());
    composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

    final Table table = new Table(composite, SWT.NO_SCROLL | SWT.FULL_SELECTION);
    table.setHeaderVisible(true);

    composite.setContent(table);
    composite.setExpandHorizontal(true);
    composite.setExpandVertical(true);
    composite.setAlwaysShowScrollBars(true);
    composite.setMinSize(table.computeSize(SWT.DEFAULT, SWT.DEFAULT));

    Button fillTable = new Button(shell, SWT.PUSH);
    fillTable.setText("Fill table");
    fillTable.setLayoutData(new GridData(SWT.FILL, SWT.END, true, false));

    fillTable.addListener(SWT.Selection, new Listener()
    {
        @Override
        public void handleEvent(Event arg0)
        {
            if (table.getColumnCount() < 1)
            {
                for (int col = 0; col < 4; col++)
                {
                    TableColumn column = new TableColumn(table, SWT.NONE);
                    column.setText("Column " + col);
                }
            }

            for (int row = 0; row < 20; row++)
            {
                TableItem item = new TableItem(table, SWT.NONE);

                for (int col = 0; col < table.getColumnCount(); col++)
                {
                    item.setText(col, "Item " + row + " " + col);
                }
            }

            for (int col = 0; col < table.getColumnCount(); col++)
            {
                table.getColumn(col).pack();
            }

            composite.setMinSize(table.computeSize(SWT.DEFAULT, SWT.DEFAULT));
        }
    });

    Button clearTable = new Button(shell, SWT.PUSH);
    clearTable.setText("Clear table");
    clearTable.setLayoutData(new GridData(SWT.FILL, SWT.END, true, false));

    clearTable.addListener(SWT.Selection, new Listener()
    {
        @Override
        public void handleEvent(Event arg0)
        {
            table.removeAll();

            composite.setMinSize(table.computeSize(SWT.DEFAULT, SWT.DEFAULT));
        }
    });

    shell.pack();
    shell.setSize(400, 300);
    shell.open();
    while (!shell.isDisposed())
    {
        if (!display.readAndDispatch())
            display.sleep();
    }
    display.dispose();
}

Looks like this:

enter image description here enter image description here

As you can see, the scroll bar is always visible.


UPDATE

As pointed out in the comment, this approach will not keep the Table headers visible when you scroll down. If you could post a small working code example that illustrates your problem, we might come up with an alternative (unrelated to forcing the scroll bars).

UPDATE2

Here is some code that should do what you want, the trick is to trigger a resize event on the parent of the TableViewer, the horizontal scrollbar that is shown isn't really necessary and it disappears after you resize the window:

public static void main(String[] args)
{
    final Display display = new Display();
    final Shell shell = new Shell(display);
    shell.setText("StackOverflow");
    shell.setLayout(new GridLayout());

    createMasterPart(shell);

    shell.pack();
    shell.setSize(400, 300);
    shell.open();

    shell.layout(true, true);

    while (!shell.isDisposed())
    {
        if (!display.readAndDispatch())
            display.sleep();
    }
    display.dispose();
}

private static void createMasterPart(Composite parentComposite)
{
    Composite composite = new Composite(parentComposite, SWT.NONE);
    composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    composite.setLayout(new GridLayout(1, false));

    Composite tableComposite = new Composite(composite, SWT.NONE);
    TableColumnLayout tableColumnLayout = new TableColumnLayout();
    tableComposite.setLayout(tableColumnLayout);
    tableComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

    TableViewer tableViewer = new TableViewer(tableComposite, SWT.BORDER | SWT.FULL_SELECTION);
    tableViewer.setContentProvider(ArrayContentProvider.getInstance());
    Table table = tableViewer.getTable();
    table.setHeaderVisible(true);
    table.setLinesVisible(true);

    TableViewerColumn firstTableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
    TableColumn firstTableColumn = firstTableViewerColumn.getColumn();
    firstTableColumn.setText("Sample");
    firstTableViewerColumn.setLabelProvider(new ColumnLabelProvider()
    {
        @Override
        public String getText(Object element)
        {
            Dummy p = (Dummy) element;
            return p.first;
        }
    });

    TableViewerColumn secondTableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
    TableColumn secondTableColumn = secondTableViewerColumn.getColumn();
    secondTableColumn.setText("Speaker");
    secondTableViewerColumn.setLabelProvider(new ColumnLabelProvider()
    {
        @Override
        public String getText(Object element)
        {
            Dummy p = (Dummy) element;
            return p.second;
        }
    });

    TableViewerColumn thirdTableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
    TableColumn thirdTableColumn = thirdTableViewerColumn.getColumn();
    thirdTableColumn.setText("Remark");
    thirdTableViewerColumn.setLabelProvider(new ColumnLabelProvider()
    {
        @Override
        public String getText(Object element)
        {
            Dummy p = (Dummy) element;
            return p.third;
        }
    });

    List<Dummy> elements = new ArrayList<>();

    for(int i = 0; i < 20; i++)
    {
        elements.add(new Dummy("firstfirstfirst " + i, "secondsecondsecond " + i, "thirdthirdthirdthirdthirdthird " + i));
    }

    tableViewer.setInput(elements);

    tableColumnLayout.setColumnData(firstTableColumn, new ColumnWeightData(1, true));
    tableColumnLayout.setColumnData(secondTableColumn, new ColumnWeightData(1, true));
    tableColumnLayout.setColumnData(thirdTableColumn, new ColumnWeightData(2, true));
}

private static class Dummy
{
    public String first;
    public String second;
    public String third;

    public Dummy(String first, String second, String third)
    {
        this.first = first;
        this.second = second;
        this.third = third;
    }
}