正如问题所述,如何在JTextPane
的同一行文本中成功放置多个图标?每当我尝试更改actionText
的值时,结果都是非常难以预测的。举个例子,这就是我想要实现的目标:
如果我只传递图标标记来创建图标(例如“”“),它们只是堆叠在一起(或者可能不是,很难说)。如果我输入“,”或“和”,则第一个战斗机图标出现在第一行,而逗号和其他战斗机图标出现在第二行。
我目前正在尝试使用基于JTextPane
:JTextPane tutorial的oracle教程构建的解决方案。以下是我创建自定义文本窗格的代码块。
public final class GameTextPaneFactory {
private static final String[] ADVENTURER_TOKENS = {"<FIGHTER>", "<CLERIC>", "<WIZARD>", "<ROGUE>"};
private static final int TEXT_PANE_WIDTH = 30;
public static JTextPane createActionTextPane(String actionText) {
ArrayList<String>[] wordsAndStyles = parseActionText(actionText);
JTextPane actionTextPane = new JTextPane();
StyledDocument doc = actionTextPane.getStyledDocument();
addStylesToDocument(doc);
try {
for (int i=0; i < wordsAndStyles[0].size(); i++) {
doc.insertString(doc.getLength(), wordsAndStyles[0].get(i),
doc.getStyle(wordsAndStyles[1].get(i)));
}
} catch (BadLocationException ble) {
System.err.println("Couldn't insert initial text into text pane.");
}
actionTextPane.setEditable(false);
return actionTextPane;
}
private static void addStylesToDocument(StyledDocument doc) {
// TODO add images (styles) here
Style def = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
Style regular = doc.addStyle("regular", def);
Style icons = doc.addStyle("fighterIcon", regular);
StyleConstants.setAlignment(icons, StyleConstants.ALIGN_CENTER);
ImageIcon fighterIcon = new ImageIcon("images/fighter_image.png", "fighter");
StyleConstants.setIcon(icons, fighterIcon);
icons = doc.addStyle("clericIcon", regular);
StyleConstants.setAlignment(icons, StyleConstants.ALIGN_CENTER);
ImageIcon clericIcon = new ImageIcon("images/cleric_image.png", "cleric");
StyleConstants.setIcon(icons, clericIcon);
icons = doc.addStyle("wizardIcon", regular);
StyleConstants.setAlignment(icons, StyleConstants.ALIGN_CENTER);
ImageIcon wizardIcon = new ImageIcon("images/wizard_image.png", "wizard");
StyleConstants.setIcon(icons, wizardIcon);
icons = doc.addStyle("rogueIcon", regular);
StyleConstants.setAlignment(icons, StyleConstants.ALIGN_CENTER);
ImageIcon rogueIcon = new ImageIcon("images/rogue_image.png", "rogue");
StyleConstants.setIcon(icons, rogueIcon);
}
private static ArrayList<String>[] parseActionText(String text) {
String[] words = text.split(" ");
ArrayList<String> outputStrings = new ArrayList<String>();
ArrayList<String> outputStyles = new ArrayList<String>();
StringBuilder nextStringBuilder = new StringBuilder();
int currentLineLength = TEXT_PANE_WIDTH;
for(String word : words) {
if(Arrays.asList(ADVENTURER_TOKENS).contains(word)) {
if(nextStringBuilder.length() != 0) {
outputStrings.add(nextStringBuilder.toString());
outputStyles.add("regular");
nextStringBuilder = new StringBuilder();
}
outputStrings.add(" "); // this is ignored, but cannot be empty
switch(word) {
case "<FIGHTER>":
outputStyles.add("fighterIcon");
break;
case "<CLERIC>":
outputStyles.add("clericIcon");
break;
case "<WIZARD>":
outputStyles.add("wizardIcon");
break;
case "<ROGUE>":
outputStyles.add("rogueIcon");
break;
}
currentLineLength += 3; // an icon is about 3 characters in length
} else {
if(currentLineLength + word.length() + 1 > TEXT_PANE_WIDTH) {
nextStringBuilder.append("\n");
currentLineLength = 0;
}
nextStringBuilder.append(" " + word);
currentLineLength += word.length() + 1;
}
}
if(nextStringBuilder.length() != 0) {
outputStrings.add(nextStringBuilder.toString());
outputStyles.add("regular");
}
@SuppressWarnings("unchecked")
ArrayList<String>[] output = new ArrayList[2];
output[0] = outputStrings;
output[1] = outputStyles;
return output;
}
}
如果某人有更好的解决方案,我会全力以赴。谢谢!
答案 0 :(得分:6)
尝试添加
outputStrings.add(" "); // this is ignored, but cannot be empty
outputStyles.add("regular");
每个新的“冒险家”风格之后
outputStrings.add(" "); // this is ignored, but cannot be empty
switch (word) {
case "<FIGHTER>":
outputStyles.add("fighterIcon");
break;
case "<CLERIC>":
outputStyles.add("clericIcon");
break;
case "<WIZARD>":
outputStyles.add("wizardIcon");
break;
case "<ROGUE>":
outputStyles.add("rogueIcon");
break;
}
outputStrings.add(" "); // this is ignored, but cannot be empty
outputStyles.add("regular");
<强>更新强>
我玩了一下,看看我是否可以让格式看起来好一点,这基本上就是我提出的......
我基本上将文本和图像直接插入文本窗格,而不是使用样式。似乎有类似样式的问题彼此相邻设置,所以相反,它们基本上合并到文档中的单个条目,这可以解释为什么你的样式有问题。出于某种原因,我在图标上遇到了类似的问题,因此我每次都必须创建一个新实例......
这有点粗糙和准备,但基本的想法是存在的。它基本上使用正则表达式API来查找“关键字”的所有匹配项,在其前面插入文本,然后根据关键字插入一个特殊图标......
public static JTextPane createActionTextPane(String actionText) {
JTextPane actionTextPane = new JTextPane();
actionTextPane.setOpaque(false);
StyledDocument doc = actionTextPane.getStyledDocument();
Pattern pattern = Pattern.compile("<FIGHTER>|<CLERIC>|<GOLD>");
Matcher matcher = pattern.matcher(actionText);
int previousMatch = 0;
while (matcher.find()) {
int startIndex = matcher.start();
int endIndex = matcher.end();
String group = matcher.group();
String subText = actionText.substring(previousMatch, startIndex);
if (!subText.isEmpty()) {
actionTextPane.replaceSelection(subText);
}
switch (group) {
case "<FIGHTER>":
actionTextPane.insertIcon(new ImageIcon("fifight.gif"));
break;
case "<CLERIC>":
actionTextPane.insertIcon(new ImageIcon("mage.gif"));
break;
case "<GOLD>":
actionTextPane.insertIcon(new ImageIcon("Gold.png"));
break;
}
previousMatch = endIndex;
}
String subText = actionText.substring(previousMatch);
if (!subText.isEmpty()) {
actionTextPane.replaceSelection(subText);
}
actionTextPane.setEditable(false);
return actionTextPane;
}
现在,坦率地说,我并没有对线宽等感到困扰,而是使用了JScrollPane
和JTextComponent
的包裹功能......但这取决于你。 ..
答案 1 :(得分:4)
结帐Auto Replace Smiles Text With Appropriate Images。可能不完全不是你想要的,但它应该给你一些想法