Афоризм
— Вы что, считаете меня идиотом?
— Нет, но я ведь могу ошибаться.
Последние статьи

 • RawContacts
Необработанные контакты в Android
 • javax.crypto.Cypher
Cимметричное шифрование и дешифрирование
 • Random, Math.random
Генерация случайных чисел
 • Компонент JDatePicker
Описание и пример компонента JDatePicker
 • Компонент Tree
Описание и пример дерева Tree библиотеки base-gui
 • Grid с навигатором
Описание и пример Gridp с навигатором
 • Компонент Grid
Описание и пример Grid библиотеки base-gui
 • Библиотека base-gui
Описание компонентов библиотеки base-gui
 • Оператор SELECT
Использование SQL-оператора SELECT
в помощь разработчикам Swing-приложений

Пример компонента JDatePicker

В статье рассмотрен пример (example-datepicker) использования компонента JDatePicker модуля base-gui, позволяющего выбирать дату из выпадающего календаря. В основе компонента лежит код, созданный Juan Heyns. Доработанный компонент локализован для русского, английского и немецкого языков, позволяет определить первый день недели [Воскресенье, Понедельник].

На следующем скриншоте представлен интерфейс примера.

В примере рассмотрены следующие возможности API компонента JDatePicker модуля base-gui :

  • определение первого дня недели [Вс, По];
  • локализация календаря;
  • чтение выбранной даты;
  • привязка выпадающего календаря к правому/левому краю компонента.

Описание примера

Пример включает класс ExampleDatePicker, который будет представлен в статье следующим образом :

  1. Описание полей класса.
  2. Формирование интерфейса.
  3. Определение первого дня недели.
  4. Локализация.
  5. Чтение значений.
  6. Главный класс ExampleDatePicker.

1. Описание полей класса

Описание полей класса ExampleDatePicker включает метки lblFilter, lblFrom и lblTo, компоненты даты dtFrom и dtTo, константы (модификаторы final не приведены в листинге) определения надписей кнопок управления FIRST_DAY, FIRST_DAYS, LOCALIZATION, CHOOSE. Объекты локализации locale (текущий) и locales (возможные), идентификаторы первого дня недели FIRST_DAY_IDX и текущей локализации LOCALE_idx. Константа PATTERN_DATE определяет формат представления даты в интерфейсе примера. Константа SPAN_normal определяет порядок представления надписей на кнопках.

JLabel           lblFilter = null;
JLabel           lblFrom   = null;
JLabel           lblTo     = null;

JDatePickerImpl  dtFrom    = null;
JDatePickerImpl  dtTo      = null;

String[]   FIRST_DAY       = {"Неделя с <%s>", 
                              "Week from <%s>", 
                              "Woche ab <%s>"};
String[][] FIRST_DAYS      = {{"Вс", "По"},
                              {"Su", "Mo"},
                              {"Mo", "So"}};
String[]   LOCALIZATION    = {"Локализация"   ,
                              "Localization"  , 
                              "Lokalisierung"};
String[]   CHOOSE          = {"Выбор"         ,
                              "Choose"        ,
                              "Auswahl"      };
Locale     locale          = null;
Locale[]   locales         = {new Locale("ru"),
                              new Locale("en"),
                              new Locale("de")};
int        FIRST_DAY_IDX   = 0;
int        LOCALE_idx      = 0;

String     PATTERN_DATE    = "dd.MM.yyyy";

String  SPAN_normal  = 
           "<html><span style=\"font-weight:normal\">";

2. Формирование интерфейса

Метод createGUI формирует интерфейс примера. Особый интерес в коде данного метода представляют строки создания двух компонентов JDatePicker :

  • раздельные модели (modelFrom, modelTo) для двух компонентов дат; в противном случае будет единое значение даты в обоих компонентах;
  • раздельные панели (datePanelFrom, datePanelTo) для двух компонентов дат; каждая панель использует свою модель, в противном случае будет единое значение даты в обоих компонентах;
  • вторым параметром в конструктор JDatePanelImpl передается объект локализации, определяющий языковые надписи, дни недели, список месяцев;
  • конструктор JDatePickerImpl в качестве параметров получает значения JDatePanelImpl (модель даты) и DateLabelFormatter (формат даты).

Примечание : обратите внимание, что для компонентов используются разные модели дат (UtilDateModel, UtilCalendarModel).

