如何在JavaFX中使用并发(线程)(使用FXML !!!(JavaFX Scene Builder))?

时间:2014-10-02 23:57:55

标签: multithreading concurrency controller fxml scenebuilder

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

1 个答案:

答案 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。