Статьи

JavaFX в дикой природе: сапфир!

JavaFX 1.0 был выпущен всего несколько дней назад, и я рад, что мы наблюдаем больше приложений JavaFX «в дикой природе». Вот одна из них, о которой я недавно узнал, под названием Sapphire, разработанная The Standards Company .

Фото 1

Согласно веб-сайту, на котором вы можете запустить это приложение JavaFX :

«Sapphire — это усовершенствованный инструмент наблюдения в классе. Он предоставляет простой в использовании интерфейс, несколько развертываний на платформе и взаимозаменяемые формы наблюдения, которые можно настраивать под большинство ситуаций. Community Edition [это версия, которую вы можете попробовать. по ссылке выше] является демонстрационной версией, запрошенной Департаментом образования штата Оклахома и настроенной в качестве дополнения к форме наблюдения «Время выполнения задания», выпущенной в октябре 2008 года ».

Некоторые технические заметки JavaFX от Бена Джонса из The Standards Company: составление диаграмм в реальном времени в JavaFX

Одной из особенностей JavaFX, которая делает его привлекательным для разработчиков приложений реального времени, является его способность привязывать графические элементы к моделям с помощью механизма привязки. Этот механизм позволяет отражать текущее состояние модели в интерфейсе без необходимости создания какого-либо типа системы опроса.

В нашем приложении Sapphire мы собираем данные в реальном времени из наблюдений в классе. Наблюдатель записывает события в классе, нажимая различные кнопки. Эти события отображаются на нескольких дисплеях типа приборной панели, которые активно связаны с поддерживаемыми моделями. Один из них отображает во времени события, созданные серией цветных прямоугольников. Размер, расположение и цвет прямоугольников представляют различные отношения в данных события. Каждый раз, когда происходит нажатие на событие, данные изменяются, и связанный экран автоматически обновляется.

Для этого вам нужно всего три вещи: модель данных, элемент отображения и драйвер событий какого-либо типа. Давайте посмотрим на один из визуальных строительных блоков, класс TimeOnTaskBlock :

public class TimeOnTaskBlock extends CustomNode {

public var aboveColor:Color = Color.GREEN;
public var belowColor:Color = Color.RED;

public var seconds:Integer;
public var startingMark:Integer;
public var zoneWidth:Integer = 600;
public var zoneSeconds:Integer = 3600;
public var height:Integer = 100;
public var maxSegments:Number = 5;
public var segment:Number = 0;
public var x:Integer;
public var scale:Number = 0.95;

public override function create(): Node {
return Group {

var maxDisplayHeight:Number = height/2;

content: [
Rectangle {
x: bind zoneWidth * startingMark / zoneSeconds;
y: bind height/2 - scale * ((maxDisplayHeight) * segment/maxSegments)
width: bind zoneWidth * seconds / zoneSeconds;
height: bind scale * (maxDisplayHeight * segment/maxSegments)
fill: bind aboveColor
strokeWidth:0
},
Rectangle {
x: bind zoneWidth * startingMark / zoneSeconds;
y: bind height / 2
width: bind zoneWidth * seconds / zoneSeconds;
height: bind scale * (maxDisplayHeight - (maxDisplayHeight * segment/maxSegments))
fill: bind belowColor
strokeWidth:0
}
]
effect: Lighting {
light: DistantLight { azimuth: 225 elevation: 60 }
surfaceScale: 2
}
};
}
}

Этот пользовательский узел представляет то, что будет отображаться. Это пара масштабированных прямоугольников, сложенных друг на друга. Различные атрибуты определяют форму, размер и размещение. Обратите внимание на использование эффекта DistantLight для придания прямоугольникам на графике некоторой глубины. Следующий строительный блок от этого — другой пользовательский узел, который обрабатывает визуальную оркестровку узлов временных блоков. Узел DisplayTimeChart фактически является отображаемым элементом панели мониторинга. Он содержит элемент данных, содержащий последовательность узлов TimeOnTaskBlock . Давайте взглянем на этот узел:

public class TimeOnTaskBlock extends CustomNode {

public var aboveColor:Color = Color.GREEN;
public var belowColor:Color = Color.RED;

public var seconds:Integer;
public var startingMark:Integer;
public var zoneWidth:Integer = 600;
public var zoneSeconds:Integer = 3600;
public var height:Integer = 100;
public var maxSegments:Number = 5;
public var segment:Number = 0;
public var x:Integer;
public var scale:Number = 0.95;

public override function create(): Node {
return Group {

var maxDisplayHeight:Number = height/2;

content: [
Rectangle {
x: bind zoneWidth * startingMark / zoneSeconds;
y: bind height/2 - scale * ((maxDisplayHeight) * segment/maxSegments)
width: bind zoneWidth * seconds / zoneSeconds;
height: bind scale * (maxDisplayHeight * segment/maxSegments)
fill: bind aboveColor
strokeWidth:0
},
Rectangle {
x: bind zoneWidth * startingMark / zoneSeconds;
y: bind height / 2
width: bind zoneWidth * seconds / zoneSeconds;
height: bind scale * (maxDisplayHeight - (maxDisplayHeight * segment/maxSegments))
fill: bind belowColor
strokeWidth:0
}
]
effect: Lighting {
light: DistantLight { azimuth: 225 elevation: 60 }
surfaceScale: 2
}
};
}
}

 

TimeDisplayChart служит несколько целей. Сначала он строит общий элемент панели инструментов. Это определяет обычное пространство отображения, необходимую маркировку и размещение элементов. Обратите внимание на два аспекта этого класса: группа, в которой его содержимое связано с последовательностью displayBlocks , и вторая группа, состоящая из одиночного TimeOnTaskBlock . Привязывая содержимое группы к источнику данных, любые изменения в источнике данных будут автоматически доступны группе. Это эффективно производит самообновляющееся отображение, так как мы связываем отображаемый узел. Вторая группа, которая является единственным экземпляром TimeOnTaskBlockслужит другой цели. Он охватывает промежуток времени с момента последнего изменения данных и текущее время. Поскольку модель данных хранит только прошлые события, нам нужны средства для отображения данных, которые еще предстоит сохранить. В конце концов, это в реальном времени.

Чтобы поместить все это в приложение, экземпляр TimeDisplayChart помещается в группу следующим образом:

Group {
translateY:310
translateX:10
content:[
TimeDisplayChart{
width:600
height:100
zoneSeconds:3600
zoneWidth:600
background:Color.#969696
timer: bind timer
displayTicker: bind displayTicker
currentSegment: bind appState.currentSegment
timeMark: bind appState.currentTimeMark
onColor: bind appState.onColor
offColor:bind appState.offColor
displayBlocks: bind displayblocks
}
]
}

Здесь мы можем видеть различные атрибуты пользовательского узла, связанные с различными источниками данных и условиями, которые выходят в более широком контексте приложения. Привязки создают активный канал связи между данными состояния приложения и графическими элементами. Это удобно, быстро реагирует и легко управляется в процессе разработки.

JavaFX на предприятии

Технические примечания, представленные Беном Джонсом выше, демонстрируют, что графическое представление данных в реальном времени очень достижимо в JavaFX. Это одна из возможностей, которые требуются во многих корпоративных приложениях, поэтому я хотел бы увидеть инициативу с открытым исходным кодом, которая предоставляет библиотеку графов JavaFX (которые, конечно, имеют современный RIA-интерфейс).

В любом случае, поиграйте с Sapphire и, пожалуйста, оставьте The Standards Company свой отзыв об этом очень специализированном приложении JavaFX. Кроме того, если у вас есть какие-либо приложения JavaFX в дикой природе, пожалуйста, дайте мне знать на jim.weaver [at] javafxpert.com. В настоящее время я особенно заинтересован в демонстрации приложений JavaFX, которые взаимодействуют с сервером, таких как корпоративные приложения и гибридные приложения.

С уважением,
Джим Уивер
JavaFXpert.com