允许GWT DataGrid填充可用高度

时间:2015-01-30 17:36:03

标签: css gwt datagrid

考虑一个其UI有标签的GWT应用程序。在一个标签中,有一些固定大小的元素,后跟DataGrid

 _______________________________________________
|       ______                                  |
| Tab1 / Tab2 \ Tab3                            |
|_____/        \________________________________|
| Fixed size widgets here.                   || |
| Fixed size widgets here.                   || |
| ----------------------                     || |
| Datagrid headings         tab scrollbar -->|| |
| cell cell cell cell ||                     || |
| cell cell cell cell ||                     || |
| cell cell cell cell ||<-- datagrid         || |
| cell cell cell cell ||    scrollbar        || |
| cell cell cell cell ||                     || |
| cell cell cell cell ||                     || |
 -----------------------------------------------

我希望DataGrid填充窗口中的剩余高度,并在浏览器窗口调整大小时更改高度,但约束条件是它不会小于指定的最小高度(例如3行,不包括标题)。在此应用程序中,数据网格中通常只有大约10行。

有两个滚动条。我希望他们表现得像这样:

数据网格滚动条允许导航数据网格中的行。如果可以看到数据网格中的所有行,则不应显示它。

标签滚动条滚动选项卡的内容,使标签选择器可见。通常这是隐藏的,因为datagrid完全包含在浏览器窗口中,并且datagrid滚动条可用于查看内容。但是,数据网格具有最小高度,如果浏览器窗口中没有空间,则可以看到选项卡滚动条。

我的问题是:我如何实现这一目标?

我有一些示例代码。首先,模块加载如下:

public class Proj implements EntryPoint {
  public void onModuleLoad() {
      RootLayoutPanel.get().add(new App());
      //RootPanel.get("app").add(new App());
  }
}

认为我需要RootLayoutPanel版本而不是RootPanel,但我欢迎对此发表评论。

现在有些UiBinder代码:

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
    xmlns:g="urn:import:com.google.gwt.user.client.ui"
    xmlns:d="urn:import:com.google.gwt.user.cellview.client"
    >
    <ui:style>
        .foo { 
        min-height: 100px; 
        max-height: 300px; 
        }

    </ui:style>
    <g:TabLayoutPanel ui:field="tabLayout" barUnit="PX" barHeight="30" >
        <g:tab>
            <g:header> Tab One </g:header>
            <g:ScrollPanel height="100%"> <!-- Hack? height="100%":-->
                <g:FlowPanel>
                    <g:Label text="Window.getClientHeight():"/>
                    <g:Label ui:field="label" text="Window.getClientHeight()"/>
                    <g:Label text="grid.getElement().getAbsoluteTop():"/>
                    <g:Label ui:field="label2" text="grid.getElement().getAbsoluteTop()"/>
                    <d:DataGrid styleName='{style.foo}' ui:field="grid"/>
                </g:FlowPanel>
            </g:ScrollPanel>
        </g:tab>
    </g:TabLayoutPanel>
</ui:UiBinder>

最后定义class App

public class App extends ResizeComposite {
    @UiTemplate("App.ui.xml")
    interface ThisUiBinder extends UiBinder<Widget, App> {
    }
    private static ThisUiBinder uiBinder = GWT.create(ThisUiBinder.class);
    @UiField
    TabLayoutPanel tabLayout;
    @UiField
    Label label;
    @UiField
    Label label2;
    @UiField (provided=true)
    DataGrid grid;

    static class Data {
        String foo;
        public Data(String foo) {
            this.foo = foo;
        }
    }
    private static final List<Data> DATA = Arrays.asList(
            new Data("A"), new Data("Q"), new Data("w"),
            new Data("e"), new Data("r"), new Data("t"),
            new Data("y"), new Data("u"), new Data("i"),
            new Data("o")
            );
    private final int MINSIZE = 100;    // of grid, in px

