如何在JavaFX中使用FXML和任务或服务类?
我的程序需要并发,因为我使用了很长的循环。 如果我“手动”(没有FXML)编码,那么它的工作原理。但是使用FXML它不起作用(JavaFX Scene Builder)。我想在textarea(可更新的组件)中编写它,而不是在控制台中打印出“String buffer”变量。但是在这种情况下,当然会出现错误消息,因为它不再属于JavaFX应用程序线程。如何使这个组件(TextArea textAreaAusgabe)更新/更新,以便我可以在线程中使用它? 抱歉我的英语不好? 希望你知道我的问题是什么(它是FXML :-D)。 如果在NetBeans中有另一个gui构建器,那么我将使用它来构建swing。 据我所知,Scene Builder是JavaFX唯一的gui构建器:-(。
我想在我的代码片段中使用task3。 这是我的代码片段不起作用(如果我使用标签,文本字段等组件):
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import java.io.*;
import java.util.Random;
import java.util.Arrays;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileSystemView;
public class Kontroller implements Initializable
{
int array [ ] = new int [50];
int counter = 0;
String buffer;
int z;
public TextArea textAreaAusgabe;
public Button buttonBerechnen;
public Button buttonReset;
public Label labelAnzahl;
public ProgressBar progressBar;
public ProgressIndicator progressIndikator;
public CheckBox checkBox1;
public CheckBox checkBox2;
public CheckBox checkBox3;
public CheckBox checkBox4;
public CheckBox checkBox5;
public CheckBox checkBox6;
public CheckBox checkBox7;
public CheckBox checkBox8;
public CheckBox checkBox9;
public CheckBox checkBox10;
Task <Integer> task = new Task <Integer> ( )
{
@Override
protected Integer call ( ) throws Exception
{
int i;
for (i = 0; i < 100; i++)
{
if (isCancelled ( ) )
{
break;
}
System.out.println("Anzahl " + i);
}
return i;
}
};
Task <Integer> task2 = new Task <Integer> ( )
{
@Override
protected Integer call ( ) throws Exception
{
int j;
for (j = 0; j < 1000; j++)
{
if (isCancelled ( ) )
{
updateMessage ("Abgebrochen");
break;
}
System.out.println ("Anzahl " + j);
updateMessage ("Anzahl " + j);
updateProgress (j, 1000);
try
{
Thread.sleep (1);
} catch (InterruptedException interrupted)
{
if (isCancelled ( ) )
{
updateMessage ("Abgebrochen");
break;
}
}
}
return j;
}
};
Service <Void> service = new Service <Void> ( )
{
@Override
protected Task <Void> createTask ( )
{
return new Task <Void> ( )
{
@Override
protected Void call ( ) throws Exception
{
return null;
}
};
}
@Override
protected void succeeded ( )
{
}
};
Task task3 = new Task <Void> ( )
{
@Override public Void call ( ) throws IOException
{
File ergebnis = new File (FileSystemView.getFileSystemView ( ).getHomeDirectory ( ).getAbsolutePath ( ) + "\\Ergebnis.txt");
final FileWriter fw = new FileWriter (ergebnis);
for (int k = 1; k <= 10000000; k++)
{
if (isCancelled ( ) )
{
break;
}
updateProgress (k, 10000000);
Arrays.fill (array, 0);
// textAreaAusgabe.appendText (buffer); // Does not work
System.out.println (buffer); // Works
System.out.println (counter++);
System.out.println ( );
fw.append (System.getProperty ("line.separator") );
fw.append (System.getProperty ("line.separator") );
fw.append (""+counter+"");
fw.append (System.getProperty ("line.separator") );
fw.append (System.getProperty ("line.separator") );
}
return null;
}
};
Thread thread = new Thread (task3);
public void reset ( )
{
// Zurücksetzen
}
public void berechnen (ActionEvent event)
{
thread.setDaemon (true);
thread.start ( );
}
public void fehler ( )
{
// Zeige Stage bei Fehler
}
public void initialize (URL url, ResourceBundle rb)
{
progressBar.progressProperty ( ).bind (task3.progressProperty ( ) );
progressIndikator.progressProperty ( ).bind (task3.progressProperty ( ) );
}
}
如果我注释掉这一行:
// textAreaAusgabe.appendText (buffer); // Does not work
出现以下错误:
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
这是NetBeans输出中的完整错误消息:
ant -f D:\\Users\\Benutzer\\Documents\\NetBeansProjects\\Threading jfxsa-run
init:
Deleting: D:\Users\Benutzer\Documents\NetBeansProjects\Threading\build\built-jar.properties
deps-jar:
Updating property file: D:\Users\Benutzer\Documents\NetBeansProjects\Threading\build\built-jar.properties
Compiling 1 source file to D:\Users\Benutzer\Documents\NetBeansProjects\Threading\build\classes
warning: [options] bootstrap class path not set in conjunction with -source 1.5
warning: [options] source value 1.5 is obsolete and will be removed in a future release
warning: [options] target value 1.5 is obsolete and will be removed in a future release
warning: [options] To suppress warnings about obsolete options, use -Xlint:-options.
4 warnings
compile:
Detected JavaFX Ant API version 1.3
Launching <fx:jar> task from F:\Java\Java Development Kit\Java Development Kit (1.8.0_20) (x64)\jre\..\lib\ant-javafx.jar
Warning: From JDK7u25 the Codebase manifest attribute should be used to restrict JAR repurposing.
Please set manifest.custom.codebase property to override the current default non-secure value '*'.
Launching <fx:deploy> task from F:\Java\Java Development Kit\Java Development Kit (1.8.0_20) (x64)\jre\..\lib\ant-javafx.jar
jfx-deployment-script:
jfx-deployment:
jar:
Copying 12 files to D:\Users\Benutzer\Documents\NetBeansProjects\Threading\dist\run1389427067
jfx-project-run:
Executing D:\Users\Benutzer\Documents\NetBeansProjects\Threading\dist\run1389427067\Threading.jar using platform F:\Java\Java Development Kit\Java Development Kit (1.8.0_20) (x64)\jre/bin/java
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
at javafx.scene.Scene.addToDirtyList(Scene.java:485)
at javafx.scene.Node.addToSceneDirtyList(Node.java:424)
at javafx.scene.Node.impl_markDirty(Node.java:415)
at javafx.scene.shape.Shape.impl_markDirty(Shape.java:942)
at javafx.scene.Node.impl_geomChanged(Node.java:3784)
at javafx.scene.text.Text.impl_geomChanged(Text.java:763)
at javafx.scene.text.Text.needsTextLayout(Text.java:194)
at javafx.scene.text.Text.needsFullTextLayout(Text.java:189)
at javafx.scene.text.Text.access$200(Text.java:96)
at javafx.scene.text.Text$2.invalidated(Text.java:386)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:109)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:143)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.scene.text.Text.setText(Text.java:367)
at com.sun.javafx.scene.control.skin.TextAreaSkin.lambda$new$231(TextAreaSkin.java:571)
at com.sun.javafx.scene.control.skin.TextAreaSkin$$Lambda$256/235779996.invalidated(Unknown Source)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:349)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.scene.control.TextInputControl$TextProperty.fireValueChangedEvent(TextInputControl.java:1123)
at javafx.scene.control.TextInputControl$TextProperty.markInvalid(TextInputControl.java:1127)
at javafx.scene.control.TextInputControl$TextProperty.invalidate(TextInputControl.java:1066)
at javafx.scene.control.TextInputControl$TextProperty.access$1300(TextInputControl.java:1038)
答案 0 :(得分:2)
您的问题不是针对FXML的。
您的问题是您的任务代码违反了JavaFX线程规则(即您无法修改JavaFX应用程序线程中活动场景中的节点)。
替换不起作用的代码:
textAreaAusgabe.appendText (buffer); // Does not work
使用:
Platform.runLater(() -> textAreaAusgabe.appendText (buffer));
这将执行JavaFX应用程序线程上的文本区域节点的操作并解决线程运行时问题。
请参阅Task文档部分&#34;修改场景图的任务&#34;。
但是,对于您的示例应用程序,您现在将遇到另一个问题,因为您将快速更新JavaFX场景一亿次,这将使JavaFX系统过载并使您的应用程序无响应。您需要做的是批量处理文本更改,并仅发出runlater调用以每秒更新UI不超过60次。要求UI每秒更新超过60次是无用的,因为没有人能看到中间更新。
另外,回答你的辅助问题=&gt;不,JavaFX目前没有其他GUI编辑器,而不是SceneBuilder。