Афоризм
Идут года, мне все еще за тридцать.
Наталья Резник
Последние статьи

 • Активности Android
Многоэкранные Android приложения
 • Fragment dynamic
Динамическая загрузка фрагментов в Android
 • Fragment lifecycle
Жизненный цикл Fragment'ов в Android
 • Fragment example
Пример Fragment'ов в Android
 • Data Binding
Описание и пример Data Binding
 • Пример MVVM
Пример использования MVVM в Android
 • Компонент TreeTable
Описание компонента TreeTable для Swing
 • Пример TreeTable
Пример использования TreeTable
 • Хранилища Android
Внутренние и внешние хранилища данных
 • Пример SQLite
Пример использования SQLite в Android
 • WebSocket
Описание и пример реализации WebSocket
 • Визуальные компоненты
Улучшен компонент выбора даты из календаря
 • Анимация jQuery
Описание и примеры анимации элементов DOM
 • APK-файл Android
Создание apk-файла для android устройств, .dex файлы
 • платформа JaBricks
Платформа OSGi-приложения JaBricks
Поддержка проекта

Если Вам сайт понравился и помог, то будем признательны за Ваш «посильный» вклад в его поддержку и развитие
 • Yandex.Деньги
  410013796724260

 • Webmoney
  R335386147728
  Z369087728698

Урок 15. Столбчатые и круговые диаграммы

В данном уроке будем заниматься разработкой бандла создания и представления столбчатых и круговых диаграмм в приложениях на платформе JaBricks. Создавать интерфейсный бандл будем не с «нуля». В качестве шаблона используем проект templ-jdialog, наследующего свойства базового модуля base-jdialog. Преимущества использования базового модуля для создания интерфейсного бандла представлены на странице его описания.

Структура проекта

Подготовка проекта. Скачаем архив проекта templ-jdialog и «развернем» его. Проект создан в среде разработки IDE Eclipse. Переименуем директорию проекта в «jfreechart-bar-pie». После этого внесем изменения в наименование проекта (<name>) в файле «jfreechart-bar-pie/.project». Далее переименуем artifactId проекта в «jfreechart-bar-pie/pom.xml». На этом все приготовления проекта к «употреблению» на начальном этапе заканчиваются. После этого импортируем проект в IDE и продолжим структурные преобразования проекта.

Изменим наименование пакета (package) : «org.jabricks.lesson». Также переименуем классы проекта : активатор JDialogActivator назовем LessonActivator, а класс формы JDialogForm переименуем в ChartForm. Соответствующие изменения следует внести и в проектный файл pom.xml, где необходимо переопределить groupId в секции GAV-параметров бандла и <Bundle-Activator> плагина maven-bundle-plugin.

В ресурсных файлах «resources/properties/propertiesXX.properties» изменим только локализованные заголовки (title) формы.

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

На скриншоте слева представлен наш проект бандла в IDE Eclipse. Структура проекта включает LessonActivator, играющего роль активатора бандла, ChartForm, формирующего интерфейс диалогового окна, проектный файл pom.xml, включающего все зависимости модуля и определяющего порядок сборки бандла. Кроме этого, в проекте появился дополнительный класс ModuleDAO и поддиректория repo. ModuleDAO будет играть роль хранилища данных и обеспечивать взаимодействие с утилитой формирования диаграмм util-jfreechart. В поддиректории repo создадим внутри проекта репозиторий для графической библиотеки osgi-jfreechart, наличие которой в проекте необходимо для определения соответствующих зависимостей в pom.xml.

Описание утилиты формирования диаграмм util-jfreechart и её связь с бандлом osgi-jfreechart, являющегося аналогом графической библиотекой org.jfree.jfreechart, представлено на странице модуля. Кроме этого, Вам необходимо также иметь представление о Maven и OSGi, чтобы разобраться со структурой проекта.

Описание проекта

