我以前遇到過這個問題,無論是在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的固定。 –