我正在尝试创建一个可滚动的XYChart(实际上是pannable,但由于ScrollPane提供了setPannable(boolean pannable)
函数,它们实际上是等效的)。我使用的XYChart类型是蜡烛图表,它与rterp @ Github发布的代码基本相同,可在此处获取:
我发现,这本身似乎主要来自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+蜡烛)确定:
非常感谢。
更新
经过一番思考和研究后,我将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);
不知怎的,这使它有效。比我更聪明的人可以解释为什么,以及哪些设置确实是必要的,以及更改这些设置的(可能是负面的)含义是什么,因为我确信作者将它们放在那里是有充分理由的。