Библиотека сайта rus-linux.net
Фреймворк Violet
Глава 22 из книги "Архитектура приложений с открытым исходным кодом", том 1.
Оригинал: "Violet", глава из книги "The Architecture of Open Source Applications"
Автор: Cay Horstmann
Перевод: Н.Ромоданов
22.2. Графический фреймворк
Violet базируется на универсальном фреймворке редактирования графов, который может выдавить изображения и позволяет редактировать узлы и ребра изображений произвольной формы. Редактор Violet для UML использует узлы для отображения классов, объектов, границ активации (в диаграммах последовательностей), и так далее, а ребра — для различных дуг в диаграммах UML. Другой экземпляр графического фреймворка может отображать диаграммы «сущность - отношение» или синтаксические диаграммы.
Рис.22.2: Простой экземпляр фреймворка редактирования
Для того чтобы проиллюстрировать фреймворк, рассмотрим редактор для очень простых графов с черно-белыми круглыми узлами и прямыми ребрами (рис.22.2). В классе SimpleGraph определяются прототипные объекты для типов узлов и ребер, иллюстрирующие шаблон прототипорования prototype:
public class SimpleGraph extends AbstractGraph
{
public Node[] getNodePrototypes()
{
return new Node[]
{
new CircleNode(Color.BLACK),
new CircleNode(Color.WHITE)
};
}
public Edge[] getEdgePrototypes()
{
return new Edge[]
{
new LineEdge()
};
}
}
Прототипные объекты используются для рисования кнопок узлов и ребер в верхней части рисунка 22.2. Они клонируются всякий раз, когда пользователь добавляет в граф новый экземпляр узла или ребра. Узел Node и ребро Edge являются интерфейсами со следующими ключевыми методами:
- В обоих интерфейсах есть метод
getShape, который возвращает объект Java2DShape, представляющий собой узел или ребро. - The интерфейс
Edgeимеет методы, с помощью которых можно получить начальный и конечный узел ребра. - Метод
getConnectionPointв интерфейсе типа Node вычисляет оптимальные точки подсоединения к границе узла (смотрите рис.22.3). - Метод
getConnectionPointsинтерфейсаEdgeпозволяет получать две конечные точки ребра. Этот метод необходим, чтобы рисовать «грабберы», которыми помечается текущее выбранное ребро. - Узел может иметь потомков, которые перемещаются вместе с родителем. Предлагается ряд методов для нумерации и управления потомками.
Рис.22.3: Поиск точки присоединения на границе формы узла Node
Удобные классы AbstractNode и AbstractEdge реализуют ряд таких методов, а классы RectangularNode и SegmentedLineEdge обеспечивают всю полную реализацию прямоугольных узлов со строкой-заголовком и ребрами, которые состоят из отрезков прямой.
В случае нашего простого редактора графов нам нужны подклассы CircleNode и LineEdge, в которых есть метод draw, метод contains и метод getConnectionPoint, в которых описывается форма границы узла. Ниже приведен код, а на рис 22,4 показана диаграмма классов для этих классов (нарисованных, конечно, с помощью Violet).
public class CircleNode extends AbstractNode
{
public CircleNode(Color aColor)
{
size = DEFAULT_SIZE;
x = 0;
y = 0;
color = aColor;
}
public void draw(Graphics2D g2)
{
Ellipse2D circle = new Ellipse2D.Double(x, y, size, size);
Color oldColor = g2.getColor();
g2.setColor(color);
g2.fill(circle);
g2.setColor(oldColor);
g2.draw(circle);
}
public boolean contains(Point2D p)
{
Ellipse2D circle = new Ellipse2D.Double(x, y, size, size);
return circle.contains(p);
}
public Point2D getConnectionPoint(Point2D other)
{
double centerX = x + size / 2;
double centerY = y + size / 2;
double dx = other.getX() - centerX;
double dy = other.getY() - centerY;
double distance = Math.sqrt(dx * dx + dy * dy);
if (distance == 0) return other;
else return new Point2D.Double(
centerX + dx * (size / 2) / distance,
centerY + dy * (size / 2) / distance);
}
private double x, y, size, color;
private static final int DEFAULT_SIZE = 20;
}
public class LineEdge extends AbstractEdge
{
public void draw(Graphics2D g2)
{ g2.draw(getConnectionPoints()); }
public boolean contains(Point2D aPoint)
{
final double MAX_DIST = 2;
return getConnectionPoints().ptSegDist(aPoint) < MAX_DIST;
}
}
Рис.22.4: Диаграмма классов для простого графа
В целом, Violet предоставляет простой фреймворк для создания редакторов графов. Чтобы получить экземпляр редактора, определяются классы узлов и ребер и предоставляются методы в классе графа, с помощью которых можно получить прототипы объектов узел и ребро.
Конечно, есть и другие графовые фреймворки, например, JGraph [Ald02] и JUNG2. Однако эти фреймворки гораздо более сложные и они являются фреймворками для рисования графов, а не для создания приложений, которые рисуют графы.
Продолжение статьи: 22.3. Использование свойств JavaBeans.
