文章目录
- 需求分析
- Document 应用
- 彩蛋
需求分析
在Swing中,如果期望实现对JTextArea 或者 TextPane等文本区域实现单行渲染改怎么做?如上图所示
总的来说有两种实现方案
-
文本行数可控,那么构造一组JLabel集合按表单顺序添加,这样可以预先调整特定位置的颜色
-
文本行数未知,想基于关键字模糊匹配,甚至将所在行进行统一控制,那么需要借助Document对象完成
如果行数可控的文本控制,直接使用label.setColor(XXX)
即可设置,无需过多考虑,下面主要探讨行数可变,且不同需求下的文本渲染问题。
Document 应用
在行数可变前提下 还得你的技术选型是什么,不同的Component的渲染方式思路一样,但实现上略有差异。否则东施效颦,结果啥也出不来
- 基于JTextArea 的 Document
private JTextArea jTextArea = new JTextArea();# 引入样式组件private StyleContext styleContext = new StyleContext();# 添加全局样式private Style redStyle = styleContext.addStyle("red", null);private Style common = styleContext.addStyle("common", null);StyleConstants.setForeground(redStyle, Color.RED);StyleConstants.setForeground(common, Color.BLACK);# 使用 Document document = jTextArea.getDocument();# 注意这个方式是以插入方式渲染,也就是说其他默认样式也需要通过插入方式到textArea,否则就会出现内容丢失//document.insertString(document.getLength(), "特定文本之前内容", common);document.insertString(document.getLength(), "特定文本", redStyle);//document.insertString(document.getLength(), "特定文本之后的内容", common);
- 基于JTextPane 的StyleDocument
本文开头使用的便是如下这种方式
JTextPane textPane = new JTextPane();textPane.setEditable(false); // 可编辑textPane.setFont(new Font("微软雅黑", Font.PLAIN, 16)); // 设置字体textPane.setText("hello swing this is red\n hello java, this is blue\n hello word\n");StyledDocument styledDocument = textPane.getStyledDocument();SimpleAttributeSet red = new SimpleAttributeSet();StyleConstants.setForeground(red, Color.RED);// 关键字渲染String text = textPane.getText();int swing = text.indexOf("swing");styledDocument.setCharacterAttributes(swing, swing, red, true);SimpleAttributeSet blue = new SimpleAttributeSet();StyleConstants.setForeground(blue, Color.BLUE);StyleConstants.setBold(blue, true);// 按行渲染int java = text.indexOf("java");Element defaultRootElement = styledDocument.getDefaultRootElement();int offset = defaultRootElement.getElementIndex(java);int start = defaultRootElement.getElement(offset).getStartOffset();int end = defaultRootElement.getElement(offset).getEndOffset();styledDocument.setCharacterAttributes(start, end - start, blue, true);
- 基于JTextPane的HTML文档
// 创建一个 JTextPaneJTextPane textPane = new JTextPane();textPane.setEditable(false); // 不可编辑// 创建一个 HTML 文档HTMLEditorKit kit = new HTMLEditorKit();StyleSheet styleSheet = kit.getStyleSheet();styleSheet.addRule("body { font-size: 16px; font-family: Arial; }"); // 自定义样式String htmlContent = "<html><body><h1>Hello, <span style='color: blue;'>World</span></h1></body></html>";try {textPane.setEditorKit(kit);textPane.setText(htmlContent);} catch (Exception e) {e.printStackTrace();}
彩蛋
重构之美系列文章一定存在通用解决方案的工具方法,大家可参考使用:
/**重点介绍:String... tags 统一渲染的关键字集合replaceAll: 是否对tag 进行全文样式替换*/
private void repaintCaseTitle(StyledDocument doc, SimpleAttributeSet style, boolean replaceAll, String... tags) {String text = jTextPane.getText();for (String tag : tags) {int i = text.indexOf(tag);if (i < 0) {log.info(tag + "无效渲染");return;}Element defaultRootElement = doc.getDefaultRootElement();if (!replaceAll) {int offset = defaultRootElement.getElementIndex(i);int startIndex = defaultRootElement.getElement(offset).getStartOffset();int endIndex = defaultRootElement.getElement(offset).getEndOffset();doc.setCharacterAttributes(startIndex, endIndex - startIndex, style, true);continue;}// 全部替换for (int j = 0; j < defaultRootElement.getElementCount(); j++) {Element line = defaultRootElement.getElement(j);try {String lineText = doc.getText(line.getStartOffset(), line.getEndOffset() - line.getStartOffset());if (lineText.contains(tag)) {doc.setCharacterAttributes(line.getStartOffset(), line.getEndOffset() - line.getStartOffset(), style, true);}} catch (BadLocationException e) {e.printStackTrace();}}}}
改工具方法基于JTextPane提供通用样式渲染提供简便调用
使用时仅仅需要通过一行代码便可以对目标关键字进行按行渲染, 如果还有定制化需求,可自行修改
repaintCaseTitle(doc, redStyle, false, "测试", "分析", "异常");
研发不易,多多支持