我目前正在尝试为我的程序创建一个启动屏幕,因为启动需要一些时间。问题是创建GUI需要一段时间(创建对话、更新表格等)。而且我不能将GUI创建移动到后台线程(如“Task”类),因为我会得到“Not on FXApplication thread”异常。我尝试使用:
Platform.runLater(new Runnable() {
public void run() {
//create GUI
}
}
以及任务的“调用”方法:
public class InitWorker extends Task<Void> {
private Model model;
private ViewJFX view;
public InitWorker(Model model) {
this.model = model;
}
@Override
protected Void call() throws Exception {
View view = new View();
Collection collection = new Collection();
//do stuff
}
}
当我在Swing中编写程序时,我可以在EventDispatchThread上显示和更新Splash屏幕,而无需任何真正的并发。代码如下所示:
public void build() {
MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Menus");
menuCreator = new MenuCreatorOld (model, this);
menuCreator.createMenu();
MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE, "Creating Toolbar");
toolBar = menuCreator.createToolBar();
createWesternPanelToolBar();
shoppingPanel = new ShoppingListOld(model, this, collectionController, shoppingController, controller);
centerTabbedPane = new JTabbedPane();
MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Collection");
collectionPanel = new CollectionOld(model, collectionController, this, controller);
MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Wish List");
wishPanel = new WishListOld(model, this, collectionController, wishController, controller);
MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Folders Table");
//and so on
}
public static void updateProgressBar(int progressValue, String text) {
System.out.println("Loading Bar Value:"+progressValue);
progressBar.setValue(progressValue);
loadingLabel.setText(text);
progressBar.setString(text);
}
有没有办法在后台创建GUI,同时显示带有加载栏的初始屏幕?
编辑:
我看了一下我的代码,能够将启动时间减少5秒。大多数对话框在创建时都会从数据库中提取数据。所以我将对话框的创建移到了他们的getter方法中。这导致了3秒的改进。但是我仍然想知道是否有办法在后台线程上创建图形用户界面。
编辑:
按照建议,我还尝试在“任务”中使用“RunLater”。这样,我可以创建 GUI 并显示初始屏幕,但我无法更新进度条和进度标签,因为 GUI 创建会阻止 JavaFX 应用程序线程。进度条和标签仅在完全创建 GUI 后才会更新。
下面是一个你们可以运行的例子(我删除了启动屏幕,只保留了进度条和进度标签):
public class InitWorker extends Task<Void> {
private static ProgressBar progressBar;
private static Label progressLabel;
private static double PROGRESS_MAX = 5;
private double loadingValue;
public InitWorker() {
loadingValue = 0;
}
@Override
protected void succeeded() {
System.out.println("Succeeded");
}
@Override
protected void failed() {
System.out.println("Failed");
}
@Override
protected Void call() throws Exception {
System.out.println("RUNNING");
Platform.runLater(new Runnable() {
public void run() {
displaySplashScreen();
for(int i=0; i<10; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
updateProgressBar(loadingValue++, "Label "+i);
Stage stage = new Stage();
Label label = new Label("Label " + i);
VBox panel = new VBox();
panel.getChildren().add(label);
Scene scene = new Scene(panel);
stage.setScene(scene);
stage.centerOnScreen();
stage.show();
}
// updateProgressBar(1, "Initializing...");
}});
return null;
}
public void updateProgressBar(double loadingValue, String text) {
progressBar.setProgress(loadingValue / PROGRESS_MAX);
progressLabel.setText(text);
}
public static void displaySplashScreen() {
Stage progressBarStage = new Stage();
progressBar = new ProgressBar();
Scene progressBarScene = new Scene(progressBar);
progressBarStage.setScene(progressBarScene);
Stage progressLabelStage = new Stage();
progressLabel = new Label("Loading...");
progressLabel.setPadding(new Insets(5));
progressLabel.setStyle("-fx-background-color: red");
Scene progressLabelScene = new Scene(progressLabel);
progressLabelStage.setScene(progressLabelScene);
double progressBarWidth = 500;
double progressBarHeight = 75;
//muss angezeigt werden, um sie abhängig von Größe zu positionieren
progressBarStage.show();
progressLabelStage.show();
//
progressBarStage.setWidth(progressBarWidth);
progressBarStage.setHeight(progressBarHeight);
progressBarStage.centerOnScreen();
progressBarStage.centerOnScreen();
progressLabelStage.setY(progressLabelStage.getY() + 25);
}
}
请参阅标题为“修改场景图的任务”的任务文档,其中提供了一个示例:
final Group group = new Group();
Task<Void> task = new Task<Void>() {
@Override protected Void call() throws Exception {
for (int i=0; i<100; i++) {
if (isCancelled()) break;
final Rectangle r = new Rectangle(10, 10);
r.setX(10 * i);
Platform.runLater(new Runnable() {
@Override public void run() {
group.getChildren().add(r);
}
});
}
return null;
}
};
上面的例子通过100次runLater调用将矩形添加到场景图中。更有效的方法是将矩形添加到未附加到活动场景图的组中,然后只在runLater调用中将该组添加到活动场景图中。例如:
final Group groupInSceneGraph = new Group();
Task<Void> task = new Task<Void>() {
@Override protected Void call() throws Exception {
final Group localGroup = new Group();
for (int i=0; i<100; i++) {
if (isCancelled()) break;
final Rectangle r = new Rectangle(10, 10);
r.setX(10 * i);
localGroup.getChildren().add(r);
}
Platform.runLater(new Runnable() {
@Override public void run() {
groupInSceneGraph.add(localGroup);
}
});
return null;
}
};
您可以在JavaFX应用程序线程之外创建和修改大多数场景图对象(包括加载FXML),只要这些对象没有附加到活动场景图。活动场景图是指当前作为场景附加到显示阶段的场景图。(像WebView
这样的复杂控件可能是此规则的例外,可能需要在JavaFX应用程序线程上创建)。
您只能将从JavaFX应用程序线程创建的场景图对象附加到JavaFX程序线程上的活动场景图(例如,使用Platform.runLater()
)。而且,只要它们继续附加到活动场景图,就必须在JavaFX应用程序线程上使用它们。
我正在尝试执行某些操作,例如创建一个表,并在应用程序的初始启动时插入720行,这需要一些时间,所以我决定在后台运行它。请参见下面的代码, 主要活动。Java语言 当我运行它时,它显示logcat中的以下错误, 请帮忙! 仅供参考:整个Logcat
我原以为这是一个简单的问题,但我很难找到答案。我有一个与JavaFX场景对象关联的ImageView对象,我想从磁盘加载大图像,并使用ImageView一个接一个地显示它们。我一直在努力寻找一种好方法来反复检查图像对象,当它在后台加载完成时,将其设置为ImageView,然后开始加载新的图像对象。我提出的代码(如下)有时有效,有时无效。我很确定我在JavaFX和线程方面遇到了问题。它有时加载第一个
我正在创建一个应用程序,其中我从服务器下载一些数据。在后台运行时,我希望连接应该继续运行,以便可以下载数据。我知道在app里有方法 当应用程序进入后台时调用。但由于连接是在viewController中创建的,如何在appDelegate中管理它 还有其他方法可以做到这一点吗?我已经通过了这个链接,但是有一个简单的实现方法吗?
我最初的fxml(例如)有很多功能,因此完全加载需要大量时间。因此,为了避免程序启动和fxml加载之间的时间间隔,我引入了另外一个fxml()和一个gif图像,该图像应该在加载主fxml时出现。问题是我的加载器中的gif图像。fxml不会移动,就像程序中的挂起一样,直到home.fxml被完全加载。为了避免这种情况,我将home.fxml加载移到一个线程中,如下代码所示。 但是在这段代码之后,我的
我试图在一个网站上获得一个内容列表(若有人感兴趣的话,这一个)。布局最近发生了变化,现在他们不会一次加载所有内容,而是使用magic(可能是js)。我目前正在使用JSoup分析HTML,但我愿意接受建议。 这就是我得到的: 实现此目的的代码: 这是我想看到的(复制从检查元素后,页面加载了所有的内容): 谷歌帮不了什么忙,因为与微调器等相关的所有内容都与javascript有关。 解决方案: 由于J
问题内容: 我在新应用中使用Alamofire(基于Alamofire的下载管理器示例),我需要一些有关使用后台会话下载文件的说明。我需要重写SessionDelegate才能使其正常工作?还是只是? 通常,使用Alamofire在后台处理下载的步骤是什么?以及如何处理我的应用程序重新启动,下载量不断增加的情况。 问题答案: 更新资料 基于这个惊人的教程,我整理了一个GitHub上可用的示例项目。