Статьи

Узлы с иконками динамического значения

Nodes API предоставляет функциональные возможности для представления объектов данных. Он включает в себя функциональность для настройки способа отображения узлов в представлениях проводника. В этом коротком руководстве основное внимание уделяется изменению значка значения для свойства узла.

В учебном руководстве по API узлов NetBeans подробно объясняется, как использовать API узлов. Предполагается, что читатель знаком с основами этого учебного пособия, и поэтому некоторые его части не рассматриваются в деталях.

Цель учебника

Цель данного руководства — создать представление, отображающее количество пользователей, подключенных к системе. Когда количество пользователей падает до 0, состояние подключения должно включать значок предупреждения. На рисунке 1 показан желаемый конечный результат. Представление — это TopComponent, содержащий OutlineView.

Рисунок 1: Завершенное окно статуса

Шаг 1: Создание проектов

Начните с создания нового проекта приложения платформы NetBeans и добавления в него нового пустого модуля. Все классы будут созданы в этом модуле. База кодовых имен, которую я выбрал для своего модуля, — это za.co.kitt.demo.nodesdemo — не забудьте изменить расположение изображений в фрагментах кода, чтобы они отражали вашу базу кодовых имен.

Добавьте зависимости от следующих библиотек в ваш модуль:

  • API Explorer & Property Sheet
  • Nodes API
  • Утилиты API

Добавьте эти две иконки в ваш модуль:

Шаг 2: Создание объекта API

Следующим шагом является создание объекта API, который будет содержать данные, которые будут представлены. Nodes API предназначен только для уровня представления, и поэтому узлы не должны содержать фактические данные напрямую. Очень простой класс StatusObject показан ниже.

/**
 * Status data object, containing a single property for the
 * number of clients online.
 */
public class StatusObject
{
    int mNumberOfClientsOnline = 0;

    public int getNumberOfClientsOnline()
    {
        return mNumberOfClientsOnline;
    }

    public void setNumberOfClientsOnline(int NumberOfClientsOnline)
    {
        mNumberOfClientsOnline = NumberOfClientsOnline;
    }
}

Шаг 3: Создание узла

Создайте класс StatusNode, как показано ниже.

import java.awt.Image;
import java.lang.reflect.InvocationTargetException;
import org.openide.nodes.Children;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Sheet;
import org.openide.nodes.PropertySupport;
import org.openide.util.ImageUtilities;

/**
 * Node object demonstrating value icons.
 */
public class StatusNode extends AbstractNode
{

    private StatusObject mStatus = null;

    /**
     * Constructor.
     * @param Status The object containing the status to be displayed.
     */
    public StatusNode(StatusObject Status)
    {
        super(Children.LEAF);
        mStatus = Status;
        setDisplayName("Online");
    }

    @Override
    public Image getIcon(int type)
    {
        return ImageUtilities.loadImage(
                "za/co/kitt/demo/nodesdemo/nodeicon.png", true);
    }

    @Override
    public Image getOpenedIcon(int type)
    {
        return getIcon(type);
    }

    /**
     * Create a property sheet containing only the single status property.
     */
    @Override
    protected Sheet createSheet()
    {
        Sheet sheet = Sheet.createDefault();
        Sheet.Set set = Sheet.createPropertiesSet();
        set.put(new StatusProperty());
        sheet.put(set);
        return sheet;
    }

    /**
     * Property class displaying the number of online users.
     */
    public class StatusProperty extends PropertySupport.ReadWrite
    {

        /**
         * Constructor.
         */
        public StatusProperty()
        {
            super("Status", int.class, "Number of Users", "Number of Users");
        }

        /**
         * Get the value of the number of clients online property.
         * @return The number of clients online.
         * @throws IllegalAccessException
         * @throws InvocationTargetException
         */
        @Override
        public Object getValue() throws IllegalAccessException,
                InvocationTargetException
        {
            return mStatus.getNumberOfClientsOnline();
        }

