(Java Swing)如何在同一行创建一个包含多个图标的JTextPane? [英] (Java Swing) How do I create a JTextPane with multiple icons on the same line?

查看:100
本文介绍了(Java Swing)如何在同一行创建一个包含多个图标的JTextPane?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如问题所述,如何在 JTextPane 中的同一行文本上成功放置多个图标?每次我尝试更改 actionText 的值时,结果都是非常不可预测的。举个例子,这就是我想要达到的目的:





如果我只传递图标标记来创建图标(,例如),他们只是堆叠在一起(或许不是,很难说)。如果我输入,或和,则第一个战斗机图标出现在第一行,而逗号和其他战斗机图标出现在第二行。



<我正在尝试使用基于oracle教程构建的解决方案 JTextPane JTextPane教程。以下是我创建自定义文本窗格的代码块。

  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){
System.err.println(无法在文本窗格中插入初始文本。);
}

actionTextPane.setEditable(false);
返回actionTextPane;
}

private static void addStylesToDocument(StyledDocument doc){
// TODO add images(styles)here
Style def = StyleContext.getDefaultStyleContext()。getStyle( StyleContext.DEFAULT_STYLE);
样式regular = doc.addStyle(regular,def);

样式图标= doc.addStyle(fighterIcon,常规);
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,常规);
StyleConstants.setAlignment(icons,StyleConstants.ALIGN_CENTER);
ImageIcon wizardIcon = new ImageIcon(images / wizard_image.png,wizard);
StyleConstants.setIcon(icons,wizardIcon);

icons = doc.addStyle(rogueIcon,常规);
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(); //这被忽略,但不能为空
switch(word){
case< FIGHTER>:
outputStyles.add(fighterIcon);
休息;
case< CLERIC>:
outputStyles.add(clericIcon);
休息;
case< WIZARD>:
outputStyles.add(wizardIcon);
休息;
case< ROGUE>:
outputStyles.add(rogueIcon);
休息;
}

currentLineLength + = 3; //一个图标长度约为3个字符
} 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;
输出[1] = outputStyles;
返回输出;
}

}



如果有人有更好的解决方案,我会全力以赴。谢谢!

解决方案

尝试添加

  outputStrings.add(); //这被忽略了,但不能为空
outputStyles.add(regular);

每个新的冒险家风格之后

  outputStrings.add(); //这被忽略,但不能为空
switch(word){
case< FIGHTER>:
outputStyles.add(fighterIcon);
休息;
case< CLERIC>:
outputStyles.add(clericIcon);
休息;
case< WIZARD>:
outputStyles.add(wizardIcon);
休息;
case< ROGUE>:
outputStyles.add(rogueIcon);
休息;
}
outputStrings.add(); //这被忽略了,但不能为空
outputStyles.add(regular);

已更新



<我有一点玩耍,看看我是否可以让格式看起来好一点,这基本上就是我想出来的......





我基本上不使用样式文本和图像直接到文本窗格。似乎有相似的样式彼此相邻设置的问题,所以相反,它们基本上合并到文档中的单个条目,这可以解释为什么你的样式有问题。出于某种原因,我在图标上遇到了类似的问题,因此我每次都必须创建一个新实例...



这有点粗糙并准备就绪,但基本的想法是存在的。它基本上使用正则表达式API来查找关键字的所有匹配项,在其前面插入文本,然后根据关键字插入一个特殊图标...

  public static JTextPane createActionTextPane(String actionText){
JTextPane actionTextPane = new JTextPane();
actionTextPane.setOpaque(false);

StyledDocument doc = actionTextPane.getStyledDocument();

模式模式= 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));
休息;
case< CLERIC>:
actionTextPane.insertIcon(new ImageIcon(mage.gif));
休息;
case< GOLD>:
actionTextPane.insertIcon(new ImageIcon(Gold.png));
休息;
}

previousMatch = endIndex;

}
String subText = actionText.substring(previousMatch);
if(!subText.isEmpty()){
actionTextPane.replaceSelection(subText);
}

actionTextPane.setEditable(false);
返回actionTextPane;
}

现在,坦率地说,我并没有对线宽等感到困扰,而是使用 JScrollPane JTextComponent 的包装功能......但这取决于你... 。


As the question states, how do I successfully place multiple icons on the same line of text in a JTextPane? Every time I try to change the value of actionText, the results are very unpredictable. As an example, this is the kind of thing I'm trying to achieve :

If I pass just the icon-tokens to create icons (" ", for example), they just stack on top of each other (or maybe not, hard to tell). If I put " , " or " and ", then the first fighter-icon appears on the first line, while the comma and other fighter-icon appears on the second line.

I am currently trying using a solution built upon the oracle tutorial for JTextPane : JTextPane tutorial. Here is the chunk of my code that creates my custom text panes.

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;
}

}

If someone has a better solution I am all ears. Thanks!

解决方案

Try adding

outputStrings.add(" "); // this is ignored, but cannot be empty
outputStyles.add("regular");

After each new "adventurer" style

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");

Updated

I had a bit of a play around, seeing if I could get the formatting to look a little better, this is basically what I came up with...

Instead of using styles, I basically insert the text and images directly to the text pane. There seems to be issues with like styles been set next to each other, so that instead what happens, they are basically merged into a single entry in the document, this would explain why you had issues with your styles. I had a similar issue with the icons for some reason, hence the reason why I had to create a new instance each time...

This is a bit rough and ready, but the basic idea is there. It basically uses the Regular Expression API to find all the matches of the "keywords", inserts the text before it and then inserts a special icon depending on the keyword...

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;
}

Now, frankly, I've not bothered about line widths or the like, and instead, used a JScrollPane and the JTextComponent's wrapping capabilities instead...but that's up to you...

这篇关于(Java Swing)如何在同一行创建一个包含多个图标的JTextPane?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