簡體   English   中英

JavaFX 進度條不更新

[英]JavaFX Progress Bar doesn't update

我已經搜索了所有其他問題,但沒有運氣。 四個多小時以來,我一直在嘗試不同的東西,但絕對沒有任何進展(或錯誤,這更令人沮喪),所以我想我最終會在這里問。

我正在開發一個小型生存游戲作為輔助項目,以自學更多有關 Java UI 元素的知識。 玩家尋找食物等,這是一場與飢餓和口渴的賽跑。 我的情況是這樣的:

游戲打開一個控制器(MainController),它有幾個指示角色統計數據的條; 對於這個例子,我們會說飢餓和口渴。

玩家可以點擊一個按鈕來打開角色的物品欄,其中包括他們的食物。 這會在新控制器 (InventoryController) 上打開一個新窗口,其中列出了與角色庫存項目對應的按鈕。

當玩家點擊食物時,角色的飢餓值會下降,並且相關的 ProgressBar 也應該會下降。

問題是:角色的內部飢餓統計數據下降,ProgressBar 的進度下降,進度條永遠不會在視覺上更新,即使它在內部發生了變化。

舉個簡單的例子:

public class MainController implements Initializable {

    @FXML private ProgressBar hungerBar;

    public void initialize(URL url, ResourceBundle rb) {
        updateBars();
    }    

    public void updateBars(){
        hungerBar.setProgress(CC.pc.getHunger()/100);
    }
}

首先起作用 它成功獲取角色的飢餓值,將其除以 100,然后設置條形(在本例中為 0.40)。 沒有問題。 欄出現並且已滿 40%。 但是,當我打開並使用第二個 Controller 時,沒有任何反應。

public class InventoryController implements Initializable {


    @Override
    public void initialize(URL url, ResourceBundle rb) {
    }    

    @FXML private void feedVenison(ActionEvent event) throws Exception{

        FXMLLoader loader = new FXMLLoader(getClass().getResource("Main.fxml"));
        loader.load();
        PlayController c = loader.<PlayController>getController();

        //Stuff that does the math and changes the character's stats here;
        //cut short for clarity.

        c.updateBars();
    }
}

我可以添加一些打印命令,例如 System.out.println(hungerBar.getProgress()),然后看到一切都運行良好。 角色的飢餓感會降低,反過來,進度條的進度也會更新,並且在功能上會降低。 但是,無論設置在 0.01 和 1 之間的哪個位置,條形圖都不會改變。

我已經嘗試了又嘗試,但我已經無能為力了! 我顯然做錯了什么,我確定這是顯而易見的,但我不知道是什么。 沒有錯誤,它只是不起作用。 我是否只是為這項工作使用了錯誤的工具? 什么給?

更新 1:

更多的挖掘讓我想到了這個問題,這與我想要做的非常相似。 不幸的是,它也沒有答案。 它有一條評論指向這個 Oracle 文檔,我試圖實現它。

public void updateBars(){

    DoubleProperty hunger = new SimpleDoubleProperty(CC.pc.getHunger());
    hungerBar.progressProperty().bind(hunger);

}

但再一次,我遇到了完全相同的問題。 條形在內部更新,但 UI 永遠不會改變並且總是顯示不正確的靜態數量。 我該怎么辦?

更新 2:

我一直在挖掘,但每次我認為我找到了答案時,它只是一遍又一遍地做同樣的事情。 嘗試了這個,但結果相同。

public void updateBars(){

    maybeWillWork();

}

public void maybeWillWork()
 {
    Platform.runLater(new Runnable() {
        @Override public void run() {
           hungerBar.setProgress(CC.pc.getHunger()/100);
           System.out.println("It ran!");
        }
    });
}

完全一樣的結果。

請。 我做錯了什么? 我拒絕相信像我這樣的簡單的 ProgressBar 難倒了整個 StackOverflow; 有人必須知道我犯了什么愚蠢的錯誤。

更新 3:

嗯,這令人沮喪,但我讓它工作了。 我已經在下面發布了答案。

你的方法做錯了什么

您在初始化控制器時更新該值,但您只是制作該值的“快照”。

即使您正在使用該屬性 ( Update 1 ),您也正在創建一個最初用當前值填充的獨立屬性,但存儲在該屬性中的值永遠不會更新。

