当前位置: 首页 > 知识库问答 >
问题:

如何在JavaFX(使用FXML!!!(JavaFX场景生成器))中使用并发(线程)?

汪臻
2023-03-14

如何将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) 

共有1个答案

郭翰墨
2023-03-14

您的问题不是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,然后在每个类中我更改它,并且它工作得很好。但我对此没有什么疑问: 这是一个正确的方法吗? 有没有其他方法可以在保留类的同时完成它,或者我应该只在主类中完成所有操作? 传递场景然后更改根节点是否更好? 对不起,如果我问得有点多了,但我读了很多关于它仍然没有