private void createGUI()
{
    JPanel  pnlFilter = new JPanel();
    pnlFilter.setLayout(new BorderLayout());
    pnlFilter.setPreferredSize(new Dimension(268, 80));
    Border border = BorderFactory.createCompoundBorder(
            BorderFactory.createEtchedBorder(),
            BorderFactory.createEmptyBorder(15, 10, 15, 4));
    pnlFilter.setBorder(border);

    lblFilter = new JLabel();
    lblFilter.setText(SPAN_normal + "Период времени");

    // Определение параметров компонентов дат
    UtilDateModel       modelFrom    ;
    UtilCalendarModel   modelTo      ;
    JDatePanelImpl      datePanelFrom;
    JDatePanelImpl      datePanelTo  ;
    DateLabelFormatter  dlf          ;

    modelFrom     = new UtilDateModel    ();
    modelTo       = new UtilCalendarModel();
    datePanelFrom = new JDatePanelImpl(modelFrom, locale);
    datePanelTo   = new JDatePanelImpl(modelTo  , locale);
    dlf           = new DateLabelFormatter(PATTERN_DATE);
    //-----------------------------------------------------
    Dimension dim      = new Dimension(100, 20);
    Dimension dimLabel = new Dimension( 30, 20);
    //-----------------------------------------------------
    lblFrom = new JLabel();
    lblFrom.setText(SPAN_normal + "c");
    lblFrom.setPreferredSize(dimLabel);

    dtFrom = new JDatePickerImpl(datePanelFrom, dlf);
    dtFrom.setPreferredSize(new Dimension(145, 20));
    dtFrom.getJFormattedTextField().setBackground(Color.WHITE);

    SpringLayout layoutFilter = new SpringLayout();
    JPanel pnlFrom = new JPanel(layoutFilter);

    pnlFrom.add(lblFrom);
    pnlFrom.add(dtFrom);
    pnlFrom.setPreferredSize(dim);
    pnlFrom.setSize         (dim);
    layoutFilter.putConstraint(SpringLayout.WEST, dtFrom, 30,
                               SpringLayout.EAST, lblFrom);
    //-----------------------------------------------------
    lblTo = new JLabel();
    lblTo.setText(SPAN_normal + "по");
    lblTo.setPreferredSize(dimLabel);

    dtTo = new JDatePickerImpl(datePanelTo, dlf);
    dtTo.setPreferredSize(new Dimension(145, 20));
    dtTo.getJFormattedTextField().setBackground(Color.WHITE);

    JPanel pnlTo = new JPanel(layoutFilter);

    pnlTo.add(lblTo);
    pnlTo.add(dtTo);
    pnlTo.setPreferredSize(dim);
    pnlTo.setSize         (dim);
    layoutFilter.putConstraint(SpringLayout.WEST, dtTo, 30,
                               SpringLayout.EAST, lblTo);
    //-----------------------------------------------------
    pnlFilter.add(pnlFrom, BorderLayout.NORTH);
    pnlFilter.add(pnlTo  , BorderLayout.SOUTH);
    //-----------------------------------------------------
    String caption = SPAN_normal + 
                     String.format(FIRST_DAY[LOCALE_idx],
                     FIRST_DAYS[LOCALE_idx][FIRST_DAY_IDX]);
    JButton btnFirstDay = new JButton(caption);

    String caption = SPAN_normal + LOCALIZATION[LOCALE_idx];
    JButton btnLocale   = new JButton(caption);

    String caption = SPAN_normal + CHOOSE[LOCALE_idx];
    JButton btnFilter   = new JButton(caption);

    final int WIDTH_BUTTON = 130;
    dim = new Dimension (WIDTH_BUTTON, 28);
    btnFirstDay.setPreferredSize(dim);
    btnLocale  .setPreferredSize(dim);
    btnFilter  .setPreferredSize(dim);

    // Панель кнопок управления
    JPanel pnlButtons = new JPanel();
    pnlButtons.add(btnFirstDay);
    pnlButtons.add(btnLocale  );
    pnlButtons.add(btnFilter  );
        
    btnFirstDay.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            changeFirstWeekDay();
            String caption = SPAN_normal + 
                     String.format(FIRST_DAY[LOCALE_idx],
                     FIRST_DAYS[LOCALE_idx][FIRST_DAY_IDX]);
            btnFirstDay.setText(caption);
        }
    });
    btnLocale.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            changeLocale();
            btnLocale  .setText(SPAN_normal + 
                                LOCALIZATION[LOCALE_idx]);
            btnFilter  .setText(SPAN_normal + 
                                CHOOSE[LOCALE_idx]);
            btnFirstDay.setText(SPAN_normal + 
                    String.format(FIRST_DAY[LOCALE_idx],
                    FIRST_DAYS[LOCALE_idx][FIRST_DAY_IDX]));
        }
    });

    btnFilter.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            ChoosedDates();
        }
    });
    getContentPane().add(lblFilter , BorderLayout.NORTH );
    getContentPane().add(pnlFilter , BorderLayout.CENTER);
    getContentPane().add(pnlButtons, BorderLayout.SOUTH);
}

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

3. Определение первого дня недели

Исходный код компонента JDatePicker, созданный Juan Heyns, допускает только один вариант первого дня недели «Su» (Sunday). Модифицированный компонент JDatePicker модуля base-gui позволяет выбрать первым днём недели как «Понедельник» (Monday), так и «Воскресенье» (Sunday). Для изменения текущего первого дня недели перезагрузки компонента не требуется, достаточно вызвать метод компонента setFirstDayMonday (boolean); истинное значение параметра (true) определяет первый день недели «Понедельник» (Monday). Ниже представлен листинг метода changeFirstWeekDay, который динамически в режиме run-time изменяет первый день недели в окне календаря.

