如何在 GXT 3.x 中实现冻结列? [英] How to implement freeze column in GXT 3.x?

查看:32
本文介绍了如何在 GXT 3.x 中实现冻结列?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在 GXT 3.x(来自 Sencha)中实现冻结列?Ext-JS,来自 Sencha 的另一个产品似乎实现了这一点,但我看不到基于 Java 的 GXT 在哪里实现了同样的事情:

How can frozen columns be implemented in GXT 3.x (from Sencha)? Ext-JS, another product from Sencha seems to implement this, but I can't see where the Java based GXT implement the same thing:

http://dev.sencha.com/deploy/ext-4.0.0/examples/grid/locking-grid.html

推荐答案

基本思想是您需要两种不同的滚动容器,一种带有固定列,一种带有滚动列.每一个都需要在一个不同的视口中,所以标准的 Grid/GridView 不能很好地处理这个 - 它们对滚动应该如何表现做出假设,所以简单地将一个或两个子类化可能会相当复杂.

The basic idea is that you need two different scrolling containers, one with the fixed column(s), one with the scrolling columns. Each of these need to be in a distinct viewport, so the standard Grid/GridView doesn't work well with this - they make assumptions about how scrolling should behave, so simply subclassing one or both is likely to be fairly involved.

相反,您可以构建两个网格,一个用于锁定列,一个用于滚动列.每个都可以处理自己的 ColumnConfig 类,以绘制标题和行,并将链接到相同的 ListStore 以确保它们的数据同步 - 存储中的更改将传递给两个监听网格.

Instead, you can build two grids, one for the locked columns, one for the scrolling ones. Each can deal with their own ColumnConfig classes, to draw headers and rows, and will be linked to the same ListStore to ensure their data is in sync - changes in the store will be passed along to both listening grids.

为了获得完整的效果,需要一些额外的布线:

To get the full effect, some additional wiring will be needed:

  • 链接滚动.聆听每个 Grid 的 BodyScrollEvent,并将另一个滚动到同一位置(仅更改 top,而不是 left,因为您没有想要一个控制另一个).
  • 调整大小是第二大部分 - 两个网格都需要它们的可滚动高度相同,但水平滚动网格在实际显示滚动条时需要底部的缓冲区.通常 Grid 被告知根据其父级的指令调整大小,但有时您直接调整 Grid 的大小 - 在这种情况下,不需要此步骤,只需将两个网格的大小略有不同即可.否则,您需要构建布局以正确配置它.
  • 最后,锁定的列需要隐藏其垂直滚动条 - 用户无需看到两个垂直滚动条.
  • Linking scrolling. Listen to the BodyScrollEvent from each Grid, and scroll the other to the same place (changing only top, not left, since you don't want one to control the other).
  • Sizing is the second big piece - both grids need their scrollable height to be the same, but the horizontal scrolling one needs a buffer on the bottom when it is actually showing that scrollbar. Usually the Grid is told to size based on its parent's instructions, though sometimes you directly size the Grid - in this case, this step is not needed, just size the two grids slightly differently. Otherwise, you'll need to structure the layout to properly configure this.
  • Finally, the locked column needs its vertical scrollbar to be hidden away - the user has no need to see two vertical scrollbars.

这涵盖了基本用例,但不处理诸如替代 GridView 实现之类的事情 - GroupingView 和子类将需要链接扩展(并隐藏组标题,这样它们就不会出现两次,再加上当下半部分横向滚动时组行不应该被拆分的事实),TreeGridViewTreeGrid 将需要链接扩展节点并隐藏第二个网格中的树 +/- 图标.

This covers the basic use case, but doesn't deal with things like alternate GridView implementations - GroupingView and subclasses will need to link expanding (and to hide the group headings so they don't appear twice, plus deal with the fact that the group row shouldn't get split when the second half scrolls sideways), TreeGridView and TreeGrid will need to link expanding nodes and hide the tree +/- icons from the second grid.

这是应用于 http://www.sencha.com/examples 的基本网格示例的一组基本修改/#ExamplePlace:basicgrid.为避免混淆该问题,我删除了该网格中的许多其他功能,例如工具提示和更改选择模型:

Here's this basic set of modifications applied to the basic grid example at http://www.sencha.com/examples/#ExamplePlace:basicgrid. To help avoid confusing the issue, I've deleted a number of other features in that grid such as tooltips and changing the selection model:

public class GridExample implements IsWidget, EntryPoint {
  private static final StockProperties props = GWT.create(StockProperties.class);

  private ContentPanel root;

  @Override
  public Widget asWidget() {
    if (root == null) {
      final NumberFormat number = NumberFormat.getFormat("0.00");

      ColumnConfig<Stock, String> nameCol = new ColumnConfig<Stock, String>(props.name(), 50, SafeHtmlUtils.fromTrustedString("<b>Company</b>"));

      ColumnConfig<Stock, String> symbolCol = new ColumnConfig<Stock, String>(props.symbol(), 100, "Symbol");
      ColumnConfig<Stock, Double> lastCol = new ColumnConfig<Stock, Double>(props.last(), 75, "Last");

      ColumnConfig<Stock, Double> changeCol = new ColumnConfig<Stock, Double>(props.change(), 100, "Change");
      changeCol.setCell(new AbstractCell<Double>() {

        @Override
        public void render(Context context, Double value, SafeHtmlBuilder sb) {
          String style = "style='color: " + (value < 0 ? "red" : "green") + "'";
          String v = number.format(value);
          sb.appendHtmlConstant("<span " + style + " qtitle='Change' qtip='" + v + "'>" + v + "</span>");
        }
      });

      ColumnConfig<Stock, Date> lastTransCol = new ColumnConfig<Stock, Date>(props.lastTrans(), 100, "Last Updated");
      lastTransCol.setCell(new DateCell(DateTimeFormat.getFormat("MM/dd/yyyy")));

      List<ColumnConfig<Stock, ?>> l = new ArrayList<ColumnConfig<Stock, ?>>();
      //Remove name from main set of columns
      //      l.add(nameCol);
      l.add(symbolCol);
      l.add(lastCol);
      l.add(changeCol);
      l.add(lastTransCol);

      //create two column models, one for the locked section
      ColumnModel<Stock> lockedCm = new ColumnModel<Stock>(Collections.<ColumnConfig<Stock, ?>>singletonList(nameCol));
      ColumnModel<Stock> cm = new ColumnModel<Stock>(l);

      ListStore<Stock> store = new ListStore<Stock>(props.key());
      store.addAll(TestData.getStocks());

      root = new ContentPanel();
      root.setHeadingText("Locked Grid Sample");
      root.setPixelSize(600, 300);

      final Resizable resizable = new Resizable(root, Dir.E, Dir.SE, Dir.S);
      root.addExpandHandler(new ExpandHandler() {
        @Override
        public void onExpand(ExpandEvent event) {
          resizable.setEnabled(true);
        }
      });
      root.addCollapseHandler(new CollapseHandler() {
        @Override
        public void onCollapse(CollapseEvent event) {
          resizable.setEnabled(false);
        }
      });

      //locked grid
      final Grid<Stock> lockedGrid = new Grid<Stock>(store, lockedCm) {
        @Override
        protected Size adjustSize(Size size) {
          //this is a tricky part - convince the grid to draw just slightly too wide
          //and so push the scrollbar out of sight
          return new Size(size.getWidth() + XDOM.getScrollBarWidth() - 1, size.getHeight());
        }
      };
      lockedGrid.setView(new GridView<Stock>(){{
        this.scrollOffset=0;
      }});
      //require columns to always fit, preventing scrollbar
      lockedGrid.getView().setForceFit(true);

      //main grid, with horiz scrollbar
      final Grid<Stock> grid = new Grid<Stock>(store, cm);
      //don't want this feature, want to encourage horizontal scrollbars
      //      grid.getView().setAutoExpandColumn(nameCol);
      grid.getView().setStripeRows(true);
      grid.getView().setColumnLines(true);
      grid.setBorders(false);

      grid.setColumnReordering(true);
      grid.setStateful(true);
      grid.setStateId("gridExample");

      //link scrolling
      lockedGrid.addBodyScrollHandler(new BodyScrollHandler() {
        @Override
        public void onBodyScroll(BodyScrollEvent event) {
          grid.getView().getScroller().scrollTo(ScrollDirection.TOP, event.getScrollTop());
        }
      });
      grid.addBodyScrollHandler(new BodyScrollHandler() {
        @Override
        public void onBodyScroll(BodyScrollEvent event) {
          lockedGrid.getView().getScroller().scrollTo(ScrollDirection.TOP, event.getScrollTop());
        }
      });

      HorizontalLayoutContainer gridWrapper = new HorizontalLayoutContainer();
      root.setWidget(gridWrapper);

      //add locked column, only 300px wide (in this example, use layouts to change how this works
      HorizontalLayoutData lockedColumnLayoutData = new HorizontalLayoutData(300, 1.0);

      //this is optional - without this, you get a little offset issue at the very bottom of the non-locked grid
      lockedColumnLayoutData.setMargins(new Margins(0, 0, XDOM.getScrollBarWidth(), 0));

      gridWrapper.add(lockedGrid, lockedColumnLayoutData);

      //add non-locked section, taking up all remaining width
      gridWrapper.add(grid, new HorizontalLayoutData(1.0, 1.0));
    }

    return root;
  }

  @Override
  public void onModuleLoad() {
    RootPanel.get().add(asWidget());
  }
}

存在一些问题(锁定列和未锁定列之间没有界线,锁定列标题菜单上下文图标有点不合适),但它涵盖了大部分细节而没有太多麻烦,并且几乎所有细节都对配置 - 最后想要锁?只需移动修改 - 想要多个锁定的列?只需添加更多到lockedCm.

There are a handful of issues (no line between locked and unlocked column, locked column header menu context icon is slightly out of place), but it covers most of the details without much hassle, and leaves almost all of it open to configuration - want the lock at the end? Just move the modifications around - want more than one locked column? just add more to the lockedCm.

这篇关于如何在 GXT 3.x 中实现冻结列?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