创建可滚动的XYChart - 遇到截止问题

时间:2015-02-13 00:15:29

标签: java charts javafx

我正在尝试创建一个可滚动的XYChart(实际上是pannable,但由于ScrollPane提供了setPannable(boolean pannable)函数,它们实际上是等效的)。我使用的XYChart类型是蜡烛图表,它与rterp @ Github发布的代码基本相同,可在此处获取:

StockChartsFX

我发现,这本身似乎主要来自Ensemble8。

最初的设置:

CandleStickChart扩展了XYChart扩展图表

然后我意识到XYChart没有暴露足够的数据以便能够真正搞乱图表的功能,所以我创建了一个ScrollableXYChart类,因为我已经走了那么远,所以决定创建一个MultiChart类作为好吧,以防万一我需要达到那个级别(它不仅滚动我正在实施,我也在实现工具栏和其他类似的东西,但目前不需要帮助)。 ScrollableXYChart和MultiChart分别是从XYChart和Chart中复制粘贴的(来自Java 8u40 ea 23)。

为了使图表内容可滚动,我做了以下内容:

private ScrollPane plotAreaScrollPane = new ScrollPane();

public ScrollableXYChart(Axis<X> xAxis, Axis<Y> yAxis)
{
    ...
    plotAreaScrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS);
    plotAreaScrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS);
    plotAreaScrollPane.setPannable(true);
    plotAreaScrollPane.setPrefSize(800, 600);
    plotAreaScrollPane.setContent(plotArea);
    getChartChildren().addAll(plotBackground, plotAreaScrollPane, xAxis, yAxis);
    ...
}

在执行该操作后,图表内容位于ScrollPane中,并且宽度看起来正确缩放到图表,唯一的问题是,当向右滚动时,蜡烛不会呈现。我注意到调整应用程序窗口的大小会强制绘制更多蜡烛,所以我想如果我在layoutChartChildren(...)内设置宽度会强制绘制更多蜡烛。它似乎确实如此,但这样做会使ScrollPane不可滚动(滚动条的水平缩略图变为条形的整个宽度)。

在查看CandleStickChart的layoutPlotChildren(...)方法后,我意识到它正在迭代数据,如下所示:

Iterator<Data<String, Number>> iter = getDisplayedDataIterator(series);
while (iter.hasNext())
{
    // draw candle
}

所以,为了减少抽取的蜡烛数量,我将其替换为:

int candleIndex = 0;

for (Data<String, Number> datum: getData().get(seriesIndex).getData())
{
    // draw candle
}

但这并没有改变任何事情。

以下是一些屏幕截图(是的,有更多的数据比显示的更多......我试过5000+蜡烛)确定:

Candles are shown No candles when scrolled

非常感谢。

更新

经过一番思考和研究后,我将CandleStickChart从XYChart<String, Number>更改为XYChart<Number, Number>这样做允许我通过setLowerBound(...)和{设置x轴的边界{1}} setUpperBound(...)中的方法。通过访问这些新方法,我试图在ScrollPane的ValueAxis<Number>上添加以下更改侦听器:

hvalueProperty

...

private double lastHoffset = 0d;

希望,我试着看看发生了什么。但是,没有(可见)变化。

更新的 我能够通过修补几乎所有可能的设置来实现它......我仍然不确定哪种设置组合使其起作用,但它涉及评论plotAreaScrollPane.hvalueProperty().addListener((observableValue, oldValue, newValue) -> { double hmin = plotAreaScrollPane.getHmin(); double hmax = plotAreaScrollPane.getHmax(); double hvalue = plotAreaScrollPane.getHvalue(); double contentWidth = plotAreaScrollPane.getContent().getLayoutBounds().getWidth(); double viewportWidth = plotAreaScrollPane.getViewportBounds().getWidth(); double hoffset = Math.max(0, contentWidth - viewportWidth) * (hvalue - hmin) / (hmax - hmin); double dHoffset = hoffset - lastHoffset; lastHoffset = hoffset; xAxis.setAutoRanging(false); xAxis.setAnimated(false); getXAxis().setLowerBound(getxAxis().getLowerBound() + hoffset); getXAxis().setUpperBound(getxAxis().getUpperBound() + hoffset); }); 并设置:

plotArea.setClip(plotAreaClip);

为:

    plotArea.setAutoSizeChildren(false);
    plotContent.setAutoSizeChildren(false);

    plotArea.setAutoSizeChildren(true);
    plotContent.setAutoSizeChildren(true);

为:

    plotContent.setManaged(false);
    plotArea.setManaged(false);

不知怎的,这使它有效。比我更聪明的人可以解释为什么,以及哪些设置确实是必要的,以及更改这些设置的(可能是负面的)含义是什么,因为我确信作者将它们放在那里是有充分理由的。

0 个答案:

没有答案