Статьи

Работа с данными с помощью JavaFX Visuals и платформы NetBeans

Поэтому вам нужно создать визуализацию данных, которые должны загружаться и динамически взаимодействовать. Приятная внешность важна, поэтому вы выбрали JavaFX, но вы начинаете с существующего приложения на основе Swing. Нет проблем, верно? Но что, если у вас есть много данных для загрузки в вашу сцену? Как вы поддерживаете положительный пользовательский опыт?

Может быть, вы используете платформу NetBeans, потому что … ну … это довольно круто. Работа с вашим приложением очень отзывчива до момента, когда вы анализируете и отображаете данные, но затем происходит небольшое ожидание или даже зависание, пока создается сценарий JavaFX. Визуальный результат великолепен, но пользовательский опыт запятнан многосекундным ожиданием. 

С этим можно справиться, вам просто нужно визуально подтвердить пользователю какую-то анимацию, чтобы он знал … «Эй, я все еще здесь, не волнуйтесь!» Нет проблем. Следующий шаблон показывает, как вы можете легко сделать это либо с помощью прямого взаимодействия Swing, либо встроенного из приложения платформы NetBeans.

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

  • Платформа NetBeans с созданным многовидовым компонентом TopComponent
  • Среда выполнения JavaFX добавлена ​​в виде библиотеки или дополнительного плагина
  • Некоторые данные и сценарий JavaFX для отображения
  • Понимание стандартного шаблона взаимодействия JFXPanel.

Это учебное пособие было выполнено с использованием среды IDE NetBeans 7.4, которая просто великолепна … получите ее ! Версия JavaFX — это среда выполнения 2.x, взятая из Java 1.7u45. Если вы работаете с ранними выпусками JDK 8, вам не нужно беспокоиться об обертывании среды выполнения JavaFX в ваше приложение на платформе NetBeans … его автоматизация. 

Предположение, принятое в этом руководстве, заключается в том, что вы хотите присоединить визуальный элемент JavaFX к пользовательскому типу файла, который расширяет элемент TopComponent API элемента MultiView. Это очень мощный шаблон, типичный для разработки RCP в целом, который я широко использую во всем программном обеспечении наземной системы NASA. Здесь возникает проблема, когда ваши наборы данных на основе файлов являются относительно большими. Не большие «Большие данные» … так что, возможно, мы назовем их «Средние данные». Проблема заключается в том, что при переключении из стандартного представления «Источник» в пользовательское представление «Visual» происходит своего рода зависание, пока создается и загружается ваша JFXPanel. Начиная здесь в вашем конструкторе TopComponent:

public final class SomeBigDataFileVisualElement extends JPanel implements MultiViewElement {

    private SomeBigDataFile obj;
    private JToolBar toolbar = new JToolBar();
    private transient MultiViewElementCallback callback;

    public SomeBigDataFileVisualElement(Lookup lkp) {
        obj = lkp.lookup(SomeBigDataFileDataObject.class);
        assert obj != null;
        initComponents();
        toolbar.setFloatable(false);
        final JFXSomeBigDataFilePanel jfxpanel = new JFXSomeBigDataFilePanel();        
        add(jfxpanel, BorderLayout.CENTER);
    }

Во время ожидания загрузки ваших данных вы увидите пустой TopComponent:

образ

Хм … первое впечатление, что ваше приложение сломано. Что делать, если вам просто нужно еще 5 или 6 секунд? Многие наивные пользователи будут просто закатывать глаза и харампфить . Это объясняется тем, что вы помещаете все свои сцены JavaFX внутри вызова Platform.runLater () внутри конструктора JFXPanel. Типичная картина. Вместо этого попробуйте построить свою сцену в отдельном потоке задач JavaFX. Затем в конструкторе JFXPanel просто создайте очень легкий макет с помощью ProgressIndicator. Попробуйте следующий шаблон:

    public JFXSomeBigDataPanel() {
        super();
        Platform.setImplicitExit(false);
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                createScene();
                
            }
        });         
    }    
    private void createScene() {
        pane = new BorderPane();
        barPi.setOpacity(0.6);        
        barPi.setVisible(true);
        pane.setTop(barPi);
        scatterPi.setOpacity(0.6);        
        scatterPi.setVisible(true);
        pane.setCenter(scatterPi);
        scene = new Scene(pane);
        setScene(scene);        
    }  

Который намеревается загрузить две сложные диаграммы JavaFX (StackedBarChar и категоризированный ScatterPlot. Это покажет некоторые хорошие счетчики на экране. 

образ

Заметьте маленькую вертушку над большой вертушкой? Да, я использовал BorderPane … для примера, и это размеры по умолчанию, которые делает JavaFX. Плюс поверь мне, они крутятся. Настройте с любой легкой графикой, которая вам нравится.

Теперь переместите все ваши тяжелые работы во вторичный метод, который инкапсулирует усилия в объекте javafx.concurrent.Task:

    public void refreshScene(final SomeBigDataFileDataObject fileObj) {
        Task loadTask = new Task() {
            @Override
            protected Object call() throws Exception {
                dobj = fileObj;
                SomeBigDataFile dataFile = new SomeBigDataFile(dobj.getPrimaryFile().getPath(),true);
                barChartXAxis.setCategories(FXCollections.<String>observableArrayList(dataFile.getColumnLabelsContent()));                
                buildStackedBarChart();               
                buildScatterChart();
                Platform.setImplicitExit(false);
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        pane.setTop(stackedBarChart);
                        barPi.setVisible(false);
                        pane.setCenter(scatterChart);
                        scatterPi.setVisible(false);
                    }
                });
             return null;   
            }
        };
        new Thread(loadTask).start();
    }

Вот то , что может поймать некоторые из вас , как это было со мной: Убедитесь , что ваша сцена строительства выполняется внутри вызова Task () метод , но вне метода Platform.runLater () Run (). Все, что находится внутри Platform.runLater (), все равно будет блокироваться и не будет выполняться асинхронно. Единственное, что вам нужно внутри вашего runLater (), это то, что ДОЛЖНО  быть, то есть все, что напрямую изменяет сам экран, например, добавление ваших полностью скомпонованных компонентов JavaFX в сцену.

Совет Sorta-Pro: постройте его асинхронно … добавьте его синхронно.

Затем просто вызовите новый метод refreshScene () после добавления компонента JFXPanel в исходное представление Swing. Я просто добавляю это обратно в оригинальный конструктор TopComponent:

    public SomeBigDataFileVisualElement(Lookup lkp) {
        obj = lkp.lookup(SomeBigDataFileDataObject.class);
        assert obj != null;
        initComponents();
        toolbar.setFloatable(false);
        final JFXSomeBigDataFilePanel jfxpanel = new JFXSomeBigDataFilePanel();        
        add(jfxpanel, BorderLayout.CENTER);
        jfxpanel.refreshScene(obj);
    }

И вуаля, вы увидите несколько блесен, за которыми следует ваша полная сцена JavaFX. Например, прямо из моего программного обеспечения наземной системы NASA GGSS:

образ

Теперь, когда у меня загружены данные, мне не нужно беспокоиться о моих по-настоящему дурацких неэффективных алгоритмах разбора файлов !!

Бонус:

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