为什么我的JavaFX进度指示器没有更新?

为什么我的JavaFX进度指示器没有更新?,javafx,javafx-8,Javafx,Javafx 8,我的JavaFX应用程序中有以下布局 StackPane - BorderPane - Text (on Top) - Vbox (on Center) - ProgressIndicator - Label - BorderPane - Scroll Pane (with Tile Pane inside) (Center of Border Pane) - Button (Bottom of Bo

我的JavaFX应用程序中有以下布局

StackPane
   - BorderPane 
    - Text (on Top) 
    - Vbox (on Center)
        - ProgressIndicator
        - Label
   - BorderPane
        - Scroll Pane (with Tile Pane inside) (Center of Border Pane)
        - Button (Bottom of Border)

   - BorderPane
     - Vbox (on Center)
       - Progress Indicator
       - Label
     - Button ( Bottom)
显示第一个边框窗格时,进度指示器工作正常。我使用以下代码设置它

progress.progressProperty().bind(iconLoadTask.progressProperty());
progresspane.visibleProperty().bind(iconLoadTask.runningProperty());
当iconLoadTask完成时,进度窗格将不可见,并且下一个窗格将正确显示

在下一个边框窗格(有滚动窗格)中,我显示最后一个边框窗格(带有进度指示器-不确定)。这个进度指示器根本没有动画

编辑:

正如我所建议的,我试图复制这个问题

我有以下控制器文件。在这里您可以看到两个进度指示器(progress和stopProfInd)。从任务appLoadTask更新进度。这是一个有限的任务,我可以从任务中更新进度。这个很好用

我有另一个指示器叫stopProfInd。这在场景生成器中设置为不确定。在这里,您可以看到我使该窗格可见。我希望指示器能够动画化,但事实并非如此

public class AppController
    implements Initializable {

@FXML
private StackPane stackpaneapps;

@FXML
private BorderPane progresspane;

@FXML
private ProgressIndicator progress;

@FXML
private ProgressIndicator stopProfInd;

@FXML
private BorderPane profilingpane;

@FXML
private Label devicename;

private ObservableValue<Number> profProperty;

// Reference to the main application.
private Main mainApp;

private AppIconsTask appLoadTask;

private ProfilingTask prTask;

private Queue<MyVbox> clickedAppQueue;

@Override // This method is called by the FXMLLoader when initialization is complete
public void initialize(URL fxmlFileLocation, ResourceBundle resources) {
    clickedAppQueue = new LinkedList<MyVbox>();
}
/**
 * Is called by the main application to give a reference back to itself.
 *
 * @param mainApp
 */
public void setMainApp(Main mainApp) {
    this.mainApp = mainApp;
}

/**
 * Is called by the main application to give a reference back to itself.
 *
 * @param task
 *
 */
public void setAppLoadTask(AppIconsTask task) {
    this.appLoadTask = task;
    progress.progressProperty().bind(appLoadTask.progressProperty());
    progresspane.visibleProperty().bind(appLoadTask.runningProperty());
    appLoadTask.setOnSucceeded(t -> drawAppIcons(appLoadTask.getApps()));
    profilingpane.setVisible(false);
}


void drawAppIcons(ObservableList<App> apps){
    progress.setVisible(false);
    profilingpane.setVisible(true);

    prTask = new ProfilingTask();
    stopProfInd.progressProperty().bind(prTask.progressProperty());
    new Thread(prTask).start();
}
}
在这里复制这个问题,

所以,这可能是我的无知,也可能是一个bug

在我的代码中,而不是在下面的行中

profilingpane.setVisible(true);
我使用下面的方法,问题就消失了。这更像是解决问题的一种手段

profilingpane.setOpacity(0.0);
然后当我想让窗格显示时

profilingpane.setOpacity(1.0);

在撰写本文时,我认为您遇到了最新的GA发行版(JDK 8u20)中修复的问题。如果可能的话,最简单的修复方法是升级到并需要该版本

如果不能这样做,下一个最直观的选择是避免使用
setVisible(…)
,并在需要时将进度指示器添加到场景图中。可以使用在FXML中定义场景图中不包含的元素。像往常一样注入该元素,然后根据需要将该元素添加到场景图中。(如果需要,可以以类似的方式将其删除。)

您的FXML文件变为:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.effect.*?>
<?import javafx.scene.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<AnchorPane prefHeight="263.0" prefWidth="304.0"
    xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
    fx:controller="com.stackoverflow.repro.controller.AppController">
    <children>
        <StackPane fx:id="stackpaneapps" AnchorPane.bottomAnchor="0.0"
            AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0"
            AnchorPane.topAnchor="10.0">
            <children>
                <BorderPane fx:id="progresspane" prefHeight="200.0"
                    prefWidth="200.0">
                    <center>
                        <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0"
                            BorderPane.alignment="CENTER">
                            <children>
                                <ProgressIndicator fx:id="progress" maxHeight="100.0"
                                    maxWidth="100.0" prefHeight="68.0" prefWidth="77.0" />
                            </children>
                        </VBox>
                    </center>
                </BorderPane>
            </children>

        </StackPane>
    </children>
    <fx:define>
        <BorderPane prefHeight="200.0" prefWidth="200.0" fx:id="profilingpane">
            <center>
                <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0"
                    BorderPane.alignment="CENTER">
                    <children>
                        <ProgressIndicator fx:id="stopProfInd" />
                    </children>
                </VBox>
            </center>
        </BorderPane>
    </fx:define>
</AnchorPane>
您的不透明性解决方案也可以,但这感觉更自然。在功能上有一点不同,这在
堆栈窗格中的所有内容中并不明显。使用
setVisible
(当它正常工作时)和
setOpacity(…)
解决方法时,进度指示器将占用布局中的空间。在需要时添加和删除它,当它不存在时,它不会占用布局中的空间。因此,方法的选择可能取决于您希望它在布局方面的表现

关于您的代码,还有几个其他注释:

如果将运行
prTask
的线程设置为守护进程线程,则在关闭最后一个窗口时不会阻止JVM退出。显然,在您的真实应用程序中,您可能有其他机制来关闭此功能,但这可能是一个有用的技巧(如果您正在Eclipse中测试此功能,则不会那么烦人……):

此外,分析任务中的线程代码看起来不太正确。
stopProf
字段几乎肯定会在不同的线程上更改为读取该字段的线程。这意味着无法保证字段的活跃性(在一个线程中更改字段和在另一个线程中可见更改之间可能存在任意延迟,可能是不确定的)。您应该执行以下操作之一:

  • 将字段标记为易变
  • ,或
  • getStopProf()
    setStopProf(…)
    方法标记为
    synchronized
    ,或
  • boolean
    字段替换为
    AtomicBoolean
    第三个选项是我更喜欢的(喜欢高级API而不是低级原语):

    package com.stackoverflow.repo.tasks;
    导入java.util.concurrent.AtomicBoolean;
    导入javafx.concurrent.Task;
    /**
    *由karthik于2015年2月17日创建。
    */
    公共类ProfilingTask扩展了任务{
    原子晶体;
    @凌驾
    受保护的Void调用()引发异常{
    双f=1.0;
    而(!getStopProf()){
    睡眠(30);
    }
    返回null;
    }
    公共布尔getStopProf(){
    返回stoptrof.get();
    }
    公共无效设置topprof(布尔停止){
    停止设置(停止);
    }
    }
    
    如果没有这些代码,就很难找到线索。@ItachiUchiha在设置ProgressIndicators progressProperty的地方添加了一些代码。这样可以回答您的问题。创建一个绝对最小的执行和复制问题的东西,并编辑您的问题以包含它。@jewelsea添加了控制器代码。我将添加FXML工具,这样您就不必花时间创建一个示例来演示这个问题,但您希望人们自愿花时间浏览您的代码并猜测您没有发布的部分,以便帮助您解决问题?祝你好运,这太糟糕了。你在浪费每个关心帮助你的人的时间。而这种黑客行为对任何遇到类似问题的人都没有帮助。@Roland.抱歉。昨天我真的很沮丧,因为我已经尝试了4-5个小时的问题,并且在一些任务上落后了。我添加了包含完整源代码的链接。请看一看。@Hi James_D,谢谢你详尽的回答。是的,你是对的,我确实在使用1.8_u05时隐藏了错误。我升级到1.8_u31,bug消失了。尽管如此,我还是很喜欢你关于使用fx:define的建议。我将继续并更改我的实现。感谢您指出原子布尔的用法。还有一件事需要改变:)
    profilingpane.setOpacity(0.0);
    
    profilingpane.setOpacity(1.0);
    
    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.geometry.*?>
    <?import javafx.scene.text.*?>
    <?import javafx.scene.paint.*?>
    <?import javafx.scene.effect.*?>
    <?import javafx.scene.*?>
    <?import javafx.scene.image.*?>
    <?import javafx.scene.control.*?>
    <?import java.lang.*?>
    <?import javafx.scene.layout.*?>
    
    <AnchorPane prefHeight="263.0" prefWidth="304.0"
        xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
        fx:controller="com.stackoverflow.repro.controller.AppController">
        <children>
            <StackPane fx:id="stackpaneapps" AnchorPane.bottomAnchor="0.0"
                AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0"
                AnchorPane.topAnchor="10.0">
                <children>
                    <BorderPane fx:id="progresspane" prefHeight="200.0"
                        prefWidth="200.0">
                        <center>
                            <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0"
                                BorderPane.alignment="CENTER">
                                <children>
                                    <ProgressIndicator fx:id="progress" maxHeight="100.0"
                                        maxWidth="100.0" prefHeight="68.0" prefWidth="77.0" />
                                </children>
                            </VBox>
                        </center>
                    </BorderPane>
                </children>
    
            </StackPane>
        </children>
        <fx:define>
            <BorderPane prefHeight="200.0" prefWidth="200.0" fx:id="profilingpane">
                <center>
                    <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0"
                        BorderPane.alignment="CENTER">
                        <children>
                            <ProgressIndicator fx:id="stopProfInd" />
                        </children>
                    </VBox>
                </center>
            </BorderPane>
        </fx:define>
    </AnchorPane>
    
    package com.stackoverflow.repro.controller;
    
    
    import java.io.IOException;
    import java.net.URL;
    import java.util.ResourceBundle;
    
    import com.stackoverflow.repro.Main;
    import com.stackoverflow.repro.tasks.AppIconsTask;
    import com.stackoverflow.repro.tasks.ProfilingTask;
    
    import javafx.fxml.FXML;
    import javafx.fxml.FXMLLoader;
    import javafx.fxml.Initializable;
    import javafx.scene.control.Label;
    import javafx.scene.control.ProgressIndicator;
    import javafx.scene.layout.*;
    
    
    public class AppController
            implements Initializable {
    
        @FXML
        private StackPane stackpaneapps;
    
        @FXML
        private BorderPane progresspane;
    
        @FXML
        private ProgressIndicator progress;
    
        @FXML
        private ProgressIndicator stopProfInd;
    
        @FXML
        private BorderPane profilingpane;
    
        // Reference to the main application.
        private Main mainApp;
    
        private AppIconsTask appLoadTask;
    
        private ProfilingTask prTask;
    
    
        @Override // This method is called by the FXMLLoader when initialization is complete
        public void initialize(URL fxmlFileLocation, ResourceBundle resources) {
        }
        /**
         * Is called by the main application to give a reference back to itself.
         *
         * @param mainApp
         */
        public void setMainApp(Main mainApp) {
            this.mainApp = mainApp;
        }
    
        /**
         * Is called by the main application to give a reference back to itself.
         *
         * @param task
         *
         */
        public void setAppLoadTask(AppIconsTask task) {
            this.appLoadTask = task;
            progress.progressProperty().bind(appLoadTask.progressProperty());
            progresspane.visibleProperty().bind(appLoadTask.runningProperty());
    //        profilingpane.setVisible(false);
            appLoadTask.setOnSucceeded(t -> drawAppIcons());
    
        }
    
    
        void drawAppIcons(){
    //        profilingpane.setVisible(true);
            stackpaneapps.getChildren().add(profilingpane);
            prTask = new ProfilingTask();
            new Thread(prTask).start();
        }
    }
    
        Thread prThread = new Thread(prTask);
        prThread.setDaemon(true);
        prThread.start();
    
    package com.stackoverflow.repro.tasks;
    
    import java.util.concurrent.atomic.AtomicBoolean;
    
    import javafx.concurrent.Task;
    
    /**
     * Created by karthik on 17/02/15.
     */
    public class ProfilingTask extends Task<Void> {
    
        AtomicBoolean stopProf;
        @Override
        protected Void call() throws Exception {
            double f = 1.0;
            while(!getStopProf()){
                Thread.sleep(30);
    
            }
            return null;
        }
        public boolean getStopProf(){
            return stopProf.get();
        }
    
        public void setStopProf(boolean stop){
            stopProf.set(stop);
        }
    }