Описание файлов проекта начнем с pom.xml, на содержимое которого реагирует среда разработки IDE отображением ошибок и блокированием всплывающих подсказок.

Проектный файл, pom.xml

Проектный файл pom.xml включает несколько секций : GAV-параметры, репозиторий, свойства, зависимости и сборка. В секции GAV-параметров определены групповой идентификатор groupId, артифакт artifactId, версия и тип сборки packaging. Секция репозитория определяет путь к внутреннему проектному repo. При выполнении сборки проекта бандл osgi-jfreechart из проектного репозитория будет загружен в локальный репозиторий $(user.home)/.m2/repository/.

Следует обратить внимание на секцию зависимостей <dependencies>, включающую описания модулей фреймворка, утилиты управления внешними ресурсами util-resources, модуль компонентов gui-widgets, базовый модуль base-jdialog и модули создания диаграмм (util-jfreechart, osgi-jfreechart). В секции сборки <build> используется плагин создания бандла maven-bundle-plugin, определяющий активатор и импортируемые в модуль пакеты (<Import-Package>).

Листинг

<project xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
              http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.jabricks.lesson</groupId>
  <artifactId>jfreechart-bar-pie</artifactId>
  <packaging>bundle</packaging>
  <version>1.0.0</version>

  <name>JFreechart example (bar, pie)</name>
  <url>http://maven.apache.org</url>
 
  <repositories>
      <repository>
          <id>repo/id>
          <url>file://${basedir}/repo</url>
      </repository>
  </repositories>

  <properties>
      <project.build.sourceEncoding>UTF-8
                          </project.build.sourceEncoding>
      <maven.test.skip>true</maven.test.skip>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
  </properties>
  
  <dependencies>
      <dependency>
        <groupId>org.apache.felix</groupId>
        <artifactId>org.apache.felix.framework</artifactId>
        <version>5.6.1</version>
        <scope>provided</scope>
      </dependency>
      <dependency>
        <groupId>org.apache.felix</groupId>
        <artifactId>org.apache.felix.eventadmin</artifactId>
        <version>1.2.2</version>
        <scope>provided</scope>
      </dependency>
      <dependency>
          <groupId>org.jabricks.resources</groupId>
          <artifactId>util-resources</artifactId>
          <version>1.0.0</version>
          <scope>provided</scope>
      </dependency>
      <dependency>
          <groupId>org.jabricks.widgets</groupId>
          <artifactId>gui-widgets</artifactId>
          <version>1.0.0</version>
          <scope>provided</scope>
      </dependency>
      <dependency>
          <groupId>org.jabricks.jdialog</groupId>
          <artifactId>base-jdialog</artifactId>
          <version>1.0.0</version>
          <scope>provided</scope>
      </dependency>
      <dependency>
          <groupId>org.jfree</groupId>
          <artifactId>osgi-jfreechart</artifactId>
          <version>1.0.19</version>
          <scope>provided</scope>
      </dependency>
      <dependency>
          <groupId>org.jabricks.jfreechart</groupId>
          <artifactId>util-jfreechart</artifactId>
          <version>1.0.0</version>
          <scope>provided</scope>
      </dependency>
  </dependencies>
  
  <build>
      <plugins>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>2.3.2</version>
              <configuration>
                  <source>${maven.compiler.source}</source>
                  <target>${maven.compiler.target}</target>
              </configuration>
          </plugin>
          <plugin>
              <groupId>org.apache.felix</groupId>
              <artifactId>maven-bundle-plugin</artifactId>
              <version>2.3.7</version>
              <extensions>true</extensions>
              <configuration>
                  <instructions>
                     <Bundle-SymbolicName>
                   ${project.groupId}.${project.artifactId}
                                 </Bundle-SymbolicName>
                     <Bundle-Name>${project.name}
                                 </Bundle-Name>
                     <Bundle-Version>${project.version}
                                 </Bundle-Version>
                     <Bundle-Activator>
                         ${project.groupId}.LessonActivator
                                 </Bundle-Activator>
                     <Import-Package>
                          javax.swing.*,
                          org.osgi.framework.*,
                          org.jfree.ui.*,
                          org.jfree.chart.*,
                          org.jfree.data.*,
                          org.jabricks.jfreechart.*,
                          org.jabricks.widgets.*,
                          org.jabricks.jdialog.*,
                          org.jabricks.resources
                     </Import-Package>
                  </instructions>
              </configuration>
          </plugin>
      </plugins>
   </build>
