Ранее мы продемонстрировали, как разработчик может принять форму графического интерфейса 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-содержимого по мере необходимости.
- Предоставить доступ к редактору 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" />
- Обновите классы первой панели мастера для передачи содержимого HTML. Здесь нет ничего необычного. Он будет выглядеть так же, как и стандартный мастер NetBeans на платформе Swing:
@Override public void storeSettings(WizardDescriptor wiz) { // use wiz.putProperty to remember current panel state wiz.putProperty("content", getComponent().getHtmlContent()); }
На самом деле вы, возможно, уже сделали это после выполнения предыдущего урока.
- Создать 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. - Добавьте 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 для добавления в макет.
- Установить содержимое 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, чтобы проверить, какие классные блоги существуют: