Question

I'm using two flex tables. One for header and one for data.
The one for data is wrapped with a scroll panel.
The size of my columns is presented with percentage and this is where my problem begins:
I set the width of both tables to 100%.
The thing is that the scrollbar isn't always visible. It's visible only when required.
So when the scrollbar is shown - there's a gap between the width of the header and the width of the data area inside the scrollpanel. (since the scrollbar itself has width of 16px)
This way, the titles of the columns, doesn't match precisely the data columns.

Any suggestions?
Thanks in advance!

Was it helpful?

Solution

Based on your comment from my other answer you are left with having to code. I have solved this sort of problem in the past by using a shim column. I wouldn't call it elegant but it did the trick. Basically, you have an extra column in your header at the end that acts as a shim for the scrollbar. When the scrollbar is being displayed then the shim column is displayed with the exact width of the scrollbar. When there is no scrollbar you hide the shim.

  1. Setup your layout with the additional column. Style it however you want. I usually make it so it blends in with the adjoining column so the user doesn't see a little square when it is being displayed.

  2. Add all your data rows to the content table as you normally would. Make sure the content table and all its tr/td are added to the DOM.

  3. Once the data is added then test whether the scrollbar is visible. You can do this by checking if the scroll height is greater then the offset height.

    ScrollPanel scrollPanel;
    Element scrollElem = scrollPanel.getElement();
    
    if (scrollElem.getScrollHeight() > scrollElem.getOffsetHeight()) {
        // scrollbar is visible
    }
    
  4. If the scrollbar is displayed then show your shim column, otherwise hide it.

    if (scrollElem.getScrollHeight() > scrollElem.getOffsetHeight()) {
        // scrollbar is visible - show shim column
        shimColumnTD.getStyle().setDisplay(Display.BLOCK);
    }
    else {
        // scrollbar not visible - hide shim column
        shimColumnTD.getStyle().setDisplay(Display.NONE);
    }
    
  5. Determine the width of the shim column so that it matches the width of the scrollbar. If you go look inside the below method you can see how it does this.

    // calculate the width of the scrollbar for the given browser
    int shimWidth = AbstractNativeScrollbar.getNativeScrollbarWidth();
    

Obviously, this is just all pseudo but it should lead you in the right direction. Good luck...

OTHER TIPS

There are a lot of possible things you can do to keep columns in sync, but most of them requires active layout and/or preview resize events.

I guess that, for your use case, is much simpler and (performance wise) far faster to either:

  • shrink both tables a bit, to always accomodate the space for the scrollbar (or even remove the scrollbars at all, keeping the scrolling behavior functionality). Both solutions are generally achieved by using a pair of nested div, with the second one wider enough to hide/accomodate the scrollbar;
  • wrap your second table into a panel that does not shrink the content when it overflows. In GWT you can do that natively using a CustomScrollPanel (instead a ScrollPanel). Just pay attention that is a RequiresResize panel that needs either an interrupted chain of ProvidesResize containers, or an explict size.

Side note: If you ever need to calculate the size of the native scrollbars in a cross browser solution, just use AbstractNativeScrollbar.getNativeScrollbarHeight() (and/or the width one).

A common trick for this sort of thing that avoids complex code and layout is to simply fix the widths of all your columns except the last one. The last column will auto adjust and you won't have to worry about the scrollbar at all.

Here is a jsfiddle sample along with some sample html/css to show you what I mean. The caveat is that all of the columns have to have width (they cannot be percentages) except the last one.

jsfiddle example

CSS:

.container {
    width: 500px;
    border: 1px solid red;
}

.content-wrapper {
    overflow: auto;
    height: 75px;
}

table {
    width: 100%;
    border-collapse: collapse;
}

col {
    width: 100px;
}

col:last-child {
    width: auto;
}

.container td {
    border: 1px solid green;
}

HTML:

<div class="container">
    <div class="header-wrapper">
        <table class="header">
            <colgroup>
                <col/>
                <col/>
                <col/>
                <col/>
                <col/>
            </colgroup>
            <tr>
                <td>Column A</td>
                <td>Column B</td>
                <td>Column C</td>
                <td>Column D</td>
                <td>Column E</td>
            </tr>
        </table>
    </div>
    <div class="content-wrapper">
        <table class="content">
            <colgroup>
                <col/>
                <col/>
                <col/>
                <col/>
                <col/>
            </colgroup>
            <tr>
                <td>Row 1/A</td>
                <td>Row 1/B</td>
                <td>Row 1/C</td>
                <td>Row 1/D</td>
                <td>Row 1/E</td>
            </tr>
            <tr>
                <td>Row 2/A</td>
                <td>Row 2/B</td>
                <td>Row 2/C</td>
                <td>Row 2/D</td>
                <td>Row 2/E</td>
            </tr>
            <tr>
                <td>Row 3/A</td>
                <td>Row 3/B</td>
                <td>Row 3/C</td>
                <td>Row 3/D</td>
                <td>Row 3/E</td>
            </tr>
            <tr>
                <td>Row 4/A</td>
                <td>Row 4/B</td>
                <td>Row 4/C</td>
                <td>Row 4/D</td>
                <td>Row 4/E</td>
            </tr>
            <tr>
                <td>Row 5/A</td>
                <td>Row 5/B</td>
                <td>Row 5/C</td>
                <td>Row 5/D</td>
                <td>Row 5/E</td>
            </tr>
        </table>
    </div
</div>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top