В Codename One - универсальный метод для получения всех компонентов данного типа. - PullRequest
1 голос
/ 07 мая 2019

Я знаю, что в Codename One я могу получить все Компоненты данного типа (и его подтипов), используя рекурсивный метод, подобный следующему:

recursiveSearch(Display.getInstance().getCurrent());

public void recursiveSearch(Container cnt) {
    for (Component cmp : cnt.getChildrenAsList(true)) {
        if (cmp instanceof Label) {
            // for debugging
            Log.p(cmp.toString());
        } else if (cmp instanceof Container) {
            recursiveSearch((Container) cmp);
        }
    }
}

Моя проблема в том, что я хотел бы обобщить этот тип поиска, потому что я использую его много раз во время разработки.

Вот почему я написал для этого новый класс с двумя статическими методами. Но мой код не является точным эквивалентом предыдущего recursiveSearch, потому что он не возвращает подтипы. Например, если я ищу все Label s, я ожидаю также получить Button s, потому что Button - это Label. Но это не так: со следующим кодом я получу только экземпляры Label, которые не являются экземплярами подклассов Label.

Можете ли вы помочь мне исправить это? Спасибо

Я понимаю, что этот вопрос больше относится к универсальной Java, чем к Codename One, однако его использование специфично для Codename One.

public class Selector extends ComponentSelector {

    /**
     * Returns a Set of Components of the given type.
     *
     * @param <T>
     * @param type
     * @return
     */
    public static <T extends Component> Set<T> $(Class<T> type) {
        return Selector.$(type, null);
    }

    /**
     * Returns a Set of Components of the given type, searching for them in the
     * children of the given Container.
     *
     * @param <T>
     * @param type
     * @param root
     * @return
     */
    public static <T extends Component> Set<T> $(Class<T> type, Container root) {
        Set<T> result = new LinkedHashSet<>();
        if (root == null) {
            root = Display.getInstance().getCurrent();
            if (root == null) {
                throw new IllegalStateException("Selector.$(Class<T> type) invoked without a shown Form");
            }
        }
        for (Component cmp : root.getChildrenAsList(true)) {
            if (cmp.getClass().isAssignableFrom(type)) {
                result.add((T) cmp);
            } else if (cmp instanceof Container) {
                result.addAll(Selector.$(type, (Container) cmp));
            }
        }

        return result;
    }

}

Пример тестирования:

Log.p(Selector.$(Label.class).toString());

Ответы [ 2 ]

1 голос
/ 08 мая 2019

Вот функция-обертка, которую я использую для этой цели.

    /**
     * Find set of specific type of component in subtree rooted at root container.
     * @param <T> The type of the component to find.
     * @param type The class of the component to find.
     * @param root The root from which to search
     * @return A set of components of the given type.
     */
    public static <T> Set<T> select(Class<T> type, Container root) {
        return (Set<T>) $("*", root).filter(c -> {
            return type.isAssignableFrom(c.getClass());
        });
    }

Обратите внимание, что метод filter() ComponentSelector уже почти все делает.Обертывание этого метода с параметром типа делает его более удобным для использования.

1 голос
/ 07 мая 2019

Если вы не включите это:

cmp.getClass().isAssignableFrom(type)

К этому:

type.isAssignableFrom(cmp.getClass())
...