How to always show vertical scroll bar in SWT table?

12,110

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;
    }
}
Share:
12,110
Claude
Author by

Claude

Updated on July 03, 2022

Comments

  • Claude
    Claude almost 2 years

    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");
    }
    
  • Claude
    Claude over 10 years
    The table is not a ScrollableComposite and is not inside a ScrollableComposite. What is ScrolledComposite?
  • Basilevs
    Basilevs about 10 years
    Are column headers still visible after scroll down?
  • Baz
    Baz about 10 years
    @Basilevs They never are in SWT Tables.
  • Basilevs
    Basilevs about 10 years
    In usual table headers are always shown in every scroll position.
  • Baz
    Baz about 10 years
    @Basilevs Huh, never realized. They definitely won't be with this code. OP will have to decide what's more important.
  • Claude
    Claude about 10 years
    @Baz Thanks for your help! However, table headers are more important to me (as the question owner). And yes: the problem seems to be the OS. How can I force the OS to show the scroll bars? Is there a way to set a combination of properties on the table object which let the OS show the scrollbar?
  • Baz
    Baz about 10 years
    @Michael No, there is no way to force the OS to show the scroll bar from SWT code. As I said in the answer, if you can post a (minimal) sample program that shows your issue, we might be able to find a solution that doesn't make fiddling about with the scroll bars necessary. The only way to make the OS show the scroll bars would be to add "empty" TableItems until there are enough of them to make the scroll bars appear, but that's a road you don't want to go down.
  • Claude
    Claude about 10 years
    @Baz I have added a snippet to the original question. Hope this helps. Thank you!
  • Claude
    Claude about 10 years
    @Baz Give me some time to test it in my enviroment where I use RCP with views and forms. If it works even when the window, the view or the form is resized by the user I will accept your answer. I appreciate you efforts and help!
  • Claude
    Claude about 10 years
    @Baz I have tested the solution under "Update 2". If I resize the window such that all table items are visible then the vertical scrollbar is hidden. If I start with an empty table the vertical scrollbar is hidden too. I am afraid this is not a solution to the original problem. Thank you for your efforts!
  • Baz
    Baz about 10 years
    @Michael The goal of my code wasn't to hide the vertical scrollbar, but the horizontal one. Can you verify, that my code does not work for you and if so, please elaborate why?
  • Claude
    Claude about 10 years
    @Baz The question was "How to always show vertical scroll bar?" not to hide the horizontal one. I guess (and you already confirmed this) that this is a matter of the OS.
  • Baz
    Baz about 10 years
    @Michael Yes it is up to the OS, but what I'm suggesting in my latest update is an alternative that doesn't require forcing the scroll bar. Did you try it in your environment?
  • Claude
    Claude about 10 years
    @Baz I tried it with the outcome described above. I understand that the vertical scroll bar can't be shown under any circumstances. I see that instead of this your solution ensures that the last column is not partially hidden. However, the question was how to always show the scroll bar. If the scroll bar would be always visible then columns don't get resized when the table overflows. This happens with the solution above. I appriciate your help and that's why I voted up your answer. Let the community decide if the original question is really answered.
  • Baz
    Baz about 10 years
    @Michael Ok, then the answer is: "No", you can't force the scroll bars to always be shown. BTW: how would the community decide if the original question is answered? The person who decides that (and may mark this as answered) is you.
  • Claude
    Claude about 10 years
    @Baz In addition to my last comment I have to note that the solution doesn't work in an RCP environment with views and editors (see one of my comments above). Views are initialized lazily when the workbench is already open. If the shell is packed and resized the workbench gets resized.
  • Claude
    Claude about 10 years
    @Baz Ok, please make clear at the very top of your answer that it is not possible to always show the scroll bar. After that I will mark it as answer.
  • Baz
    Baz about 10 years
    @Michael Done, sorry that we couldn't find a suitable solution for your case though...
  • Claude
    Claude about 9 years
    Thanks for the example! However, I am afraid that there is a lot to do to get this hack working in a productive environment: disable selection of empty items; adapt when table is resized; adapt if real items are added; work with table models. Thanks anyway!