但是您又在調用updateBars() ,對嗎? 您這樣做,但為此目的使用新的控制器實例創建了一個新場景,因此您無需調整顯示的場景,而是調整一些從未顯示的其他場景。

因此,更新永遠不會到達當前顯示的場景。

當然,您可以將現有控制器存儲在方便的位置並訪問它,但這樣可以增加程序的內聚力。

更好的方法是創建一個模型類並添加可觀察的屬性。 您只需創建此類的單個實例並將其傳遞到訪問它的任何地方。 通過觀察程序中對值“感興趣”的屬性部分可以更新自己:

public class Model {

    private final DoubleProperty hunger = new SimpleDoubleProperty();

    public DoubleProperty hungerProperty() {
        return hunger;
    }

    public void setHunger(double value) {
        hunger.set(value);
    }

    public double getHunger() {
        return hunger.get();
    }

}

模型實例可以通過這個問題中提到的方法之一傳遞給控制器​​: 傳遞參數 JavaFX FXML

例如

public class MainController {

    @FXML private ProgressBar hungerBar;

    public void setModel(Model model){
        hungerBar.progressProperty().bind(model.hungerProperty().divide(100d));
    }
}
public class InventoryController {

    @FXML private void feedVenison(ActionEvent event) throws Exception {
        model.setHunger(someNewValue);
    }

    private Model model;

    public void setModel(Model model){
        this.model = model;
    }
}

確保您使用自己的feedVenison方法中的方法將相同的Model實例傳遞給兩個控制器,但僅當您加載也顯示的場景時。 加載視圖並使用包含setModel方法的自定義接口的工廠可以幫助減少重復代碼......

注意:您也可以通過使用用於CC.pc的類中的屬性來實現這CC.pc ,但恕我直言,應避免使用靜態成員傳遞信息。

經過近八個小時的嘗試,我終於找到了問題所在。 現在,我坦率地承認我並不完全理解這如何工作的,或者為什么,但它確實像我希望的那樣發揮作用。 花了太多時間進行了數十次搜索,但我終於偶然發現了這個頁面。 他沒有直接更新標簽,而是使用了一種叫做“綁定”的東西。 嗯,那不一樣……當然,我不知道這是什么,但我挖了又挖,瞧……

酒吧需要綁定到一個DoubleProperty,然后將該得到.SET()的東西,它更新了吧。

我曾在更新 1 中使用過 DoubleProperty,但我忽略了嘗試使用 .set() 函數。 果然...

這就是最終對我有用的方法。

@FXML ProgressBar hungerBar;
static DoubleProperty hungerUpdater = new SimpleDoubleProperty(.0);
public void initialize(URL url, ResourceBundle rb) {
        hungerBar.progressProperty().bind(hungerUpdater);
    }    

我們創建一個新的DoubleProperty ,然后將我們希望更新的欄綁定到它。 后來,在同一個控制器上,我們有:

public void updateBars(){
    hungerUpdater.set(CC.pc.getHunger()/100);
}

我們獲取角色的飢餓值(介於 0 和 100 之間)並將其除以 100,從而得到介於 0 和 1 之間的小數。然后將其用於設置 HungerUpdater DoubleProperty。

在另一個控制器上,我們有:

public void initialize(URL url, ResourceBundle rb) {
}    

@FXML private void feedVenison(ActionEvent event) throws Exception{

    FXMLLoader loader = new FXMLLoader(getClass().getResource("Main.fxml"));
    loader.load();
    MainController c = loader.<MainController>getController();

    //Stuff that does the math and changes the character's stats here;
    //cut short for clarity.

    c.updateBars();
}
}

據我所知,這實質上是強制JavaFX 立即更新欄,因為欄正在積極偵聽此 Double 以進行更新。 一旦看到更新,程序就會更新它。

這是一個非常令人沮喪的夜晚,但我終於明白了。 我要去大喝,假裝我沒有在這么簡單的事情上這么努力,對許多人來說,可能很明顯。

問題:進度條采用 0 到 1 之間的參數,這意味着一個十進制值。 然而,Java 中的簡單除法返回一個不能保留小數的整數。

解決方案:將除法轉換為雙精度型

progressBar.setProgress((double)counter / 1000);

暫無
暫無

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

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