簡體   English   中英

javafx:大規模設置值時,標簽值更新會導致錯誤

[英]javafx: label value updates cause error when massively setting values

我用javafx ui編寫了一個Java程序來顯示實時的事務計數器,許多線程需要將更新的值寫入單個標簽,我這樣做是:

1-“ SOME_NUMBER”是主類中的一個整數變量(不是fx控制器類本身,讓我們考慮其名稱“ MainClass”),它定義了這種方式:

public static Integer SOME_NUMBER;

2個線程以這種方式更新“ SOME_NUMBER”的值:

synchronized(SOME_NUMBER){
    MainClass.SOME_NUMBER--;
}
synchronized(SOME_NUMBER){
    MainClass.SOME_NUMBER++;
}

3-最后,結果將以這種方式顯示在其他類中:

label.setText(String.valueOf(SOME_NUMBER));

數字應該每秒更新一次,所以我不想使用Task在特定的間隔內更新我的視圖,並且也不想使用Platform.runLater因為當您每秒大約有5-20個事務時,它會顯示他們有相當長的延遲...所以我想要一種安全的方法來實現這種事情以滿足我的需求,因為我當前的實現會導致此類錯誤,因此我刪除了ui更新,所有這些都消失了:

> java.lang.NullPointerException
    at com.sun.javafx.text.PrismTextLayout.createLine(Unknown Source)
    at com.sun.javafx.text.PrismTextLayout.layout(Unknown Source)
    at com.sun.javafx.text.PrismTextLayout.ensureLayout(Unknown Source)
    at com.sun.javafx.text.PrismTextLayout.getBounds(Unknown Source)
    at javafx.scene.text.Text.getLogicalBounds(Unknown Source)
    at javafx.scene.text.Text.getYRendering(Unknown Source)

有沒有機會使用可觀察的值或類似的值?

如果您不想使用Task ,只需對復制和粘貼進行少量修改即可使用與Task使用的相同技術(以下代碼只是從Task來源進行復制和粘貼)。

如果您知道您的值是一個Integer,那么您可能希望使用AtomicInteger而不是AtomicReference

該代碼將為您提供一個message屬性,您可以嘗試從任何線程(通過updateMessage API)更新其值,盡管僅當JavaFX應用程序線程已准備好對其進行處理時才會進行更新。 您還可以觀察屬性的變化,並將JavaFX UI組件安全地綁定到該屬性,知道該屬性本身甚至只在JavaFX應用程序線程上進行了更新。

/**
 * Used to send message updates in a thread-safe manner from the subclass
 * to the FX application thread. AtomicReference is used so as to coalesce
 * updates such that we don't flood the event queue.
 */
private AtomicReference<String> messageUpdate = new AtomicReference<>();

private final StringProperty message = new SimpleStringProperty(this, "message", "");
@Override public final String getMessage() { checkThread(); return message.get(); }
@Override public final ReadOnlyStringProperty messageProperty() { checkThread(); return message; }

/**
 * Updates the <code>message</code> property. Calls to updateMessage
 * are coalesced and run later on the FX application thread, so calls
 * to updateMessage, even from the FX Application thread, may not
 * necessarily result in immediate updates to this property, and
 * intermediate message values may be coalesced to save on event
 * notifications.
 * <p>
 *     <em>This method is safe to be called from any thread.</em>
 * </p>
 *
 * @param message the new message
 */
protected void updateMessage(String message) {
    if (isFxApplicationThread()) {
        this.message.set(message);
    } else {
        // As with the workDone, it might be that the background thread
        // will update this message quite frequently, and we need
        // to throttle the updates so as not to completely clobber
        // the event dispatching system.
        if (messageUpdate.getAndSet(message) == null) {
            runLater(new Runnable() {
                @Override public void run() {
                    final String message = messageUpdate.getAndSet(null);
                    Task.this.message.set(message);
                }
            });
        }
    }
}

private void checkThread() {
    if (started && !isFxApplicationThread()) {
        throw new IllegalStateException("Task must only be used from the FX Application Thread");
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM