Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
(Java Swing)如何创建一个在同一行上有多个图标的JTextPane?_Java_Swing_Icons_Jtextpane - Fatal编程技术网

(Java Swing)如何创建一个在同一行上有多个图标的JTextPane?

(Java Swing)如何创建一个在同一行上有多个图标的JTextPane?,java,swing,icons,jtextpane,Java,Swing,Icons,Jtextpane,如问题所述,如何在JTextPane中的同一行文本上成功放置多个图标?每次我尝试更改actionText的值时,结果都是非常不可预测的。举个例子,这就是我想要实现的目标: 如果我只传递图标标记来创建图标(“”,例如),它们只是堆叠在一起(或者可能不是,很难说)。如果我把“,”或“和”,那么第一个战斗机图标出现在第一行,而逗号和其他战斗机图标出现在第二行 我目前正在尝试使用一个基于oracle教程的解决方案,用于JTextPane:。下面是创建自定义文本窗格的代码块 public final c

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

如果我只传递图标标记来创建图标(“”,例如),它们只是堆叠在一起(或者可能不是,很难说)。如果我把“,”或“和”,那么第一个战斗机图标出现在第一行,而逗号和其他战斗机图标出现在第二行

我目前正在尝试使用一个基于oracle教程的解决方案,用于
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 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;
}
公共最终类GameTextPaneFactory{
私有静态最终字符串[]冒险家_令牌={“”、“”、“”、“”};
私有静态最终整型文本窗格宽度=30;
公共静态JTextPane createActionTextPane(字符串actionText){
ArrayList[]wordsAndStyles=parseActionText(actionText);
JTextPane actionTextPane=新的JTextPane();
StyledDocument doc=actionTextPane.getStyledDocument();
addStylesToDocument(doc);
试一试{
对于(int i=0;i文本窗格宽度){
nextStringBuilder.append(“\n”);
currentLineLength=0;
}
nextStringBuilder.append(“+”字);
currentLineLength+=字长度()+1;
}
}
如果(nextStringBuilder.length()!=0){
add(nextStringBuilder.toString());
添加(“常规”);
}       
@抑制警告(“未选中”)
ArrayList[]输出=新的ArrayList[2];
输出[0]=输出字符串;
输出[1]=输出样式;
返回输出;
}
}

如果有人有更好的解决办法,我会洗耳恭听。谢谢

尝试添加

outputStrings.add(" "); // this is ignored, but cannot be empty
outputStyles.add("regular");
在每一个新的“冒险家”风格之后

outputStrings.add(“”;//这将被忽略,但不能为空
开关(字){
案例“”:
outputStyles.add(“fighterIcon”);
打破
案例“”:
outputStyles.add(“clericIcon”);
打破
案例“”:
添加(“向导图标”);
打破
案例“”:
outputStyles.add(“rogueIcon”);
打破
}
OutputString.add(“”;//这将被忽略,但不能为空
添加(“常规”);
已更新

我有一个小游戏,看看我是否可以得到格式看起来更好一点,这基本上是我想出的

我基本上没有使用样式,而是直接将文本和图像插入到文本窗格中。似乎有类似样式的问题被设置在彼此的旁边,因此,相反,它们基本上被合并到文档中的单个条目中,这可以解释为什么您的样式存在问题。出于某种原因,我对图标也有类似的问题,因此,我必须在每个tim中创建一个新实例
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");
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;
}