Customizes the JavaFX ChoiceBox to call the callback until user clicks on the ChoiceBox or after a delay. - Java JavaFX

Java examples for JavaFX:ChoiceBox

Description

Customizes the JavaFX ChoiceBox to call the callback until user clicks on the ChoiceBox or after a delay.

Demo Code

/*/*from  w  w  w  . j  av a 2 s. co  m*/
 * Copyright (c) 2002-2015, JIDE Software Inc. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */
//package com.java2s;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.control.ChoiceBox;

import javafx.util.Callback;
import javafx.util.Duration;

public class Main {
    private final static String PROPERTY_TASK = "LazyLoadUtils.Task";

    /**
     * Customizes the ChoiceBox to call the callback until user clicks on the ChoiceBox or after a delay.
     *
     * @param choiceBox     the ChoiceBox.
     * @param callback      the callback to create the ObservableList.
     * @param delay         the delay before the callback is called.
     * @param beforeShowing whether to trigger the callback before the ChoiceBox popup is about to show, if the callback
     *                      hasn't called yet.
     * @param initialValue  the initial value. Null if the value has been set on the ChoiceBox.
     * @param <T>           The type of the value that has been selected or otherwise entered in to this ChoiceBox.
     */
    protected static <T> void customizeChoiceBox(ChoiceBox<T> choiceBox,
            Callback<ChoiceBox<T>, ObservableList<T>> callback,
            Duration delay, boolean beforeShowing, T initialValue) {
        Task oldTask = getTask(choiceBox);
        if (oldTask != null) {
            oldTask.cancel(true);
        }

        if (initialValue != null)
            choiceBox.setValue(initialValue);

        Task<ObservableList<T>> task = new Task<ObservableList<T>>() {
            @Override
            protected ObservableList<T> call() throws Exception {
                return callback.call(choiceBox);
            }
        };

        task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent event) {
                T item = choiceBox.getValue();
                Object value = event.getSource().getValue();
                if (value instanceof ObservableList) {
                    //noinspection unchecked
                    choiceBox.setItems((ObservableList<T>) value);

                    //noinspection unchecked
                    if (item == null
                            || !((ObservableList<T>) value).contains(item)) {
                        choiceBox.setValue(null);
                        choiceBox.getSelectionModel().select(0);
                    } else {
                        // trick in order to show the item. should be a bug in JavaFX combobox
                        choiceBox.setValue(null);
                        choiceBox.setValue(item);
                    }
                }
            }
        });

        // when user clicks on the choicebox, we will retrieve the fonts, not using thread because we don't want the empty
        // list to show up. User has to wait for a while if the task takes a long time
        if (beforeShowing) {
            choiceBox.setOnContextMenuRequested(new EventHandler<Event>() {
                @Override
                public void handle(Event event) {
                    if (!task.isRunning() && !task.isDone()) {
                        task.run();
                    }
                    choiceBox.setOnContextMenuRequested(null);
                }
            });
        }

        // or use Timeline to get the font in a thread after 1 second, if user didn't click on the font choicebox before that
        startTimer(delay, task);

        putTask(choiceBox, task);
    }

    private static Task getTask(Node node) {
        Object task = node.getProperties().get(PROPERTY_TASK);
        if (task instanceof Task) {
            return (Task) task;
        } else {
            return null;
        }
    }

    private static <T> void startTimer(Duration delay,
            Task<ObservableList<T>> task) {
        if (delay != null && !delay.isIndefinite()) {
            Timeline timeline = new Timeline();
            timeline.getKeyFrames().add(
                    new KeyFrame(delay, new EventHandler<ActionEvent>() {
                        public void handle(ActionEvent t) {
                            if (!task.isRunning() && !task.isDone()) {
                                new Thread(task).start();
                            }
                        }
                    }));
            timeline.play();
        }
    }

    private static void putTask(Node node, Task task) {
        node.getProperties().put(PROPERTY_TASK, task);
    }
}

Related Tutorials