2015-05-19 5 views
0

Этот вопрос можно рассматривать как простое расширение для this qeustion У меня есть простое приложение с меткой и WebView. WebView содержит небольшой прямоугольник, чья onclick должна вызывать метод в JavaFX и изменять текст метки.Изменение метки JavaFX с использованием метода обратного вызова Javascript

Ниже мой FXML файл

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.web.*?> 
<?import java.lang.*?> 
<?import java.util.*?> 
<?import javafx.scene.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="webviewlabel.FXMLDocumentController"> 
    <children> 
     <VBox prefHeight="200.0" prefWidth="100.0"> 
     <children> 
      <Label id="lblSample" fx:id="lblSample" text="Sample Label" /> 
      <WebView fx:id="wvSample" prefHeight="200.0" prefWidth="200.0" /> 
     </children> 
     </VBox> 
    </children> 
</AnchorPane> 

И мой класс FXMLController является

public class FXMLDocumentController implements Initializable { 

    @FXML 
    private Label lblSample; 

    @FXML 
    private WebView wvSample; 
    private WebEngine webEngine ; 

    @FXML 
    private void handleButtonAction(ActionEvent event) { 
     System.out.println("You clicked me!");  
    } 

    @Override 
    public void initialize(URL url, ResourceBundle rb) { 
     // wvSample = new WebView(); 
     initiateWeb(); 
    } 

    public void initiateWeb() { 
     webEngine = wvSample.getEngine(); 

     webEngine.getLoadWorker().stateProperty().addListener(
      new ChangeListener<Worker.State>() { 
       public void changed(ObservableValue<? extends Worker.State> p, Worker.State oldState, Worker.State newState) { 
        if (newState == Worker.State.SUCCEEDED) { 
         JSObject win = (JSObject) webEngine.executeScript("window"); 
         win.setMember("javaObj", new Connector());  
         System.out.println("FXMLDocumentController.initialize(): Called"); 
        } 
       } 
      } 
     );   
     webEngine.loadContent(
      "<div style='width: 50; height: 50; background: yellow;' onclick='javaObj.Connecting();' />" 
     ); 
    } 

    public void setLabelText(String text) 
    { 
     System.out.println("FXMLDocumentController.setLabelText(): Called"); 
     lblSample.setText(text); 
    }  
} 

А класс Коннектор

public class Connector {  
    public void Connecting() { 
     try { 
      System.out.println("Connector.Connecting(): Called"); 
      /* 
      FXMLLoader loader = new FXMLLoader(FXMLDocumentController.class.getResource("FXMLDocument.fxml")); 
      loader.load(); 
      FXMLDocumentController controller = (FXMLDocumentController) loader.getController(); 
      */ 
      // controller.setLabelText("Bye World"); 
     } catch (Exception ex) { 
      Logger.getLogger(Connector.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
} 

В приведенном выше класс соединителя, как я получаю обработчик класса FXMLController, чтобы можно было получить доступ к setLabelText.

Из ответов для question я мог понять, что FXMLDocumentController может быть передан как параметр, но я не уверен, как обращаться к контроллеру, когда я обращаюсь к нему через обратный вызов javascript.

ответ

0

Определение поля в Connector класса и конструктор для инициализации:

public class Connector { 

    private final FXMLDocumentController controller ; 

    public Connector(FXMLDocumentController controller) { 
     this.controller = controller ; 
    } 

    // ... 
} 

Затем вы можете ссылаться на controller непосредственно в connecting() метода:

public void connecting() { 
    // ... 

    controller.setLabelText("Bye World"); 
    // ... 
} 

так же, как вы хотели сделать ранее.

Теперь вы просто построить Connector со ссылкой на контроллер:

public class FXMLDocumentController { 

    // ... 

    public void initiateWeb() { 
     // ... 

     webEngine.getLoadWorker().stateProperty().addListener(
      new ChangeListener<State>() { 
       // ... 

       win.setMember("javaObj", new Connector(FXMLDocumentController.this)); 
       // ... 
      } 
     ); 
    } 
    // ... 
} 

как вариация на это, в Java 8, вместо того, чтобы хранить ссылку на контроллер в Connector классе, вы могли бы просто сохранить функцию для обработки сообщения:

public class Connector { 

    private final Consumer<String> messageUpdater ; 

    public Connector(Consumer<String> messageUpdater) { 
     this.messageUpdater = messageUpdater ; 
    } 

    // ... 

    public void connecting() { 
     // ... 
     messageUpdater.accept("Bye world"); 
     // ... 
    } 
} 

А затем создать экземпляр Connector с

webEngine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> { 
    if (newState == Worker.State.SUCCEEDED) { 
     JSObject win = (JSObject) webEngine.executeScript("window"); 
     win.setMember("javaObj", new Connector(this::setLabelText));  
     System.out.println("FXMLDocumentController.initialize(): Called"); 
    } 
}); 
+0

Работает отлично :) – Talat