Java 如何在GXT 3.x中实现冻结列?

Java 如何在GXT 3.x中实现冻结列?,java,gwt,extjs,gxt,Java,Gwt,Extjs,Gxt,如何在GXT 3.x(来自Sencha)中实现冻结列?Sencha的另一个产品Ext JS似乎实现了这一点,但我看不出基于Java的GXT在哪里实现了同样的东西: GXT中没有实现该功能,但是有一个名为的用户,他在GXT中解决了这个问题。我还没试过,但我希望它能帮助你 基本思想是需要两个不同的滚动容器,一个带有固定列,一个带有滚动列。其中每一个都需要在一个不同的视口中,因此标准的Grid/GridView不能很好地处理这个问题——它们假设滚动应该如何进行,因此简单地对其中一个或两个进行子类化可能

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


GXT中没有实现该功能,但是有一个名为的用户,他在GXT中解决了这个问题。我还没试过,但我希望它能帮助你


基本思想是需要两个不同的滚动容器,一个带有固定列,一个带有滚动列。其中每一个都需要在一个不同的视口中,因此标准的Grid/GridView不能很好地处理这个问题——它们假设滚动应该如何进行,因此简单地对其中一个或两个进行子类化可能会相当复杂

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

为了充分发挥作用,需要一些额外的接线:

  • 链接滚动。收听每个网格中的
    BodyScrollEvent
    ,并将另一个滚动到相同的位置(仅更改
    top
    ,而不是
    left
    ,因为您不希望其中一个控制另一个)
  • 调整大小是第二个大问题——两个网格的可滚动高度必须相同,但水平滚动网格在实际显示滚动条时,底部需要一个缓冲区。通常,网格会根据其父级的指示调整大小,尽管有时您会直接调整网格的大小-在这种情况下,不需要此步骤,只需调整两个网格的大小稍微不同即可。否则,您将需要构造布局以正确配置它
  • 最后,锁定的列需要隐藏其垂直滚动条-用户无需看到两个垂直滚动条
这涵盖了基本用例,但不涉及诸如alternate
GridView
实现-
GroupingView
之类的内容,子类将需要链接扩展(并隐藏组标题,使其不会出现两次,另外还要处理这样一个事实,即当下半部分横向滚动时,组行不应被拆分),
TreeGridView
TreeGrid
需要链接展开的节点,并从第二个网格隐藏树+/-图标

下面是应用于基本网格示例的一组基本修改。为了避免混淆问题,我删除了该网格中的许多其他功能,例如工具提示和更改选择模型:

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());
  }
}
公共类GridExample实现了IsWidget入口点{ 私有静态最终StockProperties props=GWT.create(StockProperties.class); 私有ContentPanel根目录; @凌驾 公共小部件asWidget(){ if(root==null){ 最终NumberFormat编号=NumberFormat.getFormat(“0.00”); ColumnConfig nameCol=new ColumnConfig(props.name(),50,SafeHtmlUtils.fromTrustedString(“公司”); ColumnConfig symbolCol=newColumnConfig(props.symbol(),100,“symbol”); ColumnConfig lastCol=newColumnConfig(props.last(),75,“last”); ColumnConfig changeCol=newColumnConfig(props.change(),100,“change”); changeCol.setCell(新的AbstractCell(){ @凌驾 公共void呈现(上下文上下文、双值、安全HtmlBuilder sb){ String style=“style=”color:“+(值<0?”红色):“绿色”)+”; 字符串v=数字。格式(值); sb.附加恒量(“+v+”); } }); ColumnConfig lastTransCol=新的ColumnConfig(props.lastTrans(),100,“上次更新”); lastTransCol.setCell(新的DateCell(DateTimeFormat.getFormat(“MM/dd/yyyy”)); 列表l=新的ArrayList(); //从主列集中删除名称 //l.add(nameCol); l、 添加(symbolCol); l、 添加(lastCol); l、 添加(changeCol); l、 添加(lastTransCol); //创建两个柱模型,一个用于锁定截面 ColumnModel lockedCm=新的ColumnModel(Collections.singletonList(nameCol)); ColumnModel cm=新ColumnModel(l); ListStore=新的ListStore(props.key()); store.addAll(TestData.getStocks()); root=newcontentpanel(); root.setHeadingText(“锁定网格示例”); root.setPixelSize(600300); 最终可调整大小Resizable=新的可调整大小(root、Dir.E、Dir.SE、Dir.S); addExpandHandler(新的ExpandHandler()){ @凌驾 public void onExpand(ExpandEvent事件){ 可调整大小。设置已启用(true); } }); root.addCollapseHandler(新的CollapseHandler(){ @凌驾 公共空间崩塌(崩塌事件){ 可调整大小。设置已启用(false); } }); //锁定网格 最终网格锁定网格=新网格(存储,锁定CM){ @凌驾 受保护大小调整大小(大小){ //这是一个棘手的部分-说服网格绘制稍微太宽 //所以把滚动条推到看不见的地方 返回新的大小(Size.getWidth()+XDOM.getScrollBarWidth()-1,Size.getHeight()); } }; setView(新的GridView(){{ 这个.scrollOffset=0; }}); //要求列始终适合,防止滚动条 lockedGrid.getView().setForceFit(true); //主栅格,带水平滚动条 最终网格=新网格(存储,厘米); //不希望使用此功能,希望鼓励使用水平滚动条 //grid.getView().setAutoExpandColumn(nameCol); grid.getView().setStripeRows(true); grid.getView().setColumnLines(true); 表格1.订单(假); grid.setColumnReordering(true); grid.setStateful(true); G