</project>

Класс активатора LessonActivator

Ниже представлен листинг активатора LessonActivator. Практически код активатора не изменился за исключением переименования самого класса активатора и класса формы. Метод start вызывается при старте бандла. В данном методе создается интерфейсная форма ChartForm. После открытия формы выполняется подписка на сообщения локализации. В активатора метод stop не переопределяется. При закрытии формы автоматически будет вызван переопределенный метод saveComponentParams. К интерфейсной кнопке btnClose подключается слушатель закрытия формы. Также к форме подключается слушатель закрытия окна.

Листинг
public class LessonActivator extends JBDialogActivator 
{
    private ChartForm form = null;
    //-----------------------------------------------------
    @Override
    public void start(final BundleContext context) 
                                       throws Exception {
        super.start(context);

        JFrame.setDefaultLookAndFeelDecorated(true);
        IResources resources = new ResourcesImpl();
        Locale locale = resources.getLocale();
        this.form = new ChartForm(context, locale);

        form.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                form.setVisible(false);
                try {
                    // Останов бандла
                    context.getBundle().stop();
                } catch (Exception e) {}
            }
        });
        form.btnClose.addActionListener(closeListener);
        
        form.repaint();
               
        // Открытие окна
        form.setVisible(true);
        
        // Подключение слушателей
        createLocaleSubscriber();
    }
    //-----------------------------------------------------
    @Override
    public void changeLocale (Locale locale) {
        form.changeLocale(locale);
    }
    //-----------------------------------------------------
    private void closeForm() {
        form.setVisible(false);
        form.dispose();
        try {
            context.getBundle().stop();
        } catch (Exception e) {}
    }
    //-----------------------------------------------------
    ActionListener closeListener = new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            closeForm();
        }
    };
    //-----------------------------------------------------
    public void saveComponentParams() {
        if (form != null)
            form.saveComponentParams();
    }
}

Класс формы ChartForm

Ниже представлен листинг класса формирования интерфейса бандла. Конструктор и первые два метода не изменились. Конструктор вызывает метод createGUI, который сначала восстанавливает регулируемые настройки интерфейса (размер окна и положение сплиттера). После этого createGUI создает интерфейс формы, состоящий из двух частей, разделенных сепаратором split. В левой части сепаратора разместим диаграмму, в правой – компоненты выбора диаграммы. Диаграмма будет формироваться в модуле ModuleDAO.

Метод createFormPanel создает правую панель с радио-переключателями для выбора диаграммы. При изменении переключателя вызывается метод selectDiagram, обновляющий диаграмму в интерфейсе.

Листинг
public class ChartForm extends JBDialog
{
    private static final long  serialVersionUID     = 1L;

    private        int         DEFAULT_WIDTH        = 420;
    private        int         DEFAULT_HEIGHT       = 315;

    private  JSplitPane        split;
    private  final  int        DIVIDER_LOCATION     = 300;
    private  final  String     SPLITPANE    = "SPLITPANE";
 
    public   JButton           btnClose             = null;
    private  ResourceBundle    rsc                  = null;

    private  String  RESOURCES_btn_close = "btn.close";
    private  String  RESOURCES = "properties/properties";
 
    private  final   String[][]  names = 
                           {{"10", "Гистограмма, доходы" },
                            {"11", "Гистограмма, расходы"},
                            {"20", "Круговая, расходы"   }};
    //-----------------------------------------------------
    public ChartForm(final BundleContext context, 
                     final Locale locale)
    {
        // без изменений
        . . .
    }
    //-----------------------------------------------------
    private JPanel createButtons()
    {
        // без изменений
        . . .
    }
    //-----------------------------------------------------
    public void changeLocale (Locale locale)
    {
        // без изменений
        . . .
    }
    //-----------------------------------------------------
    private void createGUI()
    {
        // Создание рабочей области
        super.createDesk();
        Border border;
        border = BorderFactory.createEmptyBorder(2,2,2,2);
        pnlDesk.setBorder (border);

        split = new JSplitPane();
        split.setName(SPLITPANE);

        split.setOneTouchExpandable(false);
        split.setOrientation(JSplitPane.HORIZONTAL_SPLIT);

        if (cparams.size() == 0)
            split.setDividerLocation(DIVIDER_LOCATION);
        else {
            ComponentParams cp;
            String   cls = JSplitPane.class.getSimpleName(); 
            cp = extractComponentParams(cls, SPLITPANE);
            if (cp != null)
                split.setDividerLocation(cp.getLocation());
            else
                split.setDividerLocation(DIVIDER_LOCATION);
        }
        pnlDesk.setLayout(new BorderLayout());
        pnlDesk.add(split, BorderLayout.CENTER);

        ChartPanel pnlChart;
        pnlChart = (new ModuleDAO()).createBarChartIncome();

        split.setLeftComponent (pnlChart);		
        split.setRightComponent(createFormPanel());
    }
    //-----------------------------------------------------
    private JPanel createFormPanel()
    {
        JPanel panel = new JPanel();

        ActionListener listener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                JRadioButton radio;
                radio = (JRadioButton) event.getSource();
                selectDiagram(radio.getName());
            }
        };

        // Группа связанных радио-переключателей
        JPanel panelRadio;
        Border border    ;

        String title = "Диаграммы"
        panelRadio = new JPanel(new GridLayout(0, 1, 0, 5));
        border = BorderFactory.createTitledBorder(title);
        panelRadio.setBorder(border);
        ButtonGroup bg = new ButtonGroup();
        for (int i = 0; i < names.length; i++) {
            JRadioButton radio = new JRadioButton(names[i][1]);
            radio.setName(names[i][0]);
           	radio.setSelected(i == 0);
            radio.addActionListener(listener);
            panelRadio.add(radio);
            bg.add(radio);
        }        
        panel.add(panelRadio);
        return panel;
    }
    //-----------------------------------------------------
    private void selectDiagram(final String name)
    {
        int  location = split.getDividerLocation(); 

        ChartPanel cp = null;
        if (name.equals(names[0][0]))
            cp = (new ModuleDAO()).createBarChartIncome();
        else if (name.equals(names[1][0]))
            cp = (new ModuleDAO()).createBarChartOutcome();
        else if (name.equals(names[2][0]))
            cp = (new ModuleDAO()).createPieChartOutcome();

        if (cp != null) {
            split.setLeftComponent (cp);
            split.setDividerLocation(location);
        }
    }

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

Класс ModuleDAO

Класс ModuleDAO представляет главный интерес в данном примере, поскольку именно он решает вопрос подготовки наборов данных и формирования диаграммы. Рассмотрим эти два вопроса по-отдельности.

Подготовка данных

Как мы видели выше, в примере создаются три диаграммы : две столбчатые и одна круговая. Для этих трёх диаграмм будем создавать три набора данных. В ModuleDAO для столбчатых диаграмм определены массивы INCOME и OUTCOME, а для круговой – SECTIONS. Размерности первых двух массивов отличаются от третьего. В целях сокращения нагроможденности в представлении листинга массивы приведены в усеченном виде.

Для формирования наборов данных CategoryDataset для столбчатых диаграмм будем использовать методы createIncomeDataset и createOutcomeDataset, а для создания набора данных PieDataset соответственно метод createPieDataset. Поскольку масивы и результирующие наборы данных для столбчатых диаграмм идентичны, то создадим для них общий метод подготовки createDataset, который будет принимать в качестве параметра массив данных. В методах сначала выполняются преобразования массивов в наборы данных List, после чего вызываются методы createCategoryDataset и createPieDataset утилиты util-jfreechart для пребразования наборов List в соответствующие наборы Dataset.

Листинг
private final String[][] INCOME = {
                      {"52733", "Янв", "Доходы 2018"},
                      {"51345", "Фев", "Доходы 2018"},
                      . . .
                      {"57800", "Дек", "Доходы 2019"}};
                      {"52733", "Янв", "Доходы 2018"},
private final String[][] OUTCOME = {
                      {"50733", "Янв", "Расходы 2018"},
                      {"49345", "Фев", "Расходы 2018"},
                      . . .
                      {"58400", "Ноя", "Расходы 2019"},
                      {"55800", "Дек", "Расходы 2019"}};

private final String[][] SECTIONS = {
                      {"99535" , "Квартира"  },
                      {"520000", "Питание"   },
                      . . .
                      {"58600" , "Автомобиль"},
                      {"15000" , "Дача"     }};
//-----------------------------------------------------
private CategoryDataset createIncomeDataset()
{
    return createDataset(INCOME);
}
//-----------------------------------------------------
private CategoryDataset createOutcomeDataset()
{
    return createDataset(OUTCOME);
}
//-----------------------------------------------------
private CategoryDataset createDataset(String[][] data)
{
    List<CategoryDataItem> list;

    list = new ArrayList<CategoryDataItem>();
    for (int i = 0; i < INCOME.length; i++) {
        CategoryDataItem rc = new CategoryDataItem();
        rc.setValue    (Double.valueOf(INCOME[i][0]));
        rc.setColumnKey(INCOME[i][1]);
        rc.setRowKey   (INCOME[i][2]);
        list.add(rc);
    }
    JFreeChartImpl fci = new JFreeChartImpl();
    return fci.createCategoryDataset(list);
}
//-----------------------------------------------------
private PieDataset createPieDataset()
{
    List<PieDataItem> data_pie;

    data_pie = new ArrayList<PieDataItem>();
    for (int i = 0; i < SECTIONS.length; i++) {
        PieDataItem rp;
        double value = Double.valueOf(SECTIONS[i][0])
                             .doubleValue();
        rp = new PieDataItem(SECTIONS[i][1], value);
        data_pie.add(rp);
    }
    JFreeChartImpl fci = new JFreeChartImpl();
    return fci.createPieDataset(data_pie);
}

Создание диаграмм

Ниже представлены методы ModuleDAO, создающие диаграммы. Условно методы можно разделить на две группы. Первая группа методов без параметров с модификаторами public подготавливает описания диаграмм в виде объектов ChartDescBar и ChartDescPie. Для столбчатых диаграмм используется общий метод с параметрами createBarChart, которому необходимо передать заголовок, подпись оси и dataset. После этого из данных методов вызываются соответствующие закрытые (private) методы с параметром описания диаграммы (createBarChart, createPieChart), где с использованием методов createBarChart и createPieChart утилиты util-jfreechart создаются соответствующие диаграммы.

Листинг

private ChartPanel createBarChart(final String title,
                                 final String y_axis,
                                 CategoryDataset dataset)
{
    ChartDescBar cdb;
    cdb = new ChartDescBar(title, null, y_axis, dataset); 
    cdb.setSubtitle("за 2018-2019 гг");
    return createBarChart(cdb);
}
//---------------------------------------------------------
public ChartPanel createBarChartIncome()
{
    CategoryDataset dataset = createIncomeDataset();

    String title  = "Диаграмма о доходах";
    String y_axis = "Доход";
    return createBarChart(title, y_axis, dataset);
}
//---------------------------------------------------------
public ChartPanel createBarChartOutcome()
{
    CategoryDataset dataset = createOutcomeDataset();

    String title  = "Диаграмма о расходах";
    String y_axis = "Расходы";
    return createBarChart(title, y_axis, dataset);
}
//---------------------------------------------------------
public ChartPanel createPieChartOutcome()
{
    PieDataset dataset = createPieDataset();

    ChartDescPie cdp = new ChartDescPie();
    cdp.setTitle   ("Диаграмма расходов");
    cdp.setSubtitle("2018 год");
    cdp.setDataset (dataset);
    cdp.setLegend  (false);
    cdp.setTooltips(true);

    cdp.setTextTitleAlignment(HorizontalAlignment.LEFT);

    Font font = new Font("Courier New", 
                           Font.PLAIN | Font.ITALIC, 11);
    cdp.setSubtextTitleFont(font);
// cdp.setSubtextTitlePosition(RectangleEdge.BOTTOM);
// cdp.setSubtextTitleAlignment(HorizontalAlignment.RIGHT);

    return createPieChart(cdp);
}
//---------------------------------------------------------
private ChartPanel createBarChart(ChartDescBar cdb)
{
    // Утилита создания диаграммы
    JFreeChartImpl fci = new JFreeChartImpl();
    // Создание диаграммы
    JFreeChart chart = fci.createBarChart(cdb);
    // Скрытие шкал
    fci.hideAxisLineX (chart.getCategoryPlot());
    fci.hideAxisLineY (chart.getCategoryPlot());

    return new ChartPanel(chart); 
}
//---------------------------------------------------------
private ChartPanel createPieChart(ChartDescPie cdp)
{
    JFreeChartImpl fci = new JFreeChartImpl();
    JFreeChart chart = fci.createPieChart(cdp);

    PiePlot plot = (PiePlot) chart.getPlot();
    // Настройка меток названий секций
    Font font = new Font("Arial", Font.BOLD, 11);
    fci.setPiePlotLabels(plot, font, Color.DARK_GRAY, 
                                     Color.DARK_GRAY);
    return new ChartPanel(chart); 
}
 

Конфигурация приложения

После сборки бандла необходимо определить конфигурацию приложения. Ниже представлен файл «configuration/bundles.ini», включающий список всех бандлов приложения :


bundles=org.apache.felix.eventadmin-1.4.8.jar@start, \
org.apache.felix.log-1.0.1.jar@start, \
util-resources-1.0.0.jar@start, \
util-logger-1.0.0.jar@start, \
base-jframe-1.0.0.jar, \
base-jpanel-1.0.0.jar, \
base-jdialog-1.0.0.jar, \
gui-menu-1.0.0.jar, \
gui-toolbar-1.0.0.jar, \
gui-widgets-1.0.0.jar, \
util-jfreechart-1.0.0.jar, \
osgi-jfreechart-1.0.19.jar, \
jfreechart-bar-pie-1.0.0.jar, \
templ-jframe-1.0.0.jar@main
 

Кроме базового набора бандлов в конфигурацию приложения включены модули создания диаграмм osgi-jfreechart, util-jfreechart и наш бандл jfreechart-bar-pie. На следующем скриншоте представлена круговая диаграмма.

Связанные страницы

Список уроков
Предыдующий, 14-й урок
Следующий, 16-й урок

Скачать урок

Архив проекта jfreechart-bar-pie (1.82 Мб) включает бандл библиотеки osgi-jfreechart во внутреннем репозитории проекта. Используемый в уроке бандл util-jfreechart можно скачать на странице описания util-jfreechart.

Бандлы, используемые в уроке 15, файлы конфигурации и файл описания инсталлируемых бандлов собраны и упакованы в один архивный файл configuration.lesson15.zip (2.33 Мб).

Скачайте и «разверните» архив configuration.lesson15.zip, перенесите файлы в структуру, представленную на странице описания платформы JaBricks.

  Рейтинг@Mail.ru