Статусная строка StatusbarManager

Одним из важнейших элементов пользовательского интерфейса является статусная строка Statusbar, в которой, как правило, отображается дополнительная информация. К сожалению, библиотека SWT не содержит готового визуального компонента (по крайней мере, мне не удалость найти его). В данной статье рассматривается разработка собственного менеджера статусной строки StatusbarManager, который должен реализовывать следующие функции:

  • создание нескольких разделов/частей статусной строки для отображения различной информации;
  • определение размеров разделов и высоты статусной строки;
  • определение фонового цвета, подсветка текстовой информации различным цветом;
  • определение шрифта текстовых компонентов;
  • размещение в статусной строке готовых SWT компонентов.

Структурно статусная строка может состоять из нескольких разделов Composite, в которых размещаются компоненты типа метки Label и выпадающие списки Combo. Менеджер статусной строки StatusbarManager позволяет установить в один или несколько разделов компоненты Control, созданные отдельно, т.е. не StatusbarManager'ом.

Для каждого раздела можно установить определенный размер. Первый раздел (отсчет от 1) занимает все свободное пространство. StatusbarManager включает пустой метод onResize, который можно переписать, чтобы изменить порядок автоматической подстройки не только первого, но и других разделов.

Ниже представлено полное описание менеджера статусной строки StatusbarManager, включающее поля, методы. Завершается описание примером использования StatusbarManager.

Конструкторы StatusbarManager

/**
 * Конструктор
 * @param parent родительский компонент размещения статусной строки
 */
public StatusbarManager(Composite parent)
{
    super(parent, SWT.NONE);
    // Определение менеджера расположения
    setLayout(new FormLayout());
    // Определение цвета фона
    setBackground(new Color(getDisplay(), 240, 240, 240));
    // Определение шрифта
    font = new Font(parent.getDisplay(),
                           new FontData(FONT_Lucida, 10, SWT.NORMAL));
}
//------------------------------------------------------------------
/**
 * Конструктор
 * @param parent родительский компонент размещения статусной строки
 * @param background цвет фона
 */
public StatusbarManager(Composite parent, final Color background)
{
    this(parent);
    setBackground(background);
}

В основном конструкторе (верхний) устанавливаются значения по умолчанию. В качестве входных параметров он принимает родительский компонент размещения parent. Можно использовать второй конструктор, которому дополнительно нужно передать цвет фона.

Параметры настройки StatusbarManager

В следующем листинге представлены параметры (поля класса), используемые менеджером статусной строки StatusbarManager по умолчанию.

                        // Высота статусной строки
private         int     STATUSBAR_HEIGTH = 27;
                        // Параметры позиционирования компонентов  
private         int     OFFSET_TOP       =  2;
private         int     OFFSET_LEFT      =  5;
private         int     OFFSET_RIGHT     = -5;
private         int     OFFSET_BOTTOM    = -2;
                        // Шрифт по умолчанию 
private  final  String  FONT_Lucida      = "Lucida";
private         Font    font             = null    ;
                        // Константы выравнивания
private  final  String  CENTER           = "CENTER";
private  final  String  RIGHT            = "RIGHT" ;
private  final  String  RESIZE           = "-1"    ;
                        // Слушатель изменения размера статусной строки
private         Listener ResizeListener  = null;

Общие параметры по умолчанию включают высоту статусной строки, отступ компонентов от границ разделов, шрифт текстовых меток. Кроме этого, по умолчанию в конструкторе определяется фоновый цвет компонентов. Все параметры, используемые по умолчанию, закрыты (private), но их можно изменить.

Методы определения высоты StatusbarManager

// Функция получения значения высота статусной строки
public int getHeight()
{
    return STATUSBAR_HEIGTH;
}
//------------------------------------------------------------------
// Процедура определения высоты статусной строки
public void setHeight(final int height)
{
    STATUSBAR_HEIGTH = height;
}

Методы определения шрифта

Методы определения шрифта позволяют установить шрифт как для всех компонентов, так и для отдельного компонента, определенного идентификатором раздела.

/**
 * Процедура определения шрифта компонентов
 * @param font шрифт
 */
