如何在可读写JTextPane中将UUID替换为可视化块并保证操作原子性
实现方案
你需要的效果Swing原生完全支持,核心用到两类特性:StyledDocument的非文本内容渲染能力、导航+文档过滤器实现原子操作,以下是具体实现步骤:
1. 渲染自定义名称方块
有两种实现方式,可根据你的需求选择:
方案A:嵌入Swing组件(实现简单)
Swing的JTextPane支持直接将Swing组件作为特殊元素插入文档,底层用单个占位符\uFFFC存储,显示时直接渲染为你定义的组件:
- 先自定义引用展示组件:可以是带圆角、背景色的
JLabel或者JPanel,上面直接显示pattern的名称,还可以额外加点击右键编辑等交互逻辑,组件内部可以存储对应的UUID值方便后续读取。 - 插入组件到文档:通过样式的
ComponentAttribute绑定组件,插入占位符到文档即可,示例代码如下:
// 自定义引用展示标签 JLabel refLabel = new JLabel("GoodName"); refLabel.setOpaque(true); refLabel.setBackground(new Color(230, 230, 230)); refLabel.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(180, 180, 180), 1, true), BorderFactory.createEmptyBorder(2, 5, 2, 5) )); // 存储关联UUID,方便后续从文档提取内容时读取 refLabel.putClientProperty("patternUUID", "你对应的UUID字符串"); // 绑定到样式插入文档 Style refStyle = jTextPane.addStyle("patternRef", null); StyleConstants.setComponent(refStyle, refLabel); try { jTextPane.getStyledDocument().insertString( jTextPane.getCaretPosition(), "\uFFFC", // 固定的组件占位符 refStyle ); } catch (BadLocationException e) { // 处理异常 }
方案B:自定义View(性能更优)
如果你的文档里引用数量很多,嵌入组件会有额外的组件开销,可以自定义字符渲染View,直接在画布上绘制名称方块:
- 自定义
PatternRefView继承LabelView,重写paint方法绘制你要的方块、边框和文字,重写getPreferredSpan方法设置方块的宽高。 - 给
JTextPane设置自定义ViewFactory,判断当前字符段的属性如果是pattern引用,就返回你自定义的PatternRefView实例即可。
2. 实现引用的原子性
要避免用户选中、修改引用的部分内容,只需要加两个过滤器即可:
- 加
NavigationFilter:拦截光标移动和选中操作,判断光标即将进入的位置如果是引用区域,直接将光标调整到引用区域的两端,禁止光标停在引用内部,也禁止选中引用的部分内容。 - 加
DocumentFilter:拦截文档修改操作,如果用户的插入、删除操作涉及到引用区域,要么直接删除整个引用,要么禁止部分修改,确保引用不会被拆分。
你之前用到的样式功能只覆盖了文本样式修改的场景,StyleConstants里的ComponentAttribute、IconAttribute以及自定义ViewFactory就是用来实现非文本内容渲染的Swing原生能力,不需要引入第三方组件。
内容的提问来源于stack exchange,提问作者FWDekker
相关产品推荐
相关产品推荐

