我以前遇到过这个问题,无论是在C#还是Java。我的解决方案,并不是说它是最好的解决方案,但似乎可行,就是使用某种形式的计时器来触发昂贵的重新计算。
在我的情况下,我在搜索文本框中使用了它,实际搜索只在用户未按下某个键一段时间(比如500ms)后触发,阻止触发搜索每个关键笔划。
在你的情况下,你可以在resize()方法中触发定时器。当定时器耗尽时,它执行昂贵的操作。当它已经在等待的时候触发定时器会导致定时器复位。
在java中,我通过使用定时器的java.util.Timer来完成此任务,然后运行我创建的java.util.TimerTask。在TimerTask的run()方法中,我创建了一个javafx.concurrent.Task并在新线程中运行它。 Task的call()方法是工作完成的地方。这确保了该工作在JavaFX线程上完成,否则您会遇到线程问题。
希望这对你有些帮助。
编辑...这里是一些代码,应该做我上面说的。 注:此代码是完全未经测试,我认为它应该工作,虽然
class ShapeCurvePlot extends Polyline {
private class ResizeTimerTask extends TimerTask {
private ShapeCurvePlot plot;
public ResizeTimerTask(ShapeCurvePlot plot) {
this.plot = plot;
}
/* (non-Javadoc)
* @see java.util.TimerTask#run()
*/
@Override
public void run() {
Task<Object> t = new Task<Object>() {
@Override
protected Object call() throws Exception {
// "expensive calculation"
Series series = plot.getSeries();
double xOffset = series.valueAxis().getLeft();
double yOffset = series.keyAxis().getLeft();
double yScale = height/series.keyAxis().range();
double xScale = width/series.valueAxis().range();
plot.getPoints().clear();
for (Map.Entry<Double, Double> item : series.data().entrySet()) {
double x = item.getValue();
double y = item.getKey();
plot.getPoints().addAll((x - xOffset) * xScale, (y - yOffset) * yScale);
}
}
}
new Thread(t).start();
}
}
private static int RESIZE_DELAY_MS = 1000;
private final CurvePlot model;
private Timer resizeTimer;
public ShapeCurvePlot(CurvePlot model) {
Objects.requireNonNull(model);
this.model = model;
strokeProperty().bind(model.strokeProperty());
strokeWidthProperty().bind(model.strokeWidthProperty());
}
@Override
public boolean isResizable() {
return true;
}
public Series getSeries() {
return this.model.getSeries();
}
@Override
public void resize(double width, double height) {
// cancel the current task (if any).
if(this.resizeTimer != null) {
this.resizeTimer.cancel();
this.resizeTimer.purge();
this.resizeTimer = null;
}
try {
// create a new task that will be executed in 1 second.
this.resizeTimer = new Timer();
this.resizeTimer.schedule(new ResizeTimerTask(this), RESIZE_DELAY_MS);
} catch (OutOfMemoryError oom) {
oom.printStackTrace();
if(this.resizeTimer != null) {
this.resizeTimer.cancel();
this.resizeTimer.purge();
this.resizeTimer = null;
}
}
}
}
进一步编辑...只是花了一些今天的JavaFX线程问题打的,还有另外一个选择,你可以用于在JavaFX显示线程中运行耗时的任务。您可以使用javafx.application.Platform.runLater(Runnable r)在JavaFX线程中执行Runnable,而不是使用Task。这将在未来的某个时间执行可运行的程序,其优点是以这种方式运行的所有可运行程序都按先进先出顺序处理。这可以方便地防止事情失序,同时仍然可以在JavaFX显示线程上以异步方式运行它们。
为了做到这一点,你会在ResizeTimerTask类的run()方法的实现更改为:
public void run() {
Platform.runLater(new Runnable() {
@Override
public void run() {
// "expensive calculation"
Series series = plot.getSeries();
double xOffset = series.valueAxis().getLeft();
double yOffset = series.keyAxis().getLeft();
double yScale = height/series.keyAxis().range();
double xScale = width/series.valueAxis().range();
plot.getPoints().clear();
for (Map.Entry<Double, Double> item : series.data().entrySet()) {
double x = item.getValue();
double y = item.getKey();
plot.getPoints().addAll((x - xOffset) * xScale, (y - yOffset) * yScale);
}
}
});
}
尝试重构你的问题,添加一些片段,并使其简单!我无法理解你的问题! – ItachiUchiha
@IchichiUchiha,用示例代码更新。我需要重新计算形状而不是缩放以保持strokeWidth的固定。 –