Статьи

Помимо расширенного текста: хитрости с использованием SourceViewer, Annotations и AnnotationPainter

SWT StyledText может отображать текстовые атрибуты, такие как жирный шрифт, курсив и зачеркнутый текст, изменять цвета и шрифты. Что мы должны делать, когда нам нужно выйти за рамки форматированного текста? В этой статье мы представляем три простых трюка, использующих стандартные API-интерфейсы SWT и JFace для создания законченной презентации, в которой только текстовые атрибуты не справятся с работой.

Маркировка Пятно


Чтобы отобразить что-то интересное, нам нужно отметить место.
Обычно это делается с помощью TextPresentation, которая определяет смещения символов и диапазоны стилей. К счастью, API-интерфейсы Eclipse предоставляют нам еще один механизм для разметки областей текста расширяемым образом: аннотации.


Ключевые API в нашем распоряжении:

org.eclipse.jface.text.source.Annotation

org.eclipse.jface.text.source.AnnotationModel


Используя эти API, мы можем создавать аннотации и указывать их местоположение.
Простое место для этого — разделитель документов. Он будет вызван в подходящее время для разделения вашего документа. С помощью
RuleBasedPartitionScannerвы можете изменить свои правила для создания соответствующих аннотаций.


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


IAnnotationAccess annotationAccess = new IAnnotationAccess() {
public Object getType(Annotation annotation) {
return annotation.getType();
}
public boolean isMultiLine(Annotation annotation) {
return true;
}
public boolean isTemporary(Annotation annotation) {
return true;
}
};

AnnotationPainter painter = new AnnotationPainter(sourceViewer, annotationAccess);


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

Перекраска персонажей


Не все шрифты могут отображать все символы.
Это проблематично в приложении, которое интернационализировано или где пользователь может изменить шрифт.

Взять например пули.
Unicode \ u2022 может использоваться для отображения сплошной круглой маркировки с большинством шрифтов, но как насчет пустой или квадратной? Эти символы не могут быть надежно найдены в часто используемых шрифтах. Хитрость, которую мы используем, заключается в том, чтобы всегда использовать символ \ u2022, но перекрасить его там, где мы хотим отобразить что-то более интересное. Делая это, мы получаем правильное отображение, и текст прекрасно работает с операциями копирования / вставки.

Чтобы это работало, мы создаем аннотации, в которых наши символы маркера находятся в документе.
Затем мы подключаем стратегию рисования пули к нашему художнику следующим образом:

painter.addDrawingStrategy(BulletAnnotation.TYPE, new BulletDrawingStrategy());
painter.addAnnotationType(BulletAnnotation.TYPE, BulletAnnotation.TYPE);
painter.setAnnotationTypeColor(BulletAnnotation.TYPE, getTextWidget().getForeground());

Художник не будет вызывать нашу стратегию рисования, если только не добавлены тип и цвет шрифта.

Как выглядит наша аннотация пули?
Он должен иметь достаточно информации для стратегии рисования, чтобы знать, что рисовать. В этом случае форма пули зависит от «уровня» отступа. Вот что я использовал:


public class BulletAnnotation extends Annotation {

public static final String TYPE = "org.eclipse.mylyn.internal.wikitext.ui.viewer.annotation.bullet";

private final int indentLevel;

public BulletAnnotation(int indentLevel) {
super(TYPE, false, Integer.toString(indentLevel));
this.indentLevel = indentLevel;
}

public int getIndentLevel() {
return indentLevel;
}

}

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

Мы удаляем предыдущий символ, рисуя прямоугольник размером с символ в цвете фона:

// erase whatever character was there
gc.fillRectangle(left.x, left.y, right.x - left.x, lineHeight);

Затем мы рисуем новую форму:

// now paint the bullet
switch (bullet.getIndentLevel()) {
case 1: // round solid bullet
gc.setBackground(color);
gc.fillOval(hcenter - 3, vcenter - 2, 5, 5);
break;
case 2: // round empty bullet
gc.setForeground(color);
gc.drawOval(hcenter - 3, vcenter - 3, 5, 5);
break;
default: // square bullet
gc.setBackground(color);
gc.fillRectangle(hcenter - 3, vcenter - 2, 5, 5);
break;
}

Вот снимок экрана, показывающий пример использования этой техники:

Рисование не-символов


Иногда необходимо отображать не символы.
Например, браузеры отображают горизонтальную линию для <hr /> (горизонтальное правило). Помечая место аннотациями и регистрируя художника, мы можем сделать то же самое. Вот результат, который мы ищем.


Чтобы создать этот эффект, мы помещаем пустую строку в отображаемый текст и аннотируем его с помощью HorizontalRuleAnnotation. Рисовать аннотацию легко:



public void draw(Annotation annotation, GC gc, StyledText textWidget, int offset, int length, Color color) {
if (gc != null) {
final Color foreground = gc.getForeground();

Point left = textWidget.getLocationAtOffset(offset);
Point right = textWidget.getLocationAtOffset(offset + length);
if (left.x > right.x) {
// hack: sometimes linewrapping text widget gives us the wrong x/y for the first character of a line that
// has been wrapped.
left.x = 0;
left.y = right.y;
}
right.x = textWidget.getClientArea().width;

int baseline = textWidget.getBaseline(offset);

int vcenter = left.y + (baseline / 2) + (baseline / 4);

gc.setLineWidth(0); // NOTE: 0 means width is 1 but with optimized performance
gc.setLineStyle(SWT.LINE_SOLID);

left.x += 3;
right.x -= 5;
vcenter -= 2;

if (right.x > left.x) {
// draw the shadow
gc.setForeground(shadowForeground);
gc.drawRectangle(left.x, vcenter, right.x - left.x, 2);

// draw the horizontal rule
gc.setForeground(color);
gc.drawLine(left.x, vcenter, right.x, vcenter);
gc.drawLine(left.x, vcenter, left.x, vcenter + 2);
}

gc.setForeground(foreground);
} else {
textWidget.redrawRange(offset, length, true);
}
}


Как и прежде, мы привязываем стратегию рисования к художнику:


painter.addDrawingStrategy(HorizontalRuleAnnotation.TYPE, new HorizontalRuleDrawingStrategy());
painter.addAnnotationType(HorizontalRuleAnnotation.TYPE, HorizontalRuleAnnotation.TYPE);
painter.setAnnotationTypeColor(HorizontalRuleAnnotation.TYPE, getTextWidget().getForeground());

Вывод


Eclipse предоставляет несколько мощных API для подключения к рисованию StyledText. Используя несколько простых приемов, мы можем создавать мощные полированные визуальные эффекты в пользовательском интерфейсе SWT. Все эти методы применяются в проекте
Mylyn WikiText , где вы можете найти работающий исходный код.