IntelliJ插件开发:如何实现编辑器内多行内联文本显示
在IntelliJ编辑器中实现多行自动换行的内联文本
问题分析
你尝试用EditorCustomElementRenderer添加块元素,但drawString只能处理单行文本,直接用JBTextArea无法在paint方法中直接绘制——因为Swing组件的绘制依赖自身布局上下文,和编辑器的Inlay绘制逻辑不兼容。
可行解决方案
放弃使用JBTextArea,改为手动处理文本换行+逐行绘制,同时正确实现自定义元素的宽高计算,确保编辑器排版正常。
修改后的实现代码
import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorColorsScheme; import com.intellij.openapi.editor.EditorFontType; import com.intellij.openapi.editor.Inlay; import com.intellij.openapi.editor.TextAttributes; import org.jetbrains.annotations.NotNull; import java.awt.*; import java.awt.font.FontMetrics; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; public class MultilineInlayRenderer implements EditorCustomElementRenderer { private final List<String> wrappedLines; private final Color textColor; private final Font editorFont; private final int lineHeight; public MultilineInlayRenderer(String content, Color color, Editor editor) { this.textColor = color; EditorColorsScheme scheme = editor.getColorsScheme(); this.editorFont = scheme.getFont(EditorFontType.PLAIN); this.lineHeight = editor.getLineHeight(); // 根据编辑器可用宽度,提前计算好换行后的文本行(留40px边距避免贴边) int maxLineWidth = editor.getContentComponent().getWidth() - 40; this.wrappedLines = wrapTextToFitWidth(content, editorFont, maxLineWidth); } /** * 将文本按指定宽度分割成多行,优先在单词边界换行 */ private List<String> wrapTextToFitWidth(String content, Font font, int maxWidth) { List<String> lines = new ArrayList<>(); if (content.isEmpty()) return lines; FontMetrics metrics = new JPanel().getFontMetrics(font); StringBuilder currentLine = new StringBuilder(); StringTokenizer tokenizer = new StringTokenizer(content, " \n", true); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); // 遇到换行符直接换行 if ("\n".equals(token)) { lines.add(currentLine.toString().trim()); currentLine.setLength(0); continue; } int currentLineWidth = metrics.stringWidth(currentLine.toString()); int tokenWidth = metrics.stringWidth(token); // 当前行加token超过宽度时,先提交当前行再添加token if (currentLineWidth + tokenWidth > maxWidth && currentLine.length() > 0) { lines.add(currentLine.toString().trim()); currentLine.setLength(0); } currentLine.append(token); } // 添加最后一行内容 if (!currentLine.isEmpty()) { lines.add(currentLine.toString().trim()); } return lines; } @Override public void paint(@NotNull Inlay inlay, @NotNull Graphics graphics, @NotNull Rectangle targetRegion, @NotNull TextAttributes textAttributes) { Editor editor = inlay.getEditor(); graphics.setFont(editorFont); graphics.setColor(textColor); int currentY = targetRegion.y + editor.getAscent(); int startX = targetRegion.x + 2; // 左内边距 for (String line : wrappedLines) { graphics.drawString(line, startX, currentY); currentY += lineHeight; } } @Override public int calcWidthInPixels(@NotNull Inlay inlay) { // 计算所有行中的最大宽度,加上左右内边距 FontMetrics metrics = inlay.getEditor().getContentComponent().getFontMetrics(editorFont); int maxWidth = 0; for (String line : wrappedLines) { maxWidth = Math.max(maxWidth, metrics.stringWidth(line)); } return maxWidth + 4; } @Override public int calcHeightInPixels(@NotNull Inlay inlay) { // 总高度 = 行数 × 编辑器行高 + 上下内边距 return wrappedLines.size() * lineHeight + 4; } }
关键说明
- 文本换行逻辑:通过
FontMetrics计算文本宽度,在单词边界或换行符处分割文本,避免切断单词。 - 尺寸计算:必须实现
calcWidthInPixels和calcHeightInPixels,让编辑器知道自定义元素的准确大小,防止覆盖其他内容或排版错乱。 - 绘制细节:添加内边距优化显示效果,使用编辑器自带的字体和行高,保持与编辑器风格统一。
内容的提问来源于stack exchange,提问作者some_dev_guy
相关产品推荐
相关产品推荐

