410013796724260
• Webmoney
R335386147728
Z369087728698
Урок 16. Линейные диаграммыВ данном уроке будем заниматься разработкой бандла создания и представления линейных диаграмм (временны́х, кусочно-линейных) в приложениях на платформе JaBricks. Как и в уроке 14 создавать интерфейсный бандл будем не с «нуля». В качестве шаблона также используем проект templ-jdialog, наследующего свойства базового модуля base-jdialog. О преимуществах использования базового модуля для создания интерфейсного бандла читайте на странице его описания. Структура проекта![]()
Подготовка проекта. Повторим все действия урока 14 по подготовке проекта. Для этого скачаем архив проекта
templ-jdialog и «развернем» его. Переименуем директорию проекта в «jfreechart-line». После этого внесем изменения в
наименование проекта (<name>) в файле «jfreechart-line/.project». Далее переименуем artifactId проекта в
«jfreechart-line/pom.xml». На этом все приготовления проекта к «употреблению» на начальном этапе заканчиваются. После
этого импортируем проект в IDE и продолжим структурные преобразования проекта. Структура нашего проекта в 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-line</artifactId> <packaging>bundle</packaging> <version>1.0.0</version> <name>JFreechart example (line)</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 = {{"30", "Временная, линейная" }, {"40", "Кусочно-линейная" }}; //----------------------------------------------------- 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 = splitPane.getDividerLocation(); ChartPanel cp = null; if (name.equals(names[0][0])) cp = (new ModuleDAO()).createTimeSeriesChart(); else if (name.equals(names[1][0])) cp = (new ModuleDAO()).createLineChart(); if (cp != null) { splitPane.setLeftComponent (cp); splitPane.setDividerLocation(location); } } } При открытии формы в методе createGUI создается временна́я линейная диаграмма, изображение которой представлено на следующем скриншоте. ![]() Класс ModuleDAOГлавный интерес в данном примере представляет класс ModuleDAO. Данному классу отводится основная роль в подготовке наборов данных и формировании диаграммы. Рассмотрим эти два вопроса по-отдельности. Массив данныхДля построения двух разнотипных диаграмм будем использовать одни и те же исходные данные, представленные ниже. Исходные данные включают массив из трех текстовых значений TIMESERIES, обозначающих наименования графиков, и двумерный массив DATA_TIMESERIES, определяющий значения курса валют и стоимость нефти в определенные дни. private final String[] TIMESERIES = {"Курс USD", "Курс EUR", "Нефть марки Brent"}; private final String[][] DATA_TIMESERIES = { // Дата USD EUR Нефть {"2017-05-11", "58.0824", "63.2634", "50.78"}, {"2017-05-12", "57.1161", "62.1595", "50.82"}, {"2017-05-13", "57.1640", "62.0915", "51.77"}, {"2017-05-16", "56.5258", "61.8449", "51.30"}, {"2017-05-17", "56.2603", "62.0382", "52.14"}}; Набор данных временно́й диаграммыДля подготовки набора данных временно́й диаграммы используем закрытые (private) методы класса createCollectionTM (int) и createDatasetTM(). Первый метод подготавливает список записей List типа <TimeSeriesDataItem>. Данный метод в качестве параметра получает идентификатор графика, в цикле парсит массив DATA_TIMESERIES, создавая экземпляры объектов TimeSeriesDataItem и упаковывая их в List. Здесь следует обратить внимание на первый параметр класса TimeSeriesDataItem, определяемый как org.jfree.data.time.Day. В качестве первого параметра может быть использован любой тип, наследующий свойства класса org.jfree.data.time.RegularTimePeriod, к которым относятся также FixedMillisecond, Hour, Millisecond, Minute, Month, Quarter, Second, Week, Year. По названиям классов однозначно можно понять временно́й тип первого параметра. Метод createDatasetTM создаёт графики (s_usd, s_eur, s_oil) типа TimeSeries методом createTimeSeries утилиты util-jfreechart. После этого собирает их в один набор XYDataset методом createXYDataset.
private List<TimeSeriesDataItem> createCollectionTM ( final int idx) { List<TimeSeriesDataItem> data; data = new ArrayList<TimeSeriesDataItem>(); TimeSeriesDataItem tsdi; Date date; SimpleDateFormat sdf ; sdf = new SimpleDateFormat("yyyy-MM-dd"); try { for (int i = 0; i < DATA_TIMESERIES.length; i++){ date = sdf.parse (DATA_TIMESERIES[i][0]); Day day = new Day(date); String vl = DATA_TIMESERIES[i][idx]; double val = Double.valueOf(vl); tsdi = new TimeSeriesDataItem(day, val); data.add(tsdi); } } catch (ParseException e) {} return data; } //--------------------------------------------------------- private XYDataset createDatasetTM() { List<TimeSeriesDataItem> data_usd; List<TimeSeriesDataItem> data_eur; List<TimeSeriesDataItem> data_oil; TimeSeries s_usd; TimeSeries s_eur; TimeSeries s_oil; data_usd = createCollectionTM(1); data_eur = createCollectionTM(2); data_oil = createCollectionTM(3); JFreeChartImpl fci = new JFreeChartImpl(); s_usd = fci.createTimeSeries(TIMESERIES[0], data_usd); s_eur = fci.createTimeSeries(TIMESERIES[1], data_eur); s_oil = fci.createTimeSeries(TIMESERIES[2], data_oil); return fci.createXYDataset(s_usd, s_eur, s_oil); } Набор данных кусочно-линейной диаграммыДля подготовки набора данных кусочно-линейной диаграммы также используем два закрытых (private) метода класса createCollectionXY (int) и createDatasetXY(). Первый метод подготавливает список записей List типа <XYDataItem>. Данный метод в качестве параметра получает идентификатор графика и в цикле парсит массив DATA_TIMESERIES, создавая экземпляры объектов XYDataItem и упаковывая их в List. Обратите внимание, что класс XYDataItem принимает два параметра типа double. В качестве первого параметра ему передается значение дня, извлекаемого из описания даты. Метод createDatasetXY создаёт графики (s_usd, s_eur, s_oil) типа XYSeries методом createXYSeries утилиты util-jfreechart. После этого собирает их в один набор XYDataset методом createXYDataset.
private List<XYDataItem> createCollectionXY(final int idx) { List<XYDataItem> data; data = new ArrayList<XYDataItem>(); for (int i = 0; i < DATA_TIMESERIES.length; i++){ String dd = DATA_TIMESERIES[i][0].substring(8); String vl = DATA_TIMESERIES[i][idx]; double day = Double.valueOf(dd); double val = Double.valueOf(vl); XYDataItem rxy = new XYDataItem(day, val); data.add(rxy); } return data; } //--------------------------------------------------------- private XYDataset createDatasetXY() { List<XYDataItem> data_usd; List<XYDataItem> data_eur; List<XYDataItem> data_oil; XYSeries s_usd ; XYSeries s_eur ; XYSeries s_oil ; data_usd = createCollectionXY(1); data_eur = createCollectionXY(2); data_oil = createCollectionXY(3); JFreeChartImpl fci = new JFreeChartImpl(); s_usd = fci.createXYSeries(TIMESERIES[0], data_usd); s_eur = fci.createXYSeries(TIMESERIES[1], data_eur); s_oil = fci.createXYSeries(TIMESERIES[2], data_oil); return fci.createXYDataset(s_usd, s_eur, s_oil); } Создание диаграммДля создания диаграмм используются два открытых (public) метода createTimeSeriesChart() и createLineChart(), названия которых однозначно определяют тип диаграммы. В методах сначала формируются объекты описания диаграмм, после этого вызываются соответствующие методы утилиты util-jfreechart. В методах Вы видите закоментированные строки, демонстрирующие возможности утилиты util-jfreechart выполнять определенные настройки как отдельных графиков, так и диаграммы в целом. Обратите внимание, что исходные данные для диаграмм одни и те же. Следовательно, графики также могут иметь схожий вид при соответствующих настройках диаграмм. Основное отличие касается осей абсцисс : одна диаграмма имеет временно́й характер, у второй – числовой (double). Отображение маркеров (фигур) в узловых точках графиков одной из диаграмм блокирует представление всплывающих подсказок.
String subtitle="Валюта, нефть с 11.05.2017 по 25.05.2017"; public ChartPanel createTimeSeriesChart() { XYDataset dataset = createDatasetTM(); ChartDescTime cdt = new ChartDescTime(); cdt.setTitle ("Временная (линейная) диаграмма"); cdt.setSubtitle(subtitle); cdt.setDataset (dataset); cdt.setLegend (true ); cdt.setTooltips(true ); // cdt.setSeriesShapeVisible(true); cdt.setAxisDateFormat(new SimpleDateFormat("dd.MM")); JFreeChartImpl fci = new JFreeChartImpl(); JFreeChart chart = fci.createTimeSeriesChart(cdt); fci.setSeriesPaint(chart, 2, Color.MAGENTA, 2f); return new ChartPanel(chart); } //--------------------------------------------------------- public ChartPanel createLineChart() { XYDataset dataset = createDatasetXY(); ChartDescXY cdxy = new ChartDescXY(); cdxy.setTitle ("Кусочно-линейная диаграмма"); cdxy.setSubtitle(subtitle); cdxy.setDataset (dataset); cdxy.setLegend (true ); cdxy.setTooltips(true ); cdxy.setRange(new Range(50, 65)); cdxy.setYTickUnit(NumberAxis.createIntegerTickUnits()); cdxy.setXTickUnit(NumberAxis.createIntegerTickUnits()); cdxy.setAxisYVisible(false); cdxy.setAxisXVisible(false); cdxy.setSeriesShapeVisible(true); JFreeChartImpl fci = new JFreeChartImpl(); // fci.setSeriesPaint(chart, 2, Color.MAGENTA, 2f); JFreeChart chart = fci.createLineChart(cdxy); return new ChartPanel(chart); // XYLineAndShapeRenderer renderer; // renderer = new XYLineAndShapeRenderer(); // // Удаление связующих линий Series 1 // renderer.setSeriesLinesVisible (0, false); // // Удаление меток Series 2 // renderer.setSeriesShapesVisible(1, false); } Конфигурация приложенияПосле сборки бандла необходимо определить конфигурацию приложения. Ниже представлен файл «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-line-1.0.0.jar, \ templ-jframe-1.0.0.jar@main Кроме базового набора бандлов в конфигурацию приложения включены модули создания диаграмм osgi-jfreechart, util-jfreechart и наш бандл jfreechart-line. На следующем скриншоте представлена кусочно-линейная диаграмма. ![]() Скачать урокАрхив примера включает описанный выше проект jfreechart-line и файлы конфигурации. Бандл библиотеки osgi-jfreechart (1.9 Мб) включен только во внутренний репозиторий проекта. Чтобы запустить приложение необходимо будет скопировать его в директорию конфигурации «configuration/bundles/». Связанные страницыСписок уроковПредыдующий, 15-й урок Скачать урокАрхив проекта jfreechart-line.zip (1.82 Мб) включает бандл библиотеки osgi-jfreechart во внутреннем репозитории проекта. Используемый в уроке бандл util-jfreechart можно скачать на странице описания util-jfreechart. Бандлы, используемые в уроке 15, файлы конфигурации и файл описания инсталлируемых бандлов собраны и упакованы в один архивный файл configuration.lesson16.zip (2.32 Мб). Скачайте и «разверните» архив configuration.lesson16.zip, перенесите файлы в структуру, представленную на странице описания платформы JaBricks. |