我有一个LineChart
,其中Y轴设置为自动范围。由于NumberAxis.autoRange()
卡在无限循环中,JavaFx线程偶尔会挂起。工作线程生成的新数据,然后每隔几秒就添加到图表(在JFX线程上)。无限循环发生在此代码中(取自NumberAxis.autoRange()
):
for (double major = minRounded; major <= maxRounded; major += tickUnitRounded, count ++) {
double size = side.isVertical() ? measureTickMarkSize(major, getTickLabelRotation(), formatter).getHeight() :
measureTickMarkSize(major, getTickLabelRotation(), formatter).getWidth();
if (major == minRounded) { // first
last = size/2;
} else {
maxReqTickGap = Math.max(maxReqTickGap, last + 6 + (size/2) );
}
}
从调试开始,每次都看到if (major == minRoundeed)
条件为true
。因此,major
变量不得更新。
我没有带有本地变量调试信息的NumberAxis
类的编译版本,所以我看不到局部变量是什么。构建JavaFX Runtime类似乎需要做很多工作,但可能是下一步。
我无法可靠地重现此问题,因此无法提供Minimal, Complete, and Verifiable example。我没有在Oracle或OpenJDK错误数据库中记录任何问题。
JDK版本:8u60
编辑:
我向Oracle报告了这个错误,目前正在等待他们接受它。
答案 0 :(得分:1)
意味着循环将依赖于双值。因此,如果您尝试为minValue和maxValue采用如此小的double值,它将失败。
对我而言,这不像是一个错误。你可以问自己,如果你真的想在轴上显示如此大的分数,或者你能更好地扩展它们吗?您的应用程序的用户可能更乐意阅读基于轴标签的基础,而不是0.00000000000000000000000000000000000000015或1.5E-33?
在整个Java API中还有更多的东西也会发生这种情况,因为它是一个简单的数字溢出。
这将证明,如果值太小,它将循环无限。
import javafx.geometry.Side;
public class AutoRangeTester {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
AutoRangeTester art = new AutoRangeTester();
art.autoRange(Double.MIN_VALUE, Double.MIN_VALUE + 0.000000000000000000000000000000001, 100, 50);
}
/**
* Called to set the upper and lower bound and anything else that needs to be
* auto-ranged
*
* @param minValue The min data value that needs to be plotted on this axis
* @param maxValue The max data value that needs to be plotted on this axis
* @param length The length of the axis in display coordinates
* @param labelSize The approximate average size a label takes along the axis
*
* @return The calculated range
*/
public Object autoRange(double minValue, double maxValue, double length,
double labelSize) {
final Side side = Side.LEFT;
// check if we need to force zero into range
if (true) {
if (maxValue < 0) {
maxValue = 0;
} else if (minValue > 0) {
minValue = 0;
}
}
final double range = maxValue - minValue;
// pad min and max by 2%, checking if the range is zero
final double paddedRange = (range == 0) ? 2 : Math.abs(range) * 1.02;
final double padding = (paddedRange - range) / 2;
// if min and max are not zero then add padding to them
double paddedMin = minValue - padding;
double paddedMax = maxValue + padding;
// check padding has not pushed min or max over zero line
if ((paddedMin < 0 && minValue >= 0) || (paddedMin > 0 && minValue <= 0)) {
// padding pushed min above or below zero so clamp to 0
paddedMin = 0;
}
if ((paddedMax < 0 && maxValue >= 0) || (paddedMax > 0 && maxValue <= 0)) {
// padding pushed min above or below zero so clamp to 0
paddedMax = 0;
}
// calculate the number of tick-marks we can fit in the given length
int numOfTickMarks = (int) Math.floor(length / labelSize);
// can never have less than 2 tick marks one for each end
numOfTickMarks = Math.max(numOfTickMarks, 2);
// calculate tick unit for the number of ticks can have in the given data range
double tickUnit = paddedRange / (double) numOfTickMarks;
// search for the best tick unit that fits
double tickUnitRounded = 0;
double minRounded = 0;
double maxRounded = 0;
int count = 0;
double reqLength = Double.MAX_VALUE;
// loop till we find a set of ticks that fit length and result in a total of less than 20 tick marks
while (reqLength > length || count > 20) {
int exp = (int) Math.floor(Math.log10(tickUnit));
final double mant = tickUnit / Math.pow(10, exp);
double ratio = mant;
if (mant > 5d) {
exp++;
ratio = 1;
} else if (mant > 1d) {
ratio = mant > 2.5 ? 5 : 2.5;
}
tickUnitRounded = ratio * Math.pow(10, exp);
minRounded = Math.floor(paddedMin / tickUnitRounded) * tickUnitRounded;
maxRounded = Math.ceil(paddedMax / tickUnitRounded) * tickUnitRounded;
count = 0;
for (double major = minRounded; major <= maxRounded; major
+= tickUnitRounded, count++) {
System.out.println("minRounded: " + minRounded);
System.out.println("maxRounded: " + maxRounded);
System.out.println("major: " + major);
System.out.println("tickUnitRounded: " + tickUnitRounded);
System.out.println("-------------------------------------");
}
}
return null;
}
}
错误报告:https://bugs.openjdk.java.net/browse/JDK-8136535 计划针对版本9进行修复。