当前位置: 首页 > 工具软件 > RichText > 使用案例 >

小程序richtext_用于基于SWT的应用程序的RichText编辑器组件

赫连俊悟
2023-12-01

小程序richtext

本文将完成使用SWT实现我们自己的RichText编辑器组件的任务。 在为我的一位客户开发基于桌面的应用程序时,我遇到了这样的可视化组件的需求,并希望添加一项功能,以允许用户使用粗体,斜体,删除线等功能来写富文本注释。 那时,我开始研究网络,以找到一个开放源代码库,该库可以使我免于从头开始部署它的工作,而我遇到了“已完成”实现的列表
让我们在这里列出我对这种组件的需求:
  • 它应该是本地SWT组件,而不是Eclipse View或Editor,并且必须可嵌入任何SWT组合中。
  • 它应允许使用粗体,斜体,删除线等基本格式。
  • 它应该支持剪贴板的基本操作,例如复制,剪切和粘贴。
  • 它应该使用基本HTML输出文本。
  • 它需要能够解析所生成的基本HTML,以允许版本。
因此,我发现的大多数解决方案都不符合我的需求,因为它们要么是Eclipse Views / Editor,要么太笨拙,无法集成,要么试图实现太多功能,要么与我用来为自己的公司打上烙印的图标集不符应用程序(尽管这是一个小问题,但总结起来,这为我做出决定提供了更多原因)。 因此,最后我终于决定根据StyledText SWT标准组件从头开始编写它,并以该示例为起点。
RichText控件
几乎所有的工作都将由RichText控件本身执行。 我将添加一些支持类,这些支持类将用作将结果文本格式化为基本HTML的助手,以及图像,本地化字符串等的提供者。
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CaretListener;
import org.eclipse.swt.custom.ExtendedModifyEvent;
import org.eclipse.swt.custom.ExtendedModifyListener;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Caret;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.xml.sax.SAXException;

public class RichText extends Composite {

 private List cachedStyles =
   Collections.synchronizedList(new LinkedList());

 private ToolBar toolBar;
 private StyledText styledText;

 private ToolItem boldBtn;
 private ToolItem italicBtn;
 private ToolItem strikeThroughBtn;
 private ToolItem underlineBtn;

 private ToolItem pasteBtn;
 private ToolItem eraserBtn;

 public RichText(Composite parent, int style) {
  super(parent, style);
  initComponents();
 }

 public void addCaretListener(CaretListener listener) {
  styledText.addCaretListener(listener);
 }

 public void removeCaretListener(CaretListener listener) {
  styledText.removeCaretListener(listener);
 }

 public void addExtendedModifyListener(ExtendedModifyListener listener) {
  styledText.addExtendedModifyListener(listener);
 }

 public void removeExtendedModifyListener(ExtendedModifyListener listener) {
  styledText.removeExtendedModifyListener(listener);
 }

 public void addModifyListener(ModifyListener listener) {
  styledText.addModifyListener(listener);
 }

 public void removeModifyListener(ModifyListener listener) {
  styledText.removeModifyListener(listener);
 }

 public void addVerifyKeyListener(VerifyKeyListener listener) {
  styledText.addVerifyKeyListener(listener);
 }

 public void removeVerifyKeyListener(VerifyKeyListener listener) {
  styledText.removeVerifyKeyListener(listener);
 }

 public void addVerifyListener(VerifyListener listener) {
  styledText.addVerifyListener(listener);
 }

 public void removeVerifyListener(VerifyListener listener) {
  styledText.removeVerifyListener(listener);
 }

 public int getCharCount() {
  return styledText.getCharCount();
 }

 public Caret getCaret() {
  return styledText.getCaret();
 }

 public int getCaretOffset() {
  return styledText.getCaretOffset();
 }

 /**
  * Obtain an HTML formatted text from the component contents
  *
  * @return an HTML formatted text
  */
 public String getFormattedText() {
  String plainText = styledText.getText();

  RichStringBuilder builder = new RichStringBuilder();
  Integer[] lineBreaks = getLineBreaks();

  int brIdx = 0;
  int start = 0;
  int end = (lineBreaks.length > brIdx ? lineBreaks[brIdx++] : plainText.length() - 1);

  while (start < end) {
    builder.startParagraph();
    StyleRange[] ranges = styledText.getStyleRanges(start, (end - start));
    if (ranges != null && ranges.length > 0) {
    for (int i = 0;i < ranges.length;i++) {
     if (start < ranges[i].start) {
      builder.append(plainText.substring(start, ranges[i].start));
     }

     List styles = translateStyle(ranges[i]);
     builder.startFontStyles(styles.toArray(new FontStyle[styles.size()]));
     builder.append(plainText.substring(ranges[i].start,
       ranges[i].start + ranges[i].length));
     builder.endFontStyles(styles.size());

     start = (ranges[i].start + ranges[i].length) + 1;
    }
   }
   if (start < end) {
     builder.append(plainText.substring(start, end));
    }
    start = end + styledText.getLineDelimiter().length();
    end = (lineBreaks.length > brIdx ? lineBreaks[brIdx++] : plainText.length() - 1);
   builder.endParagraph();
  }

  return builder.toString();
 }

 public void setFormattedText(String text)
 throws ParserConfigurationException, SAXException, IOException {
  RichTextParser parser = RichTextParser.parse(text);
  styledText.setText(parser.getText());
  styledText.setStyleRanges(parser.getStyleRanges());
 }

 public int getLineAtOffset(int offset) {
  return styledText.getLineAtOffset(offset);
 }

 public int getLineCount() {
  return styledText.getLineCount();
 }

 public int getLineSpacing() {
  return styledText.getLineSpacing();
 }

 public String getText() {
  return styledText.getText();
 }

 protected void applyFontStyleToSelection(FontStyle style) {
  Point sel = styledText.getSelectionRange();
  if ((sel == null) || (sel.y == 0)) {
   return ;
  }

  StyleRange newStyle;
  for (int i = sel.x; i < (sel.x + sel.y); i++) {
   StyleRange range = styledText.getStyleRangeAtOffset(i);
   if (range != null) {
    newStyle = (StyleRange) range.clone();
    newStyle.start = i;
    newStyle.length = 1;
   } else {
    newStyle = new StyleRange(i, 1, null, null, SWT.NORMAL);
   }

   switch (style) {
   case BOLD:
    newStyle.fontStyle ^= SWT.BOLD;
    break;
   case ITALIC:
    newStyle.fontStyle ^= SWT.ITALIC;
    break;
   case STRIKE_THROUGH:
    newStyle.strikeout = !newStyle.strikeout;
    break;
   case UNDERLINE:
    newStyle.underline = !newStyle.underline;
    break;
   }

   styledText.setStyleRange(newStyle);
  }

  styledText.setSelectionRange(sel.x + sel.y, 0);
 }

 /**
  * Clear all styled data
  */
 protected void clearStylesFromSelection() {
  Point sel = styledText.getSelectionRange();
  if ((sel != null) && (sel.y != 0)) {
   StyleRange style = new StyleRange(
     sel.x, sel.y, null, null, SWT.NORMAL);
   styledText.setStyleRange(style);
  }
  styledText.setSelectionRange(sel.x + sel.y, 0);
 }

 private Integer[] getLineBreaks() {
  List list = new ArrayList();
  int lastIdx = 0;
  while (lastIdx < styledText.getCharCount()) {
    int br = styledText.getText().indexOf(
      styledText.getLineDelimiter(), lastIdx);
    if (br >= lastIdx && !list.contains(br)) {
    list.add(br);
   }
   lastIdx += styledText.getLineDelimiter().length() + 1;
  }
  Collections.sort(list);
  return list.toArray(new Integer[list.size()]);
 }

 protected void handleCutCopy() {
  // Save the cut/copied style info so that during paste we will maintain
  // the style information. Cut/copied text is put in the clipboard in
  // RTF format, but is not pasted in RTF format. The other way to
  // handle the pasting of styles would be to access the Clipboard
  // directly and
  // parse the RTF text.
  cachedStyles = Collections
    .synchronizedList(new LinkedList());
  Point sel = styledText.getSelectionRange();
  int startX = sel.x;
  for (int i = sel.x; i <= sel.x + sel.y - 1; i++) {
    StyleRange style = styledText.getStyleRangeAtOffset(i);
   if (style != null) {
    style.start = style.start - startX;
    if (!cachedStyles.isEmpty()) {
     StyleRange lastStyle = cachedStyles
       .get(cachedStyles.size() - 1);
     if (lastStyle.similarTo(style)
       && lastStyle.start + lastStyle.length == style.start) {
      lastStyle.length++;
     } else {
      cachedStyles.add(style);
     }
    } else {
     cachedStyles.add(style);
    }
   }
  }
  pasteBtn.setEnabled(true);
 }

 private void handleExtendedModified(ExtendedModifyEvent event) {
  if (event.length == 0) return;

  StyleRange style;
  if (event.length == 1
    || styledText.getTextRange(event.start, event.length).equals(
      styledText.getLineDelimiter())) {
   // Have the new text take on the style of the text to its right
   // (during
   // typing) if no style information is active.
   int caretOffset = styledText.getCaretOffset();
   style = null;
   if (caretOffset < styledText.getCharCount())
    style = styledText.getStyleRangeAtOffset(caretOffset);
   if (style != null) {
    style = (StyleRange) style.clone();
    style.start = event.start;
    style.length = event.length;
   } else {
    style = new StyleRange(event.start, event.length, null, null,
      SWT.NORMAL);
   }
   if (boldBtn.getSelection())
    style.fontStyle |= SWT.BOLD;
   if (italicBtn.getSelection())
    style.fontStyle |= SWT.ITALIC;
   style.underline = underlineBtn.getSelection();
   style.strikeout = strikeThroughBtn.getSelection();
   if (!style.isUnstyled())
    styledText.setStyleRange(style);
  } else {
   // paste occurring, have text take on the styles it had when it was
   // cut/copied
   for (int i = 0; i < cachedStyles.size(); i++) {
     style = cachedStyles.get(i);
     StyleRange newStyle = (StyleRange) style.clone();
     newStyle.start = style.start + event.start;
     styledText.setStyleRange(newStyle);
    }
   }
  }

  private void handleTextSelected(SelectionEvent event) {
   Point sel = styledText.getSelectionRange();
   if ((sel != null) && (sel.y != 0)) {
    StyleRange[] styles = styledText.getStyleRanges(sel.x, sel.y);
    eraserBtn.setEnabled((styles != null) && (styles.length > 0));
  } else {
   eraserBtn.setEnabled(false);
  }
 }

 private void handleKeyReleased(KeyEvent event) {
  if ((event.keyCode == SWT.ARROW_LEFT) || (event.keyCode == SWT.ARROW_UP)
    || (event.keyCode == SWT.ARROW_RIGHT) || (event.keyCode == SWT.ARROW_DOWN)) {
   updateStyleButtons();
  }
 }

 private void updateStyleButtons() {
  int caretOffset = styledText.getCaretOffset();
  StyleRange style = null;
  if (caretOffset >= 0 && caretOffset < styledText.getCharCount()) {
   style = styledText.getStyleRangeAtOffset(caretOffset);
  }

  if (style != null) {
   boldBtn.setSelection((style.fontStyle & SWT.BOLD) != 0);
   italicBtn.setSelection((style.fontStyle & SWT.ITALIC) != 0);
   underlineBtn.setSelection(style.underline);
   strikeThroughBtn.setSelection(style.strikeout);
  } else {
   boldBtn.setSelection(false);
   italicBtn.setSelection(false);
   underlineBtn.setSelection(false);
   strikeThroughBtn.setSelection(false);
  }
 }

 private void initComponents() {
  GridLayout layout = new GridLayout();
  layout.numColumns = 1;
  setLayout(layout);

  toolBar = createToolBar(this);
  toolBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

  styledText = new StyledText(this, SWT.BORDER | SWT.MULTI |
    SWT.V_SCROLL | SWT.H_SCROLL);
  styledText.setLayoutData(new GridData(GridData.FILL_BOTH));
  styledText.addKeyListener(new KeyAdapter() {
   @Override
   public void keyReleased(KeyEvent e) {
    handleKeyReleased(e);
   }
  });
  styledText.addExtendedModifyListener(new ExtendedModifyListener() {
   @Override
   public void modifyText(ExtendedModifyEvent event) {
    handleExtendedModified(event);
   }
  });
  styledText.addMouseListener(new MouseAdapter() {
   @Override
   public void mouseUp(MouseEvent e) {
    updateStyleButtons();
   }
  });
  styledText.addSelectionListener(new SelectionAdapter() {
   @Override
   public void widgetSelected(SelectionEvent event) {
    handleTextSelected(event);
   }
  });
 }

 private ToolBar createToolBar(Composite parent) {
  ToolBar toolBar = new ToolBar(parent, SWT.FLAT);

  boldBtn = new ToolItem(toolBar, SWT.CHECK);
  boldBtn.setImage(RichTextImages.IMG_BOLD);
  boldBtn.setToolTipText(RichTextStrings.boldBtn_tooltipText);
  boldBtn.addSelectionListener(
    new FontStyleButtonListener(FontStyle.BOLD));

  italicBtn = new ToolItem(toolBar, SWT.CHECK);
  italicBtn.setImage(RichTextImages.IMG_ITALIC);
  italicBtn.setToolTipText(RichTextStrings.italicBtn_tooltipText);
  italicBtn.addSelectionListener(
    new FontStyleButtonListener(FontStyle.ITALIC));

  underlineBtn = new ToolItem(toolBar, SWT.CHECK);
  underlineBtn.setImage(RichTextImages.IMG_UNDERLINE);
  underlineBtn.setToolTipText(RichTextStrings.underlineBtn_tooltipText);
  underlineBtn.addSelectionListener(
    new FontStyleButtonListener(FontStyle.UNDERLINE));

  strikeThroughBtn = new ToolItem(toolBar, SWT.CHECK);
  strikeThroughBtn.setImage(RichTextImages.IMG_STRIKE_THROUGH);
  strikeThroughBtn.setToolTipText(RichTextStrings.strikeThroughBtn_tooltipText);
  strikeThroughBtn.addSelectionListener(
    new FontStyleButtonListener(FontStyle.STRIKE_THROUGH));

  new ToolItem(toolBar, SWT.SEPARATOR);

  ToolItem cutBtn = new ToolItem(toolBar, SWT.PUSH);
  cutBtn.setImage(RichTextImages.IMG_CUT);
  cutBtn.setToolTipText(RichTextStrings.cutBtn_tooltipText);
  cutBtn.addSelectionListener(new SelectionAdapter() {
   @Override
   public void widgetSelected(SelectionEvent e) {
    handleCutCopy();
    styledText.cut();
   }
  });

  ToolItem copyBtn = new ToolItem(toolBar, SWT.PUSH);
  copyBtn.setImage(RichTextImages.IMG_COPY);
  copyBtn.setToolTipText(RichTextStrings.copyBtn_tooltipText);
  copyBtn.addSelectionListener(new SelectionAdapter() {
   @Override
   public void widgetSelected(SelectionEvent e) {
    handleCutCopy();
    styledText.copy();
   }
  });

  pasteBtn = new ToolItem(toolBar, SWT.PUSH);
  pasteBtn.setEnabled(false);
  pasteBtn.setImage(RichTextImages.IMG_PASTE);
  pasteBtn.setToolTipText(RichTextStrings.pasteBtn_tooltipText);
  pasteBtn.addSelectionListener(new SelectionAdapter() {
   @Override
   public void widgetSelected(SelectionEvent e) {
    styledText.paste();
   }
  });

  new ToolItem(toolBar, SWT.SEPARATOR);

  eraserBtn = new ToolItem(toolBar, SWT.PUSH);
  eraserBtn.setEnabled(false);
  eraserBtn.setImage(RichTextImages.IMG_ERASER);
  eraserBtn.setToolTipText(RichTextStrings.eraserBtn_tooltipText);
  eraserBtn.addSelectionListener(new SelectionAdapter() {
   @Override
   public void widgetSelected(SelectionEvent e) {
    clearStylesFromSelection();
   }
  });

  return toolBar;
 }

 private List translateStyle(StyleRange range) {
  List list = new ArrayList();

  if ((range.fontStyle & SWT.BOLD) != 0) {
   list.add(FontStyle.BOLD);
  }
  if ((range.fontStyle & SWT.ITALIC) != 0) {
   list.add(FontStyle.ITALIC);
  }
  if (range.strikeout) {
   list.add(FontStyle.STRIKE_THROUGH);
  }
  if (range.underline) {
   list.add(FontStyle.UNDERLINE);
  }

  return list;
 }

 private class FontStyleButtonListener extends SelectionAdapter {
  private FontStyle style;

  public FontStyleButtonListener(FontStyle style) {
   this.style = style;
  }

  @Override
  public void widgetSelected(SelectionEvent e) {
   applyFontStyleToSelection(style);
  }
 }

}
如您所见,我们的RichText控件基本上是ToolBar和StyledText组件的包装,具有不同事件侦听器的这两个控件都将这两个控件挂钩。  
支持班
在本节中,我将显示用于实现富文本编辑器控件使用的一些支持类的代码。 我将在这里省略为控件提供图像和本地化字符串的类,因为那里有太多关于如何在SWT中进行操作的示例,我将重点介绍格式化和解析控件的输出/输入所需的类。
首先是一个Java枚举,将用于标识支持的不同字体样式:
public enum FontStyle {
 BOLD, ITALIC, STRIKE_THROUGH, UNDERLINE
}

下一个称为RichStringBuilder,它将用作帮助程序类,以将StyledText组件的内容格式化为基本HTML:

import java.util.Stack;

public final class RichStringBuilder {

 public static final String LINE_DELIMITER = "<br/>";

 private StringBuilder builder;
 private Stack fontStyleStack;

 public RichStringBuilder() {
  builder = new StringBuilder();
  fontStyleStack = new Stack();
 }

 public RichStringBuilder append(String text) {
  builder.append(text);
  return this;
 }

 public RichStringBuilder appendLineBreak() {
  builder.append(LINE_DELIMITER);
  return this;
 }

 public RichStringBuilder startParagraph() {
  builder.append("<p>");
  return this;
 }

 public RichStringBuilder startFontStyle(FontStyle fontStyle) {
  fontStyleStack.push(fontStyle);
  internalStartFontStyle(fontStyle);
  return this;
 }

 public RichStringBuilder startFontStyles(FontStyle... fontStyles) {
  for (FontStyle fs : fontStyles) {
   startFontStyle(fs);
  }
  return this;
 }

 public RichStringBuilder endFontStyles(int count) {
  for (int i = 0;i < count;i++) {
     endStyle();
    }
    return this;
   }

   public RichStringBuilder endStyle() {
    if (fontStyleStack.size() > 0) {
   FontStyle style = fontStyleStack.pop();
   internalEndFontStyle(style);
  }
  return this;
 }

 public RichStringBuilder endParagraph() {
  flushStyles();
  builder.append("</p>");
  return this;
 }

 public void flushStyles() {
  while (fontStyleStack.size() > 0) {
   endStyle();
  }
 }

 @Override
 public boolean equals(Object o) {
  if (this == o) return true;
  if (null == o) return false;
  if (!(o instanceof RichStringBuilder)) return false;

  return ((RichStringBuilder) o).builder.equals(builder);
 }

 @Override
 public int hashCode() {
  return builder.hashCode();
 }

 @Override
 public String toString() {
  return builder.toString();
 }

 private void internalStartFontStyle(FontStyle fontStyle) {
  switch (fontStyle) {
  case BOLD:
   builder.append("<b>");
                        break;
                case ITALIC:
                        builder.append("<i>");
                        break;
                case STRIKE_THROUGH:
                        builder.append("<del>");
                        break;
                case UNDERLINE:
                        builder.append("<ins>");
                        break;
                }
        }

        private void internalEndFontStyle(FontStyle fontStyle) {
                switch (fontStyle) {
                case BOLD:
                        builder.append("</b>");
   break;
  case ITALIC:
   builder.append("</i>");
   break;
  case STRIKE_THROUGH:
   builder.append("</del>");
   break;
  case UNDERLINE:
   builder.append("</ins>");
   break;
  }
 }

}

第三个是基于SAX的内容处理程序,它将基本HTML解析为StyledText控件时将启动事件:

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public final class RichTextParser {

 public static RichTextParser parse(String formattedText)
 throws ParserConfigurationException, SAXException, IOException {
  return new RichTextParser(formattedText);
 }

 private StringBuilder text = new StringBuilder();

 private List styleRanges = new ArrayList();

 private RichTextParser(String formattedText)
 throws ParserConfigurationException, SAXException, IOException {
  StringReader reader = new StringReader(formattedText);
  SAXParserFactory factory = SAXParserFactory.newInstance();
  SAXParser parser = factory.newSAXParser();
  DefaultHandler handler = new RichTextContentHandler();
  parser.parse(new InputSource(reader), handler);
 }

 public String getText() {
  return text.toString();
 }

 public StyleRange[] getStyleRanges() {
  return styleRanges.toArray(new StyleRange[styleRanges.size()]);
 }

 private class RichTextContentHandler extends DefaultHandler {

  private Stack<List> stylesStack = new Stack<List>();
  private String lastTextChunk = null;

  @Override
  public void characters(char[] ch, int start, int length)
    throws SAXException {
   lastTextChunk = new String(ch, start, length);
  }

  @Override
  public void endElement(String uri, String localName, String qName)
  throws SAXException {
   // If there is not any previous text chunk parsed then return
   if (lastTextChunk == null) return;
   // If the tag found is not a supported one then return
   if (!"p".equals(qName) || !"b".equals(qName) || !"i".equals(qName) ||
     !"ins".equals(qName) || !"del".equals(qName)) {
    return;
   }

   List lastStyles = lastFontStyles(true);
   if (lastStyles != null) {
    StyleRange range = transform(lastStyles);
    range.start = currentIndex() + 1;
    range.length = lastTextChunk.length();
    styleRanges.add(range);
   }

   text.append(lastTextChunk);
   lastTextChunk = null;
  }

  @Override
  public void startElement(String uri, String localName, String qName,
    Attributes atts) throws SAXException {
   // If the tag found is not a supported one then return
   if (!"p".equals(qName) || !"b".equals(qName) || !"i".equals(qName) ||
     !"ins".equals(qName) || !"del".equals(qName)) {
    return;
   }

   List lastStyles = lastFontStyles(false);
   if (lastTextChunk == null) {
    if (lastStyles == null) {
     lastStyles = new ArrayList();
     stylesStack.add(lastStyles);
    }
   } else {
    if (lastStyles != null) {
     StyleRange range = transform(lastStyles);
     range.start = currentIndex() + 1;
     range.length = lastTextChunk.length();
     styleRanges.add(range);
    }

    text.append(lastTextChunk);
    lastTextChunk = null;
   }

   if ("b".equals(qName)) {
    lastStyles.add(FontStyle.BOLD);
   } else if ("i".equals(qName)) {
    lastStyles.add(FontStyle.ITALIC);
   } else if ("ins".equals(qName)) {
    lastStyles.add(FontStyle.UNDERLINE);
   } else {
    lastStyles.add(FontStyle.STRIKE_THROUGH);
   }
  }

  private StyleRange transform(List styles) {
   StyleRange range = new StyleRange();
   range.start = currentIndex() + 1;
   range.length = lastTextChunk.length();
   for (FontStyle fs : styles) {
    if (FontStyle.BOLD == fs) {
     range.fontStyle = (range.fontStyle & SWT.BOLD);
    } else if (FontStyle.ITALIC == fs) {
     range.fontStyle = (range.fontStyle & SWT.ITALIC);
    } else if (FontStyle.STRIKE_THROUGH == fs) {
     range.strikeout = true;
    } else if (FontStyle.UNDERLINE == fs) {
     range.underline = true;
    }
   }
   return range;
  }

  private List lastFontStyles(boolean remove) {
   List lastStyles = null;
   if (stylesStack.size() > 0) {
    if (remove) {
     lastStyles = stylesStack.pop();
    } else {
     lastStyles = stylesStack.peek();
    }
   }
   return lastStyles;
  }

  private int currentIndex() {
   return text.length() - 1;
  }

 }

}
结论
实现您自己的SWT RichText控件可能不是满足您需求的最佳选择,您将需要权衡这样做的利弊,以及是否有必要投资其中一种现成的商业解决方案。 但是,我想通过这篇文章来演示如何在SWT对话框和视图中嵌入您自己的(简单且轻量级的)富文本编辑器,与从中获得的好处相比,它很容易实现并且需要花费很少的精力。

翻译自: https://www.javacodegeeks.com/2012/07/richtext-editor-component-for-swt-based.html

小程序richtext

 类似资料: