如何将JavaFX中的线程与FXML以及任务或服务类一起使用?
我在我的程序中需要并发,因为我使用了一个很长的循环。如果我“手动”(没有FXML)编写这个代码,那么它就可以工作。但使用FXML它不起作用(JavaFX Scene Builder)。而不是在控制台中打印出“字符串缓冲区”变量,我想把它写在文本区域(这是一个可更新的组件)中。但在这种情况下,当然会出现错误消息,因为它不再属于JavaFX应用程序线程。我如何才能让这个组件(TextArea text Area aAusgabe)更新/更新,以便我可以在线程中使用它?并且为我糟糕的英语感到抱歉?希望你知道我的问题是什么(它是FXML:-D)。如果有另一个像NetBeans中那样的gui构建器,我会使用它。据我所知,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)
您的问题不是FXML特有的。
您的问题是,您的任务代码违反了JavaFX线程规则(即,您不能在JavaFX应用程序线程之外修改活动场景中的节点)。
替换不起作用的代码:
textAreaAusgabe.appendText (buffer); // Does not work
与:
Platform.runLater(() -> textAreaAusgabe.appendText (buffer));
这将在JavaFX应用程序线程上执行文本区域节点的操作,并解决您的线程运行时问题。
请参阅任务文档部分“修改场景图的任务”。
然而,对于示例应用程序,您现在将遇到另一个问题,因为您将快速更新JavaFX场景一亿次,这将使JavaFX系统过载,并使应用程序无响应。您需要做的是批量处理文本更改,只需发出runlater调用,以每秒更新UI不超过60次。要求用户界面每秒更新60次以上是没有用的,因为没有人能看到中间的更新。
另外,回答你的辅助问题=
关于如何自定义这样的值,有什么建议或想法吗?
我正在用java开发一个聊天机器人项目,在GUI中我使用JavaFX、IDE eclipse和scene builder 8.4.1。 我在向文本区域添加背景图像时遇到问题。这是我所做的一个屏幕截图,它什么也没有显示(甚至没有错误)。 以下是场景生成器生成的fxml代码:
我希望此图表显示在场景生成器上。怎么可能。。??
我在Swing应用程序中使用JavaFX,带有JFXPanel。我一直在使用css文件手动编码JavaFXUI。我正在使用NetBeans 8.1。 我想知道,在这种情况下,我可以使用JavaFX场景生成器生成UI吗?好的,输出是代表UI组件的FXML文件。这与JFXPanel使用JavaFX的方式兼容吗? 谢谢
我对屏幕生成器有一些问题 对于某些fxml,它会在加载后发生creash。我尝试了很多次运行它,但它阻塞了,我必须终止这个进程。 fxml正常,内容在我的应用程序中正确显示。下面是导致场景生成器崩溃的FXML示例。
在public void start(Stage primaryStage)中程序开始时,我制作了A的对象并将其传递给primary Stage,然后在每个类中我更改它,并且它工作得很好。但我对此没有什么疑问: 这是一个正确的方法吗? 有没有其他方法可以在保留类的同时完成它,或者我应该只在主类中完成所有操作? 传递场景然后更改根节点是否更好? 对不起,如果我问得有点多了,但我读了很多关于它仍然没有