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


    需求分析

    在这里插入图片描述

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

    总的来说有两种实现方案

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

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

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


    Document 应用

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

    1. 基于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);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1. 基于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);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    1. 基于JTextPane的HTML文档
     		// 创建一个 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 = "

    Hello, World

    "
    ; try { textPane.setEditorKit(kit); textPane.setText(htmlContent); } catch (Exception e) { e.printStackTrace(); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    彩蛋

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

    
    /**
     重点介绍:
     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();
                    }
    
                }
    
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    改工具方法基于JTextPane提供通用样式渲染提供简便调用
    使用时仅仅需要通过一行代码便可以对目标关键字进行按行渲染, 如果还有定制化需求,可自行修改

      repaintCaseTitle(doc, redStyle, false, "测试", "分析", "异常");
    
    • 1

    研发不易,多多支持

  • 相关阅读:
    MySQL笔记-05 数据表操作
    【已解决】matrix contains invalid numeric entries,记录bug修改
    详细剖析多线程4----锁策略(八股文/面试常考)
    汽车智能计算平台公司「地平线」在 Ingress Controller 的探索和实践
    pyhton如何判断字符串中是否只含有数字——isdigit函数的用法及实例
    HTML+CSS-Day12
    Python读写文件代码
    《纳瓦尔宝典》和一个智者的对话的奇妙旅程
    c#中单例模式详解
    [Python进阶] Pyinstaller减少打包后程序大小
  • 原文地址:https://blog.csdn.net/lkg5211314/article/details/134013841