Modyfikacja elementu gui w javafx z wątku prywatnej klasy.

0

Cześć!

Piszę projekt zaliczeniowy na uczelnie, w skrocie gre w oczko online. W prywatnej klasie klient chce dodac do jednego z HBox-ów element. Problem z tym jest taki, że javafx wyrzuca błąd java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-5. Przeszukując internet jedyne rozwiązanie jakie znalazłem to uzycie Platform.runLater. Jednak jak wrzuce w tą funkcje pogrubioną linijke:

Platform.runLater(new Runnable() {
          @Override public void run() {
                **kartyGracza.getChildren().addAll(talia.rysujKarte(indexKarty));**
          }
});

to przy jej wykonaniu okienko się freezuje i jest "not responding". Rownież niektórym na stacku pomagało dopisanie do kodu "Platform.setImplicitExit(false);" jednak u mnie to nic nie zmienia. Cały dzień się męcze z tym problemem. Próbowałem modyfikować program tak aby nie musieć w ten sposób dodawać elementu do tego boxa jednak nie obejdę się bez tego i stoję w miejscu. Jak mogę rozwiązać ten problem?

Poniżej znajduje się "skrócony kod".

public class Lobby extends Application {
  HBox kartyGracza = new HBox(20);

...

  private class Klient extends Thread {
    private Scanner in ; 
    private PrintWriter out;
    private String line;
    private Socket socket;

    public Klient(Socket socket) {
      this.socket = socket;
    }

    @Override
    public void run(){ 
      try { 
         in = new Scanner(socket.getInputStream());
         out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);

         while (czyPolaczony) {
           if ( in .hasNextLine()) {
             line = in .nextLine();
      
             if (line.startsWith(ChatProtocol.KLIENT_RYSUJ_KARTE_COMMAND.toString())) {
               indexKarty = Integer.parseInt(line.substring(ChatProtocol.KLIENT_RYSUJ_KARTE_COMMAND.toString().length()));
               **kartyGracza.getChildren().addAll(talia.rysujKarte(indexKarty));**
             }
           }
        }
      }  catch (IOException ex) {
        Logger.getLogger(LobbyKlient.class.getName()).log(Level.SEVERE, null, ex);
      }
    }
  }
}
0

Czy to całe Thread, które podałeś, przekazujesz do Platform.runLater? Czy tylko tę oznaczoną linijkę, a tylko podałeś kod, gdzie tego nie ma? Jeśli tylko jedną linijkę, to podaj kod metody rysujKartę.

0

Przekazuje tylko jedną linijkę. Metoda rysujKarte:

public Karta rysujKarte(int index){
        Karta karta = null;
        while(karta == null){
            karta = karty[index]; //karty to tablica z talią kart
            karty[index] = null;   
        }
        return karta;
    }

Gdzie Karta to:

public class Karta extends Parent{

    private static final int SZEROKOSC_KARTY = 100;
    private static final int WYSOKOSC_KARTY = 140;

    enum Kolor {
        KIER, PIK, KARO, TREFL;

        final Image image;

        Kolor() {
            this.image = new Image(oKarta.class.getResourceAsStream("kolory/".concat(name().toLowerCase()).concat(".png")),
                    32, 32, true, true);
        }
    }

    enum Numer {
        DWA(2), TRZY(3), CZTERY(4), PIEC(5), SZESC(6), SIEDEM(7), OSIEM(8), DZIEWIEC(9), DZIESIEC(10),
        JACK(2), KROLOWA(3), KROL(4), AS(11);

        final int wartosc;

        Numer(int wartosc){
            this.wartosc=wartosc;
        }

        String wyswietlNazwe() {
            return ordinal() < 9 ? String.valueOf(wartosc) : name().substring(0, 1);
        }

    }

    public final Kolor kolor;
    public final Numer numer;
    public final int wartosc;

    public Karta(Kolor kolor, Numer numer){
        this.kolor = kolor;
        this.numer = numer;
        this.wartosc = numer.wartosc;

        Rectangle tloKarty =  new Rectangle(SZEROKOSC_KARTY, WYSOKOSC_KARTY);
        tloKarty.setArcWidth(20);
        tloKarty.setArcHeight(20);
        tloKarty.setFill(Color.WHITE);

        Text text1 = new Text(numer.wyswietlNazwe());
        text1.setFont(Font.font(18));
        text1.setX(WYSOKOSC_KARTY - text1.getLayoutBounds().getWidth() - 50);
        text1.setY(text1.getLayoutBounds().getHeight());

        Text text2 = new Text(text1.getText());
        text2.setFont(Font.font(18));
        text2.setX(10);
        text2.setY(SZEROKOSC_KARTY + 30);

        ImageView view = new ImageView(kolor.image);
        view.setRotate(180);
        view.setX(SZEROKOSC_KARTY - 32);
        view.setY(WYSOKOSC_KARTY - 32);

        getChildren().addAll(tloKarty, new ImageView(kolor.image), view, text1, text2);

    }


    @Override
    public String toString(){
        return numer.toString() + " of " + kolor.toString();
    }


}

Przyznam ze kwestia uzywania Platform.runLater to dla mnie totalna nowość i nie do końca jestem pewny czy dobrze to implementuje.

0

Platform.runLater uruchamia po prostu to Runnable, które mu przekażesz, w wątku JavaFX. Jeśli przekażesz mu takie Runnable, które się nie kończy, zawiera nieskończoną pętlę, to zablokujesz ten wątek. Tak pewnie jest tutaj - karta == null jest cały czas prawdą. Najlepiej uruchom debugger i sprawdź tę metodę.

0

Głupio się przyznać. Nie wiem co zmieniłem i nagle zaczęło działać... Nagle po uruchomieniu debuggera program stał się posłuszny

1 użytkowników online, w tym zalogowanych: 0, gości: 1