private void changeFirstWeekDay()
{
    if (++FIRST_DAY_IDX == 2)
        FIRST_DAY_IDX = 0;
    dtFrom.setFirstDayMonday (!dtFrom.isFirstDayMonday());
    dtTo.setFirstDayMonday   (!dtTo  .isFirstDayMonday());
}

На следующем скриншоте представлен открытый календарь компонента с первым днем недели «По» (Понедельник).

На скриншоте описания локализации (см. скриншот ниже) представлено окно календаря с первым днём недели «Su» (Sunday/Воскресенье).

4. Локализация

Локализация в примере касается только наименований кнопок и выпадающего окна календаря. Модифицированный компонент JDatePicker модуля base-gui позволяет использовать один из 3-х языков локализации : [русский (по умолчанию), английский, немецкий]. Для переключения языка локализации не требуется перезагрузка компонента, достаточно вызвать метод компонента changeLocale с объектом локализации, например changeLocale(new Locale("ru")). Ниже представлен листинг метода changeLocale, который динамически в режиме run-time изменяет язык локализации окна раскрывающегося календаря.

private void changeLocale()
{
    if (++LOCALE_idx >= locales.length)
        LOCALE_idx = 0;
    dtFrom.changeLocale(locales[LOCALE_idx]);
    dtTo  .changeLocale(locales[LOCALE_idx]);
}

На скриншоте описания первого дня недели (см.скриншот выше) представлена русскоязычная версия открытого календаря. На следующем скриншоте представлен раскрытый календарь в английской интерпретации : окно выбора месяца, надписи и дни недели представлены на английском языке.

5. Чтение значений

Метод ChoosedDates формирует сообщение с выбранными датами и отображает его в диалоговом окне JOptionPane главного JFrame. Для получения значения даты следует использовать метод getValue модели данных (getModel()) компонента. Если значение даты не определено/выбрано, то метод вернет 'null'.

Примечание : поскольку компоненты дат (dtFrom, dtTo) используют разные модели(UtilDateModel и UtilCalendarModel), то имеются и существенные отличия получения выбранного значения даты.

private void ChoosedDates()
{
    // Выбранные строки
    String msg   = "Вы выбрали период с '%s' по '%s'";
    String title = "Выбор";
    String from  = "null";
    String to    = "null";

    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");

    if (dtFrom.getModel().getValue() != null)
        from = sdf.format(dtFrom.getModel().getValue());

    if ((dtTo.getModel() instanceof UtilDateModel) && 
        (dtTo.getModel().getValue() != null)) 
        to = sdf.format(dtTo.getModel().getValue());
    else if ((dtTo.getModel() instanceof UtilCalendarModel) &&
             (dtTo.getModel().getValue() != null)) {
        Calendar calendar;
        calendar = (Calendar) dtTo.getModel().getValue();
        to = sdf.format(calendar.getTime());
    }
    msg = String.format(msg, from, to);
    JOptionPane.showMessageDialog (ExampleDatePicker.this,
              msg, title, JOptionPane.INFORMATION_MESSAGE);
}

На следующем скриншоте представлено окно с сообщением.

6. Главный класс ExampleDatePicker

Листинг класса ExampleDatePicker (см. код ниже), не включает поля и методы, описанные выше. Полный исходный код примера можно скачать в конце страницы.

В конструкторе класса определяется текущий язык локализации и вызывается метод создания интерфейса.

public class ExampleDatePicker extends JFrame
{
    public ExampleDatePicker()
    {
        super("Form example");
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        setSize(440, 180);
        locale = locales[LOCALE_idx];
        createGUI();
        vsetVisible(true);
    }

    public static void main(String[] args) {
        new ExampleDatePicker();
    }
}

Привязка выпадающего календаря к правому/левому краю компонента

На представленных выше скриншотах видно, что размер компонента по горизонтали меньше ширины открытого календаря. При этом, окно календаря привязано к левой стороне компонента. Исходный JDatePicker, созданный Juan Heyns, не допускал привязку окна календаря к правой стороне компонента при его близком размещении к правой стороне экрана; в этом случае часть календаря не отображалась на экране. Единственным спасением в этом случае было определять ширину компонента не меньше ширины окна календаря.

Доработанный JDatePicker модуля base-gui автоматически привязывает всплывающее окно календаря к правому краю компонента при его близком расположении к правой стороне монитора. Чтобы увидеть это достаточно переместить мышью окно примера в правую часть монитора и открыть окно календаря, как это представлено на следующем скриншоте.

Старт примера

Архив примера включает командный файл run-example-datepicker.bat для старта example-datepicker.jar в Windows из командной строки. Запускаемый example-datepicker.jar (runable) может быть стартован не только из командной строки, но и обычным способом (двойным нажатием клавишей мыши), поскольку модуль lib/base-gui-1.0.0.jar включен в classpath манифеста META-INF/MANIFEST.MF.

Скачать пример

Архивный файл base-gui-example.zip включает данный пример (example-datepicker) и другие примеры использования модуля base-gui.

  Рейтинг@Mail.ru