2014-03-05 56 views
4

正如問題所述,如何成功將多個圖標放在JTextPane的同一行文本中?每次我嘗試更改actionText的值時,結果都非常不可預測。作爲一個例子,這是事情我想達到那種:(Java Swing)如何在同一行上創建帶有多個圖標的JTextPane?

Cool board game text I'd like to have

如果我通過只是圖標令牌創建圖標(」」,例如),他們只是堆頂彼此(或者可能不會,很難說)。如果我把「,」或「和」放在第一行,第一行出現第一個戰鬥機圖標,而第二行出現逗號和其他戰鬥機圖標。

我目前正在嘗試使用基於oracle教程構建的解決方案JTextPaneJTextPane tutorial。這是我的代碼塊創建我的自定義文本窗格。

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

你可以添加你的'textpane'圖片嗎? –

回答

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

更新後

我有一點的發揮作用的,看如果我能得到的格式看起來好一點,這基本上是我想出來的...

Adventure

而不是使用樣式,我基本上插入文本和圖像直接到文本窗格。似乎相似的樣式被設置爲相鄰的問題,所以相反,發生了什麼,它們基本上合併到文檔中的單個條目中,這可以解釋爲什麼您的樣式有問題。我有一個類似的問題與圖標出於某種原因,因此我必須每次創建一個新實例的原因...

這是有點粗糙和準備好,但基本的想法在那裏。它基本上使用正則表達式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; 
} 

現在,坦率地說,我已經不用擔心線寬等問題,而是使用JScrollPaneJTextComponent的包裝功能來代替......但這取決於您...

+0

非常感謝!我使用了第一個解決方案,因爲它非常簡單,只需添加這兩行代碼即可。我試圖製作的遊戲並不是很複雜,所以它運行良好。如果它擴展了,儘管我很可能會使用類似於您在「更新」條目下發布的內容。乾杯! –

相關問題