public void setFont(final Font font)
{
    Control[] ctrls = getChildren();
    for (int i = 0; i < ctrls.length; i++)
        setFont(i, font);
}
//------------------------------------------------------------------
/**
 * Процедура определения шрифта компонента
 * @param idx идентификатор раздела
 * @param font шрифт
 */
public void setFont(final int idx, final Font font)
{
    Control control = getControl(idx);
    if (control != null){
        if (control instanceof Label)
            ((Label)control).setFont(font);
        else if (control instanceof CLabel)
            ((CLabel)control).setFont(font);
        else if (control instanceof Combo)
            ((Combo)control).setFont(font);
    }
}

Методы определения цвета текста

Цвет можно установить только для компонентов типа меток Label/CLabel и для выпадающих списков Combo.

/**
 * Процедура определения цвета текста компонента
 * @param idx идентификатор раздела
 * @param color цвет текста
 */
public void setForeground(final int idx, final Color color)
{
    Control control = getControl(idx);
    if (control != null){
        if (control instanceof Label)
            ((Label)control).setForeground(color);
        else if (control instanceof CLabel)
            ((CLabel)control).setForeground(color);
        else if (control instanceof Combo)
            ((Combo)control).setForeground(color);
    }
}

Метод определения цвета фона

Цвет фона устанавливатеся как для раздела, так и для компонента раздела.

public void setBackgroundColor(final Color color)
{
    setBackground(color);
    for (Control control : getChildren()) {
        control.setBackground(getBackground());
        for (Control ctrl : ((Composite)control).getChildren()) {
            ctrl.setBackground(getBackground());
        }
    }
}

Методы извлечения раздела и компонента менеджера StatusbarManager

Следующие два метода позволяют получить раздел Composite статусной строки и компонент Control раздела.

/**
 * Функция получения панели по идентификатору раздела
 * @param idx идентификатор раздела
 * @return панель
 */
private Composite getComposite(final int idx)
{
    // Реальный идентификатор раздела
    int index = getChildren().length - 1 - idx;
    if (getChildren().length > 0)
        return (Composite) getChildren()[index];
    else
        return null;
}
//------------------------------------------------------------------
/**
 * Функция получения компонента статусной строки по идентификатору
 * @param idx идентификатор раздела статусной строки
 * @return Control компонент
 */
public Control getControl(final int idx)
{
    Composite panel = getComposite(idx);
    Control[] controls = panel.getChildren();
    if ((controls != null) && (controls.length > 0))
        return controls[controls.length - 1];
    else
        return null;
}

Методы позиционирования компонентов StatusbarManager

Методы позиционирования компонентов статусной строки позволяют определить отступы по горизонтали и вертикали как для всех компонентов (setOffsetHorizontal, setOffsetVertical), так и индивидуально для отдельных компонентов (перегруженный метод setOffset).

/**
 * Процедура позиционирования компонентов по вертикали 
 */
public void setOffsetVertical(final int top, final int bottom)
{
    OFFSET_TOP    =  top;
    OFFSET_BOTTOM = -bottom;
}
//------------------------------------------------------------------
/**
 * Процедура позиционирования компонентов по горизонтали
 */
public void setOffsetHorizontal(final int left, final int right)
{
    OFFSET_LEFT  =  left;
    OFFSET_RIGHT = -right;
}
//------------------------------------------------------------------
/**
 * Процедура позиционирования компонента
 * @param idx идентификатор раздела
 */
public void setOffset(final int idx, final int left, final int top, 
                      final int right) {
    Control control = this.getControl(idx);
    if (control == null)
        return;
    FormData fd_src = (FormData) control.getLayoutData();
    FormData fd = new FormData(SWT.DEFAULT, SWT.DEFAULT);
    fd.left   = new FormAttachment(  0, left );
    fd.top    = new FormAttachment(  0, top  );
    fd.right  = new FormAttachment(100, -right);
    fd.bottom = fd_src.bottom;
    
    control.setLayoutData(fd);
}
//------------------------------------------------------------------
/**
 * Процедура позиционирования компонента
 * @param idx идентификатор раздела
 */
public void setOffset(final int idx, final int left, final int top, 
                      final int right, final int bottom) {
    Control control = this.getControl(idx);
    if (control == null)
        return;
    FormData fd = new FormData(SWT.DEFAULT, SWT.DEFAULT);
    fd.left   = new FormAttachment(  0, left  );
    fd.top    = new FormAttachment(  0, top   );
    fd.right  = new FormAttachment(100,-right );
    fd.bottom = new FormAttachment(100,-bottom);
    control.setLayoutData(fd);
}

Процедура формирования статусной строки

Процедура формирования статусной строки setItems в качестве параметра принимает двухмерный массив items с описанием разделов. Формат описания включает три текстовых параметра:

  • выравнивание [left, right, center], по умолчанию используется left;
  • размер раздела, первый раздел занимает все свободное (оставшееся) пространство;
  • тип компонента [Label, Combo].

Пример описания статусной строки:

String[][] STATUSBAR = {{"left" , "-1", "label"},
                        {"right", "80", "label"}, 
                        {""     , "60", "combo"}, 
                        {""     , "90", "null"}};

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

Листинги методов setItems, createLabel, createCombo

В методе setItems в цикле создаются разделы, начиная с последнего в обратном порядке, с привязкой правой стороной к предыдущему компоненту. Если определен компонент, то в зависимости от типа вызваются метод createLabel или createCombo.

/**
 * Процедура формирования статусной строки.
 * Структура статусной строки включает набор панелей, на которых 
 * размещаются компоненты
 * @param items
 */
public void setItems(final String[][] items)
{
    if ((items == null) || (items.length < 1))
        return;
    for (int i = items.length - 1; i >= 0; i--) {
        Composite last = null;
        if (i != items.length - 1)
            last = (Composite) getChildren()[getChildren().length - 1];
        int width = 50;
        if (!items[i][1].equals(RESIZE)) {
            width = Integer.valueOf(items[i][1]);
            if (width < 10)
                width = 10;
        }
        FormData fd = new FormData(SWT.DEFAULT, SWT.DEFAULT);
        fd.top    = new FormAttachment(  0,0);
        fd.bottom = new FormAttachment(100,0);
        if (i == items.length - 1) {
            fd.width  = width;
            fd.right = new FormAttachment(100, 0);
                if (items.length == 1)
                    fd.left  = new FormAttachment(0, 0);
        } else if (i != 0) {
            fd.width  = width;
            fd.right = new FormAttachment(last, 1);
        } else {
            // 1-раздел занимает оставшееся пространство
            fd.left  = new FormAttachment(0, 0);
            fd.right = new FormAttachment(last, 1);
        }
        Composite panel = new Composite(this, SWT.BORDER);
        panel.setBackground(this.getBackground());
        panel.setLayoutData(fd);

        panel.setLayout(new FormLayout());
        if (items[i][2].equalsIgnoreCase(
                                   Label.class.getSimpleName()))
            createLabel(panel, items[i]);
        else if (items[i][2].equalsIgnoreCase(
                                   Combo.class.getSimpleName()))
            createCombo(panel);
    }
}
//------------------------------------------------------------------
/**
 * Функция создания метки статусной строки
 * @param panel панель размещения
 * @param items описание метки
 */
private void createLabel(Composite panel, final String[] items)
{
    int alignment = SWT.LEFT;
    if (items[0].equalsIgnoreCase(CENTER))
        alignment = SWT.CENTER;
    else if (items[0].equalsIgnoreCase(RIGHT))
        alignment = SWT.RIGHT;
    Label label = new Label(panel, SWT.NONE);
    label.setFont(font);
    label.setLayoutData(createFormData());
    label.setAlignment(alignment);
    label.setBackground(this.getBackground());
}
//------------------------------------------------------------------
/**
 * Функция создания выпадающего списка
 * @param panel панель размещения
 */
private void createCombo(Composite panel)
{
    FormData fd = new FormData(SWT.DEFAULT, SWT.DEFAULT);
    fd.left   = new FormAttachment(  0, 0);
    fd.top    = new FormAttachment(  0, 0);
    fd.right  = new FormAttachment(100, 0);

    Combo combo = new Combo(panel, SWT.READ_ONLY | SWT.DROP_DOWN);
    combo.setLayoutData(fd);
}

Размещение компонента в статусной строке

При формировании разделов статусной строки в методе setItems менеджер сразу же размещает в них компоненты типа метка Label или выпадающий список Combo, если они определены в описании. Метод setControl позволяет в определенном разделе idx разместить готовый компонент Control. Если в разделе был уже размещен компонент, то он будет скрыт методом setVisible.

/**
 * Процедура установки в статусную строку компонента
 * @param idx идентификатор раздела статусной строки
 * @param control компонент
 * @param position флаг определения параметров позиционирования
 */
public void setControl(final int idx, Control control, boolean position)
{
    Composite panel = getComposite(idx);
    Control[] controls = panel.getChildren();
    control.setParent(panel);
    if (control instanceof Label)
        ((Label)control).setBackground(this.getBackground());
    else if (control instanceof CLabel)
        ((CLabel)control).setBackground(this.getBackground());
    if ((controls != null) && (controls.length > 0)) {
        Control ctrl = controls[controls.length - 1];
        if (position)
            control.setLayoutData(ctrl.getLayoutData());
        ctrl.setVisible(false);
    } else {
        if (position)
            control.setLayoutData(createFormData());
    }
}

Если логическое значение флага position равно true, то параметры позиционирования FormData будут получены у замещаемого компонента или созданы заново методом createFormData.

/**
 * Функция определения параметров местоположения
 * @return FormData
 */
private FormData createFormData()
{
    FormData fd = new FormData(SWT.DEFAULT, SWT.DEFAULT);
    fd.left   = new FormAttachment(  0, OFFSET_LEFT  );
    fd.top    = new FormAttachment(  0, OFFSET_TOP   );
    fd.right  = new FormAttachment(100, OFFSET_RIGHT );
    fd.bottom = new FormAttachment(100, OFFSET_BOTTOM);
    return fd;
}

Методы определения значений компонентов статусной строки

Менеджер статусной строки StatusbarManager включает метод определения значения текстовой метки раздела setText и выпадающего списка setComboItems.

/**
 * Процедура определения текста метки статусной строки.
 * @param idx идентификатор раздела
 * @param text текст
 */
public void setText(final int idx, final String text)
{
    Control control = getControl(idx);
    if ((control != null) && (control instanceof Label))
        ((Label)control).setText(text);
}
//------------------------------------------------------------------
/**
 * Процедура определения значений выпадающего списка 
 * @param idx идентификатор раздела
 * @param items массив значений
 */
public void setComboItems(final int idx, final String[] items)
{
    Control control = getControl(idx);
    if ((control != null) && (control instanceof Combo))
        ((Combo)control).setItems(items);
}

Слушатель изменения размера статусной строки

Для подключения/отключения слушателя изменения размера статусной строки можно использовать методы addResizeListener и removeResizeListener. При подключении слушателя ResizeListener в случае изменения размера строки будет вызван метод onResize(), который можно переопределить, чтобы определить свой способ позиционирования компонентов при изменении размеров статусной строки.

/**
 * Процедура отключения слушателя ResizeListener
 */
public void removeResizeListener()
{
    if (ResizeListener != null)
        removeListener(SWT.Resize, ResizeListener);
}
//------------------------------------------------------------------
/**
 * Процедура подключения слушателя ResizeListener
 */
public void addResizeListener()
{
    if (ResizeListener == null) {
        ResizeListener = new Listener () {
            public void handleEvent (Event e) {
                onResize();
            }
        }; 
        addListener (SWT.Resize, ResizeListener);
    }
}
//------------------------------------------------------------------
/**
 * Процедура обработки события изменения размера статусной строки
 */
protected void onResize()
{
    // System.out.println("Размер статусной строки изменился");
}

Пример использования StatusbarManager

В следующем примере создается менеджер статусной строки StatusbarManager, который размещается в нижней части формы. В примере используется модуль работы с изображениями IconCache, подробное описание которого с примером представлено на странице Toolbar, ToolItem, IconCache.

Описание статусной строки STATUSBAR включает 4 раздела. Во втором и четвертом разделах будут размещены отдельные компоненты. Значения для выпадающего списка определены в массиве COMBO_ITEMS. Сначала будут созданы только разделы статусной строки. Метод createStatusbarItems с дополнительными настройками не будет вызван.

public class StatusbarTest
{
    public   static  Display    display    = null;
    public   static  Shell      shell      = null;

    private  StatusbarManager   statusbar  = null;

    protected        IconCache  iconCache;
    protected  final int        ICON_print = 0;
    private    final int        ICON_SHELL = 1;
    protected  final int        ICON_file  = 2;
    private   final  String[]   IMAGES     = {"print.gif"  ,
                                              "shell.gif"  ,
                                              "file.gif"
                                             };
    private  final  String[][]  STATUSBAR = {{"left"  ,  "-1", "label"},
                                             {"left"  ,  "90", "null" }, 
                                             {"right" ,  "60", "combo"}, 
                                             {"center",  "90", "null"}};
    private  final  String[]  COMBO_ITEMS = {"  10", "  25", "  50", 
                                             "  75", " 100", " 250"};
    //------------------------------------------------------------------
    public StatusbarTest() 
    {
        shell.setLayout(new FormLayout());
        // Кэш изображений
        iconCache = new IconCache();
        iconCache.setImagesDir("/images/");
        // Загрузка изображений
        iconCache.loadImages (display, IMAGES);

        statusbar = new StatusbarManager(shell);
        FormData fd = new FormData(SWT.DEFAULT, SWT.DEFAULT);
        fd.left   = new FormAttachment(  0, 0 );
        fd.right  = new FormAttachment(100, 0 );
        fd.bottom = new FormAttachment(100, 0);
        fd.height = statusbar.getHeight();

        statusbar.setLayoutData(fd);
        statusbar.setItems(STATUSBAR);

        // Установка иконки приложения
        shell.setImage(iconCache.getImage(ICON_SHELL));

        // createStatusbarItems();

        // Подключение/отключение слушателя ResizeListener
        // statusbar.removeResizeListener();
        // statusbar.addResizeListener();
    }
    //------------------------------------------------------------------
    public static void main(String[] args)
    {
        display = new Display();
        shell   = new Shell (display);
        shell.setText("Пример использования StatusbarManager");
        new StatusbarTest();

        shell.setSize(420, 200);
        shell.open ();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch ())
                display.sleep ();
        }
        display.dispose ();
        System.exit(0);
    }
}

Интерфейс примера использования менеджера статусной строки StatusbarManager без вызова метода createStatusbarItems представлен на следующем скриншоте.

Листинг метода createStatusbarItems

В методе createStatusbarItems будут выполнены следующие настройки статусной строки:

  • Первый раздел - изменен шрифт и цвет текстовой метки;
  • Второй раздел - размещение метки CLabel, включающая изображение и текст;
  • Третий раздел - определение значений выпадающего списка;
  • Четвертый раздел - размещение кнопки с изображением.
private void createStatusbarItems()
{
    statusbar.setText(0, "Тестовая строка");
    statusbar.setForeground(0, new Color(display, 32, 32, 255));
    Font font = new Font(display, new FontData("Courier New", 10, 
	                                            SWT.ITALIC));
    statusbar.setFont(0, font);

    CLabel label = new CLabel(shell, SWT.NONE);
    label.setImage(iconCache.getImage(ICON_file));
    label.setText("Файл");
    label.setAlignment(SWT.LEFT);
    statusbar.setControl(1, label, true);
	
    statusbar.setComboItems(2, COMBO_ITEMS);
    ((Combo)statusbar.getControl(2)).select(1);

    FormData fd = new FormData(SWT.DEFAULT, SWT.DEFAULT);
    fd.left   = new FormAttachment(  0, 0);
    fd.top    = new FormAttachment(  0, 0);
    fd.right  = new FormAttachment(100, -0);
    fd.bottom = new FormAttachment(100, -0);

    Button button = new Button (shell, SWT.NONE);
    button.setImage(iconCache.getImage(ICON_print));
    button.setText("Печать");
    button.setLayoutData(fd);
    statusbar.setControl(3, button, false);
}

Интерфейс примера использования менеджера статусной строки StatusbarManager с вызовом метода createStatusbarItems представлен на следующем скриншоте.

Скачать SWT пример тестирования StatusbarManager

Исходный код рассмотренного примера SWT StatusbarTest в виде проекта Eclipse можно скачать здесь (6.42 Мб). Библиотека labir.utils.jar, используемая в примере, включает StatusbarManager, полное описание которого (поля, методы) представлено на этой странице. Также библиотека включает класс IconCache, полное описание которого (поля, методы) представлено на странице Toolbar, ToolItem, IconCache.

  Рейтинг@Mail.ru