        /**
         * Set the value of the number of clients online property.
         * @param NewValue The new value of the property.
         * @throws IllegalAccessException
         * @throws IllegalArgumentException
         * @throws InvocationTargetException
         */
        @Override
        public void setValue(Object NewValue) throws IllegalAccessException,
                IllegalArgumentException, InvocationTargetException
        {
            mStatus.setNumberOfClientsOnline((Integer) NewValue);
        }
    }
}

Этот класс можно в основном воссоздать, следуя учебному руководству по API узлов NetBeans , возможно, за исключением внутреннего класса StatusProperty. Это очень простое расширение свойства ReadWrite, которое на данный момент содержит только методы getValue и setValue.

Сам узел имеет иконку, возвращаемую методом getIcon () (иконка # показана на рисунке 1).

Шаг 4: Создание верхнего компонента

Создайте новый TopComponent в модуле. Когда будет предложено указать положение окна, выберите Проводник. Для удобства установите флажок «Открыть при запуске приложения».

Создайте приватное поле в TopComponent для содержания объекта статуса:

private StatusObject mStatus = new StatusObject();

Измените класс TopComponent для реализации интерфейса ExplorerManager.Provider и добавьте в класс следующее:

private final ExplorerManager mgr = new ExplorerManager();

public ExplorerManager getExplorerManager()
{
    return mgr;
}

В режиме конструктора перетащите область прокрутки из категории «Контейнеры Swing» на TopComponent и назовите ее mScrollPane. Измените пользовательский код создания для mScrollPane на:

new OutlineView()

и исправить импорт.

Наконец, в конструкторе TopComponent после вызова initComponents () добавьте:

StatusNode node = new StatusNode(mStatus);
((OutlineView) mScrollPane).setPropertyColumns(
        "Status", "Number of Users");
mgr.setRootContext(node);
associateLookup(ExplorerUtils.createLookup(mgr, getActionMap()));

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

Рисунок 2: Окно состояния без значка значения

Шаг 5: Добавление неизменного значка

На странице Настройка способа отображения свойств на странице javadoc перечислены все пользовательские параметры, которые могут быть установлены для указания редакторам, как отображать свойство. (Я обнаружил эту страницу только после отладки исходного кода org.openide.explorer во время поиска чего-то еще.)

Одним из этих параметров является valueIcon. Это означает, что мы можем добавить

setValue("valueIcon", ImageUtilities.loadImage(
                "za/co/kitt/demo/nodesdemo/error_1.png", true));

в конструктор класса StatusProperty, чтобы навсегда установить значок значения для свойства. Однако, если мы хотим удалить значок позже,

setValue("valueIcon", null);

вызовет исключение нулевого указателя, поскольку базовая коллекция не допускает нулевых значений. Если мы попробуем

setValue("valueIcon", new ImageIcon());

при редактировании значения отображается нежелательное пустое пространство, как показано на рисунке 3.

Рисунок 3: Нежелательное пустое пространство

Шаг 6: Динамическое изменение значка значения

Чтобы разрешить изменение значка в соответствии с данными StatusObject, просто добавьте следующее переопределение метода в класс StatusProperty:

/**
 * Gets the value of the named attribute.
 * @param AttributeName The name of the attribute.
 * @return If the attribute is "valueIcon", the return value is either
 * null if there are clients online, or an icon if no clients are
 * online.
 */
@Override
public Object getValue(String AttributeName)
{
    if ("valueIcon".equals(AttributeName))
    {
        if (mStatus.getNumberOfClientsOnline() == 0)
        {
            return ImageUtilities.loadImage(
                    "za/co/kitt/demo/nodesdemo/error_1.png", true);
        }
        else
        {
            return null;
        }
    }
    return super.getValue(AttributeName);
}

Обратите внимание, что вызов setValue (), добавленный на шаге 5, больше не имеет никакого эффекта и может быть безопасно удален.

Вывод

Динамически изменяющиеся значки значений являются мощным способом предоставления пользователю обратной связи о состоянии объектов данных, отображаемых узлами. Просто переопределяя метод свойства getValue (String), значки можно изменить с минимальными усилиями.

С http://www.kitt.co.za/index.php/articles/nodes-with-dynamic-value-icons/