JavaFX nowy wątek i próba

0

Cześć,
mam problem dotyczący pobrania tekstu z TextField w innej klasie->nowym wątku. Uszczegóławiając, program pisany przy pomocy JavaFX(SceneBuiler). Mam klasę View połączoną z plikiem fxml. Klasa View implementuje interfejs Initializable i metodę initialize w której umieszczam kod dotyczący zdarzeń. W tej klasie dopisałem również metodę, która czyta pole obiektu TextField url;

public String getUrl() {
    return this.url.getText();
    }

Przy kliknięciu w button1 tworzony jest nowy wątek->nowa klasa wykonująca pewne funkcję. Chciałbym w niej pobrać dane z TextField url znajdującego się w klasie View. Utworzenie obiektu View i wywołanie metody getUrl(); nie skutkuje. Chyba jest jakiś problem, że nie mogę się odwołać do obiektu TextField przez obiekt View...jak go rozwiązać?

*W klasie View metoda getUrl(); zwraca to to powinna;

Z góry dziękuję za pomoc!

1

Bierzesz się za pisanie programu z wątkami i GUI a masz problem z przekazaniem referencji z jednego obiektu do drugiego...
Przekaż referencję do pola url przez konstruktor tworząc instancję tej klasy, w której chcesz z niego korzystać. Jeżeli zastanawiasz się dlaczego utworzenie nowego obiektu klasy View i wywołanie metody getUrl() nie skutkuje to wróć do podstaw programowania obiektowego i załap różnicę pomiędzy klasą a obiektem, bez tego dalej będzie tylko trudniej...

2

Przekaż tę wartość przy wywołaniu funkcji tworzącej nowy wątek, coś na zasadzie:

public void onButtonClicked(){
    this.runSomeBackgroundTask(this.url.getText());
}

private CompletableFuture runSomeBackgroundTask(final String url) {
    return CompletableFuture.runAsync(() -> System.out.println(url)); 
}

JavaFX uniemożliwia dokonywania zmian GUI z innych wątków.

0

Dzięki za nakierowanie!
Chyba trochę za dużo nakombinowałem, ale ostatecznie utworzyłem nową zmienną statyczną String w klasie View i przy kliknięciu przycisku uruchamiającego przed utworzeniem nowego wątek przypisuje do niej wartość z TextField url. Później już w klasie nowego wątku nie mam problemów z pobraniem tej wartości.

Ps. Nick zobowiązuje, jestem początkującym i może trochę zbyt dużo wiedzy na raz ;) Staram się to jakoś uporządkować, a ten programik przy którym sobie aktualnie pracuję po godzinach jest moim pierwszym, także proszę o wyrozumiałość ;)

0

ostatecznie utworzyłem nową zmienną statyczną String w klasie View

to akurat jest totalny fakap. Nie do tego służą zmienne statyczne. Jak się uczysz to pisz porządnie. Post wyżej masz prawidłowe rozwiązanie od @AreQ212

0

Niestety przy próbie implementacji rozwiązania od @AreQ212, cały czas wyrzuca mi wyjątek java.lang.NullPointerException. Wnioskuję, że odwołuję się do obiektu TextField przez referencję url która ma przypisaną wartość null.

0

@fresh_meat: ten fragment to jedynie koncepcja, nie znamy całości Twojego kodu, żeby móc w łatwy sposób odpowiedzieć na to skąd ten NullPointer się bierze. Wrzuć proszę kod tych klas tutaj w wątku albo do pastbina. Natomiast utworzenie zmiennej statycznej to faktycznie najgorsze z możliwych rozwiązań (szczególnie w kontekście wielowątkowości) :)

0

Okej, w takim razie prezentuję kod, zdaje sobie sprawę, że pewnie będzie to fakap (chyba jestem trochę zacofany, wcześniej nie znałem tego słowa a mi się spodobało. Dzięki @dymul), także czym więcej uwag tym lepiej ;)

public class View implements Initializable {

    @FXML
    private Button end;

    @FXML
    private Button start;

    @FXML
    public TextField url;

    @FXML
    private TextField email;

    @FXML
    private Circle circle;

    @FXML
    private PasswordField password;

    public static String fromTextFieldUrl;
    public static String fromTextFieldEmail;
    public static String fromTextFieldPassword;
    public static boolean working=false;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

    start.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {

            String info1,info2;
            fromTextFieldUrl=url.getText(); 
            fromTextFieldEmail=email.getText();
            fromTextFieldPassword=password.getText();
            working=true;
            circle.setFill(Color.RED);  
                Runnable taskThread=new MyRun();
                Thread nextThread=new Thread(taskThread);
                nextThread.start();
            url.setEditable(false);
            email.setEditable(false);
            password.setEditable(false);
        }   
    });

    end.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {

            working=false;
            circle.setFill(Color.rgb(245, 240, 250));
            url.setEditable(true);
            email.setEditable(true);
            password.setEditable(true);

        }   
    });

    }//end initialize
}//end View

i klasa z metodą nowego wątku:

public class MyRun implements Runnable{

    @Override
    public void run() {
    String info1, info2,url,email,password;
    url=View.fromTextFieldUrl;
    email=View.fromTextFieldEmail;
    password=View.fromTextFieldPassword;

    while(View.working){
    System.out.println(email); 
    System.out.println(password);
        try {
            WebsiteInfo websiteInfo =new WebsiteInfo(url);
            info1=websiteInfo.chceckOutWebsite();
            Thread.sleep(10000);
            info2=websiteInfo.chceckOutWebsite();
            if(!(info1.equals(info2)))
            {
                SendAnEmail send=new SendAnEmail(email,password);
                send.setContent(url);
                try {
                    send.send();
                } catch (MessagingException e) {

                    e.printStackTrace();
                }
            }
        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }
        }//end run
}//end MyRun
0

Wystarczy że potrzebne wartości przekażesz w konstruktorze klasy MyRun i już nic nie będzie statyczne. Problem pojawia się przy sprawdzaniu czy pętla ma zostać przerwana (wydaje mi się że dałoby się to lepiej zrobić z jakimś nowszym API typu CompletableFuture), bo przekazanie wartości nie wchodzi w rachubę, musisz móc ją aktualizować. Stąd też Supplier. Innym rozwiązaniem byłoby też użycie AtomicBoolean (konieczność w przypadku gdybyś chciał zmieniać tę wartość w wątkach), ale że jedynie odczytujesz wartość zwykły Boolean powinien wystarczyć. W kodzie poniżej zmieniłem nieco nazwy (urlField, emailField, passwordField) i usunąłem statyczne zmienne.

public class View implements Initializable {
...

    @FXML
    private PasswordField passwordField;

    private boolean working = false;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        this.start.setOnAction(event -> {
            this.working = true;
            this.circle.setFill(Color.RED);
            final Runnable taskThread = new MyRun(this.urlField.getText(), this.emailField.getText(), this.passwordField.getText(), () -> this.working);
            final Thread nextThread = new Thread(taskThread);
            nextThread.start();
            this.urlField.setEditable(false);
            this.emailField.setEditable(false);
            this.passwordField.setEditable(false);
        });

        this.end.setOnAction(event -> {
            this.working = false;
            this.circle.setFill(Color.rgb(245, 240, 250));
            this.urlField.setEditable(true);
            this.emailField.setEditable(true);
            this.passwordField.setEditable(true);

        });
    }
}
public class MyRun implements Runnable {

    private final String url;
    private final String email;
    private final String password;
    private final Supplier<Boolean> shouldContinue;

    public MyRun(final String url, final String email, final String password, final Supplier<Boolean> shouldContinue) {
        this.url = url;
        this.email = email;
        this.password = password;
        this.shouldContinue = shouldContinue;
    }

    @Override
    public void run() {
        while (this.shouldContinue.get()) {
            ...         
        }
    }
}
0

Dzięki @AreQ212: Większości klas, które tutaj wymieniasz nie są mi znane, ale właśnie zaglądam do dokumentacji ;)

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