在 Canvas 低階繪圖上顯示長文字(如 RPG 對話),需自動依螢幕寬度換行。英文不可拆分單字,中日文可逐字換行。
/**
* 將文字依指定字體與寬度分行
* @param strSource 原始字串
* @param font 使用字體
* @param width 最大像素寬度
* @param strSplit 斷詞分隔字元(英文用 " ,.?!",中文傳 "")
* @return Vector<String> 每一行文字
*/
public Vector getSubsection(String strSource, Font font, int width, String strSplit) {
Vector lines = new Vector();
String temp = strSource;
int lastLen = 1;
try {
while (!temp.equals("")) {
int i = temp.indexOf('\n');
// 手動換行優先處理
if (i > 0 && font.stringWidth(temp.substring(0, i)) <= width) {
// 保留手動換行
} else {
i = -1;
}
if (i == -1) {
// 尋找適合寬度的臨界點
if (lastLen > temp.length()) i = temp.length();
else {
i = lastLen;
int step = font.stringWidth(temp.substring(0, i)) > width ? -1 : 1;
while (i < temp.length() &&
!(font.stringWidth(temp.substring(0, i)) <= width &&
font.stringWidth(temp.substring(0, i+1)) > width)) {
i += step;
}
}
// 英文斷詞處理
if (!strSplit.equals("") && i < temp.length()) {
int j = i;
while (strSplit.indexOf(temp.charAt(i-1)) == -1) {
i--;
if (i == 0) { i = j; break; } // 整行只有單一長單字
}
}
}
lastLen = i;
lines.addElement(temp.substring(0, i));
if (i == temp.length()) temp = "";
else {
temp = temp.substring(i);
if (temp.startsWith("\n")) temp = temp.substring(1);
}
}
} catch (Exception e) {
System.out.println("getSubsection: " + e);
}
return lines;
}
int lineHeight = 15;
int startLine = 0; // 由 keyPressed 控制翻頁
String text = "方便起見,可以定義一個行高作為全局變量...";
Vector lines = getSubsection(text, Font.getDefaultFont(), getWidth(), "");
for (int i = startLine; i < lines.size(); i++) {
g.drawString((String)lines.elementAt(i), 0, lineHeight * i, Graphics.TOP|Graphics.LEFT);
if ((i - startLine + 1) * lineHeight > getHeight()) break;
}
lines = null; // 釋放參考
strSplit 傳 " ,.?!" 可避免英文單字被拆半;中文、日文(若不需斷詞)傳空字串。strSplit 回溯至最近分隔字元。\n 強制換行。Vector 便於分頁、捲動顯示。