【问题标题】:NatTable mix of fixed width column and on resizable filling remaining spaceNatTable 混合固定宽度的列和可调整大小的填充剩余空间
【发布时间】:2017-10-10 11:13:59
【问题描述】:

如何制作一个 Nebula NatTable,其中混合了固定列和剩余的一个填充所有可用的垂直空间,以及最重要的是,用户可以调整固定宽度列的大小?

视觉示例:

+-----------------------------------------+-------+-------+
|     ...fills available vert space...    | 100px | 100px |

用户通过将第 0 列和第 1 列之间的边框向左推来调整中间列的大小:

+---------------------------------------+----------+-------+
|     ...fills available vert space...  |   120px  | 100px |

用户通过将第 1 列和第 2 列之间的边框向左推来调整第 3 列的大小:

+------------------------------------+----------+----------+
|   ...fills available vert space... |   120px  |   120px  |

我非常接近这段代码:

    IRowDataProvider<String> bodyDataProvider = ...;
    DataLayer bodyDataLayer = new DataLayer(bodyDataProvider);
    SelectionLayer selectionLayer = new SelectionLayer(bodyDataLayer, false);
    ViewportLayer viewportLayer = new ViewportLayer(selectionLayer);

    bodyDataLayer.setColumnPercentageSizing(0, true);
    bodyDataLayer.setColumnPositionResizable(0, true);

    bodyDataLayer.setColumnWidthByPosition(1, 100);
    bodyDataLayer.setColumnPositionResizable(1, true);

    bodyDataLayer.setColumnWidthByPosition(2, 100);
    bodyDataLayer.setColumnPositionResizable(2, true);

它在视觉上做了预期的事情,它也会对容器(Shell)按预期调整大小做出反应;即固定列保持 100px,只有第一列调整大小。到目前为止很好。但是有一个问题:列间调整大小发生了一些不好的事情。我只是反应奇怪。在第 0 列和第 1 列之间调整大小处理程序(标题边框)不做任何事情,只出现调整大小但不执行调整大小;在第 1 列和第 2 列之间调整大小的处理程序会做出反应,但只有第 1 列可以有效调整大小,第 2 列始终保持其大小,无论您做什么。

不良行为示例:您想调整第 2 列(第 3 列)的大小以使其更大;您抓住第 1 列和第 2 列之间的边界,将边界拖到 left 以通过有效地将第 1 列也向左推来使第 2 列变大。但相反,第 2 列保持不变,而第 1 列缩小!

更新

我的问题是如何实现所需的行为。我需要在哪里设置或重新实现什么?自定义SizeConfig?那里的方法听起来很有希望:calculatePercentages()calculateAvailableSpace()。谁和什么时候打电话给他们?如何捕获列调整大小事件?我需要在某处设置监听器吗?如何让 NatTable 使用自定义的SizeConfig? 我在正确的轨道上吗?

【问题讨论】:

  • 我为提到的(侧面)问题创建了一个错误报告:bugs.eclipse.org/bugs/show_bug.cgi?id=516625。我想知道为什么 NatTable 在默认设置下表现如此奇怪,为什么我的示例中的第一列使用 vanilla ColumnResizeCommandHandler 有效地无法调整大小。

标签: java swt nattable nebula


【解决方案1】:

我自己想通了。最后也没那么难。 所要做的就是注册一个自定义的ColumnResizeCommand 处理程序并实现它。

向NatTable创建代码块添加:

bodyDataLayer.registerCommandHandler(
     new BetweenColumnResizeCommandHandler(bodyDataLayer));

它可以在任何地方,我在定义列之后就有它

这会覆盖默认的BodyDataLayer 设置,该设置在方法中设置为默认类ColumnResizeCommandHandler。该寄存器是基于映射的,因此可以重复覆盖。寄存器将类命令类(表示事件)映射到给定层(事件/命令的终端消费者)的操作(处理程序)。

这是我对BetweenColumnResizeCommandHandler 类的实现:

import org.eclipse.nebula.widgets.nattable.command.AbstractLayerCommandHandler;
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
import org.eclipse.nebula.widgets.nattable.resize.command.ColumnResizeCommand;
import org.eclipse.nebula.widgets.nattable.resize.command.ColumnResizeCommandHandler;

/**
 * Customised version of {@link ColumnResizeCommandHandler}.
 * 
 * It implements "between" resizing mode, that is border is moved between two
 * adjacent column only, having no effects on any other columns; that is any
 * gain in size of the left side column is lost in size for right side column
 * and vice versa.
 * 
 * @author Espinosa
 */
public class BetweenColumnResizeCommandHandler extends AbstractLayerCommandHandler<ColumnResizeCommand> {

    private final DataLayer dataLayer;

    public BetweenColumnResizeCommandHandler(DataLayer dataLayer) {
        this.dataLayer = dataLayer;
    }

    @Override
    public Class<ColumnResizeCommand> getCommandClass() {
        return ColumnResizeCommand.class;
    }

    @Override
    protected boolean doCommand(ColumnResizeCommand command) {
        int leftSideColumn = command.getColumnPosition();
        int rightSideColumn = leftSideColumn + 1;

        int oldLeftSideColumnWidth = this.dataLayer.getColumnWidthByPosition(leftSideColumn);
        int newLeftSideColumnWidth = command.getNewColumnWidth();
        int dragWidth = newLeftSideColumnWidth - oldLeftSideColumnWidth;  
        // dragWidth has to be re-calculated back because it is lost in ColumnResizeCommandHandler :( 

        int oldRightSideColumnWidth = this.dataLayer.getColumnWidthByPosition(rightSideColumn);
        int newRightSideColumnWidth = oldRightSideColumnWidth - dragWidth;

        this.dataLayer.setColumnWidthByPosition(leftSideColumn, newLeftSideColumnWidth);
        if (rightSideColumn < this.dataLayer.getColumnCount()) {
            this.dataLayer.setColumnWidthByPosition(rightSideColumn, newRightSideColumnWidth);
        }
        return true;
    }
}

..它完全符合我的要求,如上例所示。

【讨论】:

  • 这正是我的答案。 :)
  • @Dirk 我不确定如果列重新排列、订单更改或列被隐藏,我的解决方案是否会起作用,仍然是rightSideColumn = leftSideColumn + 1 我也不知道如何正确使用GUIHelper.convertVerticalDpiToPixel()。请随时查看、评论、改进!
  • 当您在 DataLayer 上注册 IDragMode 并且 DataLayer 是层堆栈中最底层的层时,它不知道隐藏或重新排列的列。在上面的示例中,我没有看到GUIHelper.convertVerticalDpiToPixel() 的用法。 NatTable 在ColumnResizeDragMode 内部使用它来处理放大的显示分辨率,以根据 DPI 值计算像素值。不知道你需要它做什么。
【解决方案2】:

你的问题是你试图从右到左思考。但是调整大小是从左到右实现的。因此,如果您采用第 1 列和第 2 列之间的边界,则您正在调整第 1 列的大小,而不是第 2 列。方向无关紧要。

这是与众所周知的电子表格应用程序类似的行为。使用边框之间的句柄会将列的大小调整到左侧,而不是右侧。

【讨论】:

  • 感谢您的及时回复。我刚刚使用 LibreOffice Calc 和 SWT Tree 对其进行了测试,它们都在向左拖动边框时将左列 移动 到右侧,同时缩小左列。同样在我对电子表格的有限经验中,所有列实际上都是固定类型的列,所以类比是有限的。无论如何,这不是重点。请问我应该怎么做才能实现我想要的行为?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-03
  • 1970-01-01
  • 2012-09-25
  • 2017-01-12
  • 2013-09-28
  • 2011-12-20
  • 1970-01-01
相关资源
最近更新 更多