Статьи

Как интегрировать JavaFX в мастер платформы NetBeans (часть 2)

Ранее мы продемонстрировали, как разработчик может принять форму графического интерфейса JavaFX и FXML, разработанные с использованием Scene Builder, и заменить визуальную панель мастера платформы NetBeans с минимальными усилиями. Другой подход — создать панель с классами JavaFX JFXPanel, эффективно внедряя готовые компоненты JavaFX по мере необходимости. Хитрость заключается в том, чтобы с помощью этого подхода использовать конкретный шаблон проектирования, который скрывает шаблон Swing Interop от разработчика Wizard.

Чтобы полностью понять и следовать этому руководству, вам нужно начать с первой части, ссылка на которую приведена ниже:

http://netbeans.dzone.com/articles/how-integrate-javafx-netbeans-part3

который сам опирается на следующие предыдущие записи:

http://netbeans.dzone.com/articles/javafx-fxml-meets-netbeans 

http://netbeans.dzone.com/articles/how-embed-javafx-chart-visual

Теперь давайте расширим мастер из предыдущего урока, чтобы иметь вторую страницу в диалоге мастера. Мы хотим, чтобы эта вторая страница использовала информацию с первой страницы. Информация будет поступать из одного из наших элементов управления JavaFX и в идеале взаимодействовать с компонентом JavaFX на второй странице. На этот раз мы будем работать с компонентом JavaFX, который является частью готового класса, расширяющего класс JFXPanel. 

Предполагая, что у вас есть настройка проекта платформы NetBeans, на которой предыдущий учебник был остановлен, мы обновим мастер, чтобы перенести содержимое HTML в наш компонент HTML-редактор на первую страницу и отобразить его с помощью пользовательской панели браузера (используя WebView). Нечто подобное изображению ниже:

Пользовательская панель браузера расширит класс JFXPanel, инкапсулируя поля и предоставляя своего рода API-интерфейс для внедрения HTML-содержимого по мере необходимости.

  1. Предоставить доступ к редактору HTML в JavaFX GUI. Обновите свой файл FXML и класс контроллера, добавив аннотированный объект HTMLEditor и свяжите его с вашим FXML через строку fx: id. Следуйте существующему примеру для TextField и Button, которые существуют. Предоставьте метод доступа String для доступа к html-контенту объекта HTMLEditor. Ниже показано, как может выглядеть ваш класс контроллера:
    import java.io.File;
    import java.net.URL;
    import java.util.ResourceBundle;
    import javafx.embed.swing.JFXPanel;
    import javafx.event.ActionEvent;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.control.Button;
    import javafx.scene.control.TextField;
    import javafx.scene.web.HTMLEditor;
    import javafx.stage.FileChooser;
    
    /**
     *
     * @author SPhillips (King of Australia)
     */
    public class WizPanelController extends JFXPanel implements Initializable {
        @FXML
        private HTMLEditor htmledit; //fx:id="htmledit"
        @FXML //  fx:id="browseButton"
        private Button browseButton; // Value injected by FXMLLoader
        @FXML //  fx:id="pathText"
        private TextField pathText; //Field that Path is stored in
        private String filePath = ""; //some value to pass to the next Wizard panel
        
        // Handler for Button[fx:id="browseButton"] onAction
        public void handleButtonAction(ActionEvent event) {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("Select File");
            //Show open file dialog
            File file = fileChooser.showOpenDialog(null);
            if(file!=null) {
                setFilePath(file.getPath());
                pathText.setText(filePath);
            }
        }
        @Override // This method is called by the FXMLLoader when initialization is complete
        public void initialize(URL fxmlFileLocation, ResourceBundle resources) {
            assert browseButton != null : "fx:id=\"browseButton\" was not injected: check your FXML file 'WizPanel.fxml'.";
            assert pathText != null : "fx:id=\"pathText\" was not injected: check your FXML file 'WizPanel.fxml'.";
            assert htmledit != null : "fx:id=\"htmlEdit\" was not injected: check your FXML file 'WizPanel.fxml'.";
            // initialize your logic here: all @FXML variables will have been injected
        }
        @Override //This method is used by Wizard Framework to generate list of steps
        public String getName() {
            return "FXML Panel";
        }    
        /**
         * @return the filePath
         */
        public String getFilePath() {
            return filePath;
        }
        /**
         * @param filePath the filePath to set
         */
        public void setFilePath(String filePath) {
            this.filePath = filePath;
        }
        public String getHtmlContent() {
            return htmledit.getHtmlText();
        }
    }

    Обновление файла FXML очень мало, просто добавьте параметр fx: id в существующий HTMLEditor. Убедитесь, что строка fx: id соответствует имени переменной в вашем классе контроллера. Например:

    <HTMLEditor fx:id="htmledit" prefHeight="272.0" prefWidth="572.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
  2. Обновите классы первой панели мастера для передачи содержимого HTML. Здесь нет ничего необычного. Он будет выглядеть так же, как и стандартный мастер NetBeans на платформе Swing:
        @Override
        public void storeSettings(WizardDescriptor wiz) {
            // use wiz.putProperty to remember current panel state
            wiz.putProperty("content", getComponent().getHtmlContent());        
        }

    На самом деле вы, возможно, уже сделали это после выполнения предыдущего урока. 

  3. Создать BrowserJFXPanel. Технически это можно выложить вручную в конструкторе класса Visual Panel, но лучше создавать повторно используемые компоненты на основе JFXPanel. Это абстрагирует и скрывает шаблон Swing Interop от разработчика Swing. Если все сделано правильно, компонент должен иметь адекватный API для взаимодействия. 

    В этом случае мы хотим использовать компонент WebView для визуализации содержимого HTML, набранного на предыдущей странице мастера. Давайте создадим компонент, который делает именно это, предоставляя пользователю метод установки URL-адреса или строки содержимого HTML. Следующий соответствующий код даст вам это, само по себе заимствуя большой пример из примера взаимодействия Swing / JavaFX, который поставляется с IDE NetBeans. 

    public class BrowserJFXPanel extends JFXPanel {
     
        private String defaultPage = "http://www.oracle.com/us/index.html";
        private WebView view;
        private WebEngine eng;
        private TextField locationUrl = null;
        private Button loadButton;
        private Pane browserPane = null;
        
        public BrowserJFXPanel() {
            super();
            // create JavaFX scene
            Platform.setImplicitExit(false);
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    createScene();
                }
            });
        }
    
        private void createScene() {
            view =  new WebView();
            eng = view.getEngine();
            loadButton = new Button("Load");        
            loadButton.setDefaultButton(true);
            locationUrl = new TextField(defaultPage); //Gotta have something to start with
            EventHandler<ActionEvent> loadAction = new EventHandler<ActionEvent>() {
                @Override public void handle(ActionEvent event) {
                    setLocationUrl(locationUrl.getText().startsWith("http://") ? locationUrl.getText()
                           : "http://" + locationUrl.getText());
                }
            };  
            loadButton.setOnAction(loadAction);
            locationUrl.setOnAction(loadAction);
            eng.locationProperty().addListener(new ChangeListener<String>() {
                @Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                    locationUrl.setText(newValue);
                }
            }); 
            
            GridPane grid = new GridPane();
            grid.setPadding(new Insets(5));
            grid.setVgap(5);
            grid.setHgap(5);
            GridPane.setConstraints(loadButton, 0, 0);
            GridPane.setConstraints(locationUrl, 1, 0, 1, 1, HPos.CENTER, VPos.CENTER, Priority.ALWAYS, Priority.SOMETIMES);
            GridPane.setConstraints(view, 0, 1, 2, 1, HPos.CENTER, VPos.CENTER, Priority.ALWAYS, Priority.ALWAYS);
            grid.getChildren().addAll(loadButton,locationUrl, view);
            browserPane = grid;
            this.setScene(new Scene(browserPane));        
        }    
        
        public void setLocationUrl(String url) {
            //eng.getLoadWorker().progressProperty().addListener(handler);
            final String newUrl = url;
            Platform.runLater(new Runnable() {
                @Override
                public void run() {        
                    locationUrl.setText(newUrl);
                    //eng.getLoadWorker().
                    eng.load(newUrl);
                }
            });
        }
        public void setContent(String contentString) {
             final String newcontentString = contentString;
            Platform.runLater(new Runnable() {
                @Override
                public void run() {        
                    eng.loadContent(newcontentString);
                    locationUrl.setText("User Content");
                }
            });
        }

    Это был соответствующий код. Вы можете заполнить оставшуюся часть информации о классе и импортировать достаточно легко. Весь класс является примером шаблона Swing Interop, о котором заботятся в основном через конструктор.
    Также обратите внимание, что оба метода set используют шаблон Platform.runLater (), который может быть очевиден, если вы следовали этому примеру. Теперь, когда у нас есть компонент с API, давайте добавим его на нашу панель Swing.

  4. Добавьте BrowserJFXPanel в класс VisualPanel2. Вы должны иметь возможность легко добавлять компоненты JFXPanel в JScrollPane в позиции BorderLayout.Center. Ниже показано, как может выглядеть ваш код:
    import com.javafx.browser.BrowserJFXPanel;
    import java.awt.BorderLayout;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    
    public final class JfxwizVisualPanel2 extends JPanel {
        private JScrollPane scrollPane = new JScrollPane(); 
        public BrowserJFXPanel browserPanel;
        /**
         * Creates new form JfxwizVisualPanel2
         */
        public JfxwizVisualPanel2() {
            initComponents();
            setLayout(new BorderLayout());
            browserPanel = new BrowserJFXPanel();
            scrollPane.getViewport().add(browserPanel);
            add(scrollPane,BorderLayout.CENTER);        
        }
    
        @Override
        public String getName() {
            return "Review in JavaFX";
        }
    
        /**
         * This method is called from within the constructor to initialize the form.
         * WARNING: Do NOT modify this code. The content of this method is always
         * regenerated by the Form Editor.
         */
        // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
        private void initComponents() {
    
            javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
            this.setLayout(layout);
            layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGap(0, 400, Short.MAX_VALUE)
            );
            layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGap(0, 300, Short.MAX_VALUE)
            );
        }// </editor-fold>                        
        // Variables declaration - do not modify                     
        // End of variables declaration                   
    }

    Здесь не так много … просто еще один компонент Swing для добавления в макет.

  5. Установить содержимое BrowserJFXPanel. Наконец, вы можете использовать содержимое HTML, захваченное с помощью компонента HTMLEditor из предыдущей диалоговой страницы мастера. Как и в случае стандартного шаблона мастера платформы NetBeans, информация извлекается с помощью переопределения метода readSettings (). Однако на этот раз вы просто устанавливаете строку содержимого browserPanel, используя интерфейс метода, представленный в предыдущих шагах. Ваш код будет выглядеть так:
        @Override
        public void readSettings(WizardDescriptor wiz) {
            // use wiz.getProperty to retrieve previous panel state
            content = (String) wiz.getProperty("content");  
            component.browserPanel.setContent(content);
        }

Результат, если все сделано правильно, может визуализировать контент, созданный с помощью вашего FXML GUI, в вашем новом компоненте BrowserJFXPanel, как показано ниже:

И более того … поскольку вы так хорошо спроектировали свой компонент, вы можете ввести любой веб-URL-адрес по своему усмотрению
и отобразить его вместо этого. Надеюсь, вы уже задались вопросом, почему я потрудился выложить панель инструментов местоположения и кнопку загрузки для этого. Хитрость этого руководства заключается в том, что компонент браузера предоставляет интерфейс для автоматической установки либо URL-адреса, либо фактической строки содержимого автоматически. Идея состоит в том, что вы можете разрабатывать эти повторно используемые компоненты для других частей вашего приложения на платформе NetBeans, например, как часть пользовательский TopComponent или, может быть, как встроенный компонент в сцене Visual Library … (подсказка подсказка … следите за обновлениями …)

Привет, давайте воспользуемся нашим новым компонентом BrowserJFXPanel, чтобы проверить, какие классные блоги существуют: