NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Diskuze: Vlákno v FX

V předchozím kvízu, Online test znalostí Java, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:20.11.2017 16:02

Zdravíčko,

konečně jsem se odhodlal převést si všechny staré projekty do FX a už jsem si i vzpomněl, co jsem míval za problém ve swingu. Teď se objevil podobný i v FX a to, že mi vlákno z nepochopitelných důvodů interrupne. Bohužel, žádná chyba se nezobrazí. Netuším, jak vypsat nějaký blok, protože k chybě dochází vážně náhodně.
O čem program je?
Trošku nastíním i myšlenku programu. Chci si udělat radar, který mi bude detekovat komponenty, které si někam libovolně umístím na plochu. Radar v podobě klasického kolečka a ručičky, která jezdí dokola a prozkoumává prostor, pak zobrazí tyto komponenty.
Problém
Není to nic těžkého, problém je v tom, že se mi ta ručička sice točí do kola, ale tu a tam se sekne a ke všemu bez výpisu.
Pochopitelně dodávám kompletní kód.

Jo a ještě rychlá poznámka - pokud by někdo dospěl k nějakému výpisu, který by neukazoval na běhovou chybu v přiloženém kódu, ale na nějakou logickou chybu (typu ConcurrentModi­ficationExcep­tion atd.) tak prosím i o nějaký návrh řešení. Klidně i zkritizujte logiku kódu,

import javafx.application.Application;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;

public class Radar extends Application {

    private final Rotate rotate = new Rotate();
    private int angle;
    private boolean detect;

    public void start(Stage stage) throws Exception {
        Pane layout = new Pane();
        Scene scene = new Scene(layout, 400, 200);
        stage.setScene(scene);
        stage.setOnCloseRequest(evt -> System.exit(0));
        stage.setResizable(false);
        stage.show();

        //Circle background
        Circle surveyArea = new Circle(100, 100, 100);
        surveyArea.setFill(Color.BLUE);

        //Line as pointer to detection
        Line detectionHand = new Line(surveyArea.getCenterX(), surveyArea.getCenterY(), surveyArea.getRadius(), surveyArea.getCenterY() - surveyArea.getRadius());
        layout.getChildren().addAll(surveyArea, detectionHand);

        //Default position of detectionHand and add rotate to that
        rotate.setPivotX(detectionHand.getStartX());
        rotate.setPivotY(detectionHand.getStartY());
        detectionHand.getTransforms().add(rotate);

        //Rotation of pointer line
        detect = true;
        Thread threadForDetection = new Thread(() -> {
            while (detect) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException ignored) {
                }
                rotate.setAngle(angle++);
                if (angle == 360) {
                    angle = 0;
                }
            }
        });
        threadForDetection.start();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Odpovědět
20.11.2017 16:02
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Hartrik
Tvůrce
Avatar
Odpovídá na Lubor Pešek
Hartrik:20.11.2017 18:22

Asi bych prvně zkusil synchronizovat to rotate.setAngle(­...) přes Platform.runLa­ter().

 
Nahoru Odpovědět
20.11.2017 18:22
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:20.11.2017 20:21

jj synchronizace mě taky napadla, nepomohlo to (navíc, používám tam jen jedno vlákno, takže i tak to byl asi zoufalý pokus). Nicméně tu metodu Platform.runLater() neznám, řekl bys mi ve stručnosti její smysl?

Nahoru Odpovědět
20.11.2017 20:21
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Odpovídá na Lubor Pešek
Petr Štechmüller:20.11.2017 20:35

Ahoj, jak jistě víš, tak JavaFX handluje akce přes frontu zpráv (jako každý GUI framework).
Když zavoláš metodu

rotate.setAngle(angle++);

z jiného než JavaFX vlákna, tak hrozí, že dojde ke kolizi, jejíž výsledkem je v tomto případě zaseknutí ručičky.
Nebo jiný příklad: z jiného vlákna nemůžeš nastavovat hodnotu textboxu, to zařve rovnou.

Jako řešení je právě zavolat metodu Platform.runLa­ter, která jako parametr bere rozhraní Runnable. Jak už název metody napovídá, kód, který se pošle do metody jako parametr se vykoná "někdy později". To někdy později je v tomto případě ve chvíli, kdy na tento kus kódu dojde řada ve frontě zpráv, kterou si ale už obstarává JavaFX vlákno. Tím se zajistí, že nedojde k nekonzistenci a ručička se správně otočí.

Více info na stackoverflow
Případně javadoc

Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
Nahoru Odpovědět
20.11.2017 20:35
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Lubor Pešek
Člen
Avatar
Odpovídá na Petr Štechmüller
Lubor Pešek:20.11.2017 20:40

díky, oba tedy doporučujete to samé, hned na to jdu. Škoda,že nemůžu dát fajfku oběma :(

Nahoru Odpovědět
20.11.2017 20:40
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 5 zpráv z 5.