    public App() {
        grid = new DataGrid<Data>();
        TextColumn<Data> fooColumn = new TextColumn<Data>() {
            @Override
            public String getValue(Data object) {
                return object.foo;
            }
        };
        grid.addColumn(fooColumn, "foo");
        grid.setRowCount(DATA.size(), true);
        grid.setRowData(0, DATA);

        initWidget(uiBinder.createAndBindUi(this));
        //grid.setHeight("100%");   // hack, 100% of what?
        //tabLayout.setHeight("100%");  // hack, 100% of what?
        onResize(); // Hack!
    }
    public void onResize() {
        label.setText(String.valueOf(Window.getClientHeight()));

        // Note that this is 0 on the first call (from our constructor),
        // which does not give the desired result!
        label2.setText(String.valueOf(grid.getElement().getAbsoluteTop()));

        // Works very badly! Jumpy and eratic!
        int newsize = Window.getClientHeight() - grid.getElement().getAbsoluteTop();
        if (newsize > MINSIZE) {
            grid.setHeight(String.valueOf(newsize)) + "px");
        }
    }
}

onResize()中的机制不仅对我来说闻起来很糟糕(它是作为一个实验实现的),而且它也很可笑地工作。

有没有一种巧妙的方法可以完全用CSS做到这一点?或者是否必须在onResize()中完成某些事情?我使用GWT的一个动机是避免浏览器之间的差异引起的问题,纯CSS是正确的方法吗?

我已将height设置为100%在各个地方作为黑客,看看它有什么不同。我非常希望能够正确地理解这一切是如何挂在一起的 - 任何阅读建议都会受到欢迎。我也尝试过遵守http://www.dave-woods.co.uk/100-height-layout-using-css/中的指南,例如使用CSS:

html, body {
    height: 100%;
}

我还发现了这个信息:https://stackoverflow.com/a/11866677/685715。但它并没有解决我的问题。

2 个答案:

答案 0 :(得分:0)

您有三种选择:

  1. 使用附加到Window的ResizeHandler。调整窗口大小时,计算并设置DataGrid的大小。

  2. 在选项卡中使用LayoutPanel(或VerticalPanel0。设置固定宽度小部件,然后设置DataGrid小部件:

    myLayoutPanel.setWidgetTopBottom(myDataGrid, 120, Unit.PX, 0, Unit.PX);
    
  3. 此解决方案不需要调整大小处理程序,但会为您的布局引入额外的小部件(即HTML代码)。

    1. 如果您不关心旧浏览器,请使用flexbox布局模型(http://css-tricks.com/snippets/css/a-guide-to-flexbox/)。这是一个纯CSS解决方案。

答案 1 :(得分:0)

假设Datagrid上面的静态小部件的高度是常量并且已知的,我会这样做:

UiBinder代码:

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
    xmlns:g="urn:import:com.google.gwt.user.client.ui"
    xmlns:d="urn:import:com.google.gwt.user.cellview.client"
    >
    <ui:style>
        .foo { 
        min-height: [HEIGHT OF STATIC WIDGETS + 100px]; 
        max-height: [HEIGHT OF STATIC WIDEGET + 300px; 
        }

    </ui:style>
    <g:TabLayoutPanel ui:field="tabLayout" barUnit="PX" barHeight="30" >
        <g:tab>
            <g:header> Tab One </g:header>
            <g:ScrollPanel >
                <g:LayoutPanel addStyleNames="{style.foo}">
                    <g:layer top="0" height="[HEIGHT OF STATIC WIDGETS]">
                        <g:FlowPanel> 
                          <g:Label text="Window.getClientHeight():"/>
                          <g:Label ui:field="label" text="Window.getClientHeight()"/>
                          <g:Label text="grid.getElement().getAbsoluteTop():"/>
                          <g:Label ui:field="label2" text="grid.getElement().getAbsoluteTop()"/>
                         </g:FlowPanel>
                    </g:layer>
                    <g:layer top="[HEIGHT OF STATIC WIDGETS] bottom="0">
                        <d:DataGrid  ui:field="grid"/>
                    </g:layer>
               </g:LayoutPanel>
            </g:ScrollPanel>
        </g:tab>
    </g:TabLayoutPanel>
</ui:UiBinder>

这应该完全适用于UiBinder代码(不需要进行Java更改或大小计算)。

当然,这仅适用于知道DataGrid上方固定大小的小部件的总高度(只需将&#34; [静态WIDGETS高度]&#34; 替换为相应的大小

或者您也可以尝试将DataGrid包裹在ResizeLayoutPanel内,这将为DataGrid提供明确的尺寸,并且不需要{{1}的完整链最多LayoutPanels。但是我不确定这是否适用于DataGrid上的 min-height 。您可能希望将其移至RootLayoutPanel本身。