重构之美:Java Swing中 如何对指定行文本进行CSS样式渲染,三种实现思路分享

文章目录

需求分析

在Swing中,如果期望实现对JTextArea 或者 TextPane等文本区域实现单行渲染改怎么做?如上图所示

总的来说有两种实现方案

  • 文本行数可控,那么构造一组JLabel集合按表单顺序添加,这样可以预先调整特定位置的颜色

  • 文本行数未知,想基于关键字模糊匹配,甚至将所在行进行统一控制,那么需要借助Document对象完成

如果行数可控的文本控制,直接使用label.setColor(XXX)即可设置,无需过多考虑,下面主要探讨行数可变,且不同需求下的文本渲染问题。


Document 应用

在行数可变前提下 还得你的技术选型是什么,不同的Component的渲染方式思路一样,但实现上略有差异。否则东施效颦,结果啥也出不来

  1. 基于JTextArea 的 Document
java 复制代码
 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);
  1. 基于JTextPane 的StyleDocument
    本文开头使用的便是如下这种方式
java 复制代码
		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);
  1. 基于JTextPane的HTML文档
java 复制代码
 		// 创建一个 JTextPane
        JTextPane 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();
        }

彩蛋

重构之美系列文章一定存在通用解决方案的工具方法,大家可参考使用:

java 复制代码
/**
 重点介绍:
 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提供通用样式渲染提供简便调用

使用时仅仅需要通过一行代码便可以对目标关键字进行按行渲染, 如果还有定制化需求,可自行修改

java 复制代码
  repaintCaseTitle(doc, redStyle, false, "测试", "分析", "异常");

研发不易,多多支持

相关推荐
寻星探路2 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
曹牧4 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
爬山算法5 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty7255 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎5 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
李少兄5 小时前
在 IntelliJ IDEA 中修改 Git 远程仓库地址
java·git·intellij-idea
忆~遂愿6 小时前
ops-cv 算子库深度解析:面向视觉任务的硬件优化与数据布局(NCHW/NHWC)策略
java·大数据·linux·人工智能
小韩学长yyds6 小时前
Java序列化避坑指南:明确这4种场景,再也不盲目实现Serializable
java·序列化
仟濹6 小时前
【Java基础】多态 | 打卡day2
java·开发语言
Re.不晚6 小时前
JAVA进阶之路——无奖问答挑战2
java·开发语言