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. |