我在JTextPane / JTextField中发现了一个奇怪的错误(或者在它们下面的字体渲染中的某个地方)。我想知道是否有其他人遇到过同样的事情并且可能有解决方案。
我正在尝试在JTextPane中显示一些“特殊”或罕见的字符,并且一旦我更改了JTextField的字体(这与JTextPane完全无关!),JTextPane就会“分解”,并且没有更长时间显示这些字符。
这应该可以更好地解释我的意思:
public class Scrap {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setLayout(new BorderLayout());
JTextField field = new JTextField();
// Uncomment this line... and the JTextPane nor the JTextField
// no longer display the characters
// field.setFont(new Font("Arial", Font.PLAIN, 14));
frame.add(field, BorderLayout.SOUTH);
JTextPane textPane = new JTextPane();
textPane.setFont(new Font("Arial", Font.PLAIN, 14));
JScrollPane scroll = new JScrollPane(textPane);
frame.add(scroll, BorderLayout.CENTER);
StyledDocument doc = (StyledDocument) textPane.getDocument();
try {
String str = "◕ ◡◡ ◕";
doc.insertString(doc.getLength(), str, null);
} catch (BadLocationException e) {
e.printStackTrace();
}
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
}
编辑:这是问题的一个更好的例子。它似乎与Font的大小有关。移动滑块,您会注意到大小14不会渲染字形,而14恰好是JTextField字体的大小。
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.*;
import java.awt.*;
public class Scrap {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 200);
frame.setLayout(new BorderLayout());
final JTextField field = new JTextField(10);
final JTextPane textPane = new JTextPane();
StyledDocument doc = (StyledDocument) textPane.getDocument();
JPanel panel = new JPanel();
frame.add(panel, BorderLayout.SOUTH);
// Set the Font of the JTextField, and the JTextPane
// no longer displays the text of that size correctly...
int changeMe = 14;
field.setFont(new Font("Tahoma", Font.PLAIN, changeMe));
// If we change the Font Family, the problem goes away...
// field.setFont(new Font("Dialog", Font.PLAIN, 14));
panel.add(field);
final JLabel label = new JLabel();
final JSlider slider = new JSlider(6, 32);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
textPane.setFont(new Font("Tahoma", Font.PLAIN, slider.getValue()));
textPane.selectAll();
SimpleAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setFontSize(attr, slider.getValue());
textPane.setCharacterAttributes(attr, true);
label.setText("" + slider.getValue());
}
});
slider.setValue(14);
panel.add(slider);
panel.add(label);
JScrollPane scroll = new JScrollPane(textPane);
frame.add(scroll, BorderLayout.CENTER);
Style s = doc.addStyle("test", null);
try {
String str = "◕ ◡◡ ◕";
doc.insertString(doc.getLength(), str, doc.getStyle("test"));
} catch (BadLocationException e) {
e.printStackTrace();
}
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
}
答案 0 :(得分:2)
没有最深刻的想法发生了什么,而不是为什么,但必须设置
textPane.setContentType("text/html");
import java.awt.BorderLayout;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.StyledDocument;
public class Scrap {
public Scrap() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setLayout(new BorderLayout());
JTextField field = new JTextField();
// Uncomment this line... and the JTextPane nor the JTextField
// no longer display the characters
field.setFont(new Font("Arial", Font.PLAIN, 14));
frame.add(field, BorderLayout.SOUTH);
JTextPane textPane = new JTextPane();
textPane.setFont(new Font("Arial", Font.PLAIN, 14));
textPane.setContentType("text/html");
JScrollPane scroll = new JScrollPane(textPane);
frame.add(scroll, BorderLayout.CENTER);
StyledDocument doc = (StyledDocument) textPane.getDocument();
try {
String str = "\uD0180, \u2460, \u2760, \u2380, \u2C60, \u5000, \u03E0";
doc.insertString(doc.getLength(), str, null);
} catch (BadLocationException e) {
e.printStackTrace();
}
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Scrap fs = new Scrap();
}
});
}
}
答案 1 :(得分:1)
当我尝试创建一个必须支持多种语言的应用程序(包括带有“非标准”字符的语言,例如中文)时,我遇到了类似的问题。我曾经将我的小部件的字体设置为Arial
,并且遇到了问题。以下解决方案解决了我的问题,但它可能无法解决您的问题。
Java遇到无法显示的特定字符集中的字符时,会有一个回退机制。它可以使用随JRE提供的fontconfig.properties文件进行配置(该文件最初提供为“fontconfig.properties.src”,您必须手动重命名)。
当您强制使用不属于Dialog
,Serif
,SansSerif
,Monospaced
或DialogInput
的字体时,Java无法使用不同的字符集,如果当前的字符串(在你的情况下为Arial)不能代表你试图在屏幕上绘制的字符(或字形)。
如果查看fontconfig.properties.src文件,您会看到许多类型的字体有许多条目(例如Dialog.plain
,Serif.bold
等)。这些是上述字体无法显示特定字形时使用的实际后备字体。因此,设置小部件的字体让我们说Font.DIALOG
将允许Java尝试使用字体列表来显示您的字符。
有关更多信息,请访问Oracle网站(here for Java 7)。请注意,Oracle不正式支持使用fontconfig.properties。
答案 2 :(得分:0)
简单模拟字体和字形,
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
public class Fonts implements Runnable {
private String[] fnt;
private JFrame frm;
private JScrollPane jsp;
private JTextPane jta;
private JTextField field;
private int width = 450;
private int height = 300;
private GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
private StyledDocument doc;
private MutableAttributeSet mas;
private int cp = 0;
private Highlighter.HighlightPainter cyanPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.cyan);
private Highlighter.HighlightPainter redPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.red);
private Highlighter.HighlightPainter whitePainter = new DefaultHighlighter.DefaultHighlightPainter(Color.white);
private int _count = 0;
private int _lenght = 0;
public Fonts() {
jta = new JTextPane();
doc = jta.getStyledDocument();
jsp = new JScrollPane(jta);
jsp.setPreferredSize(new Dimension(height, width));
frm = new JFrame("awesome");
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frm.setLayout(new BorderLayout());
frm.add(jsp, BorderLayout.CENTER);
field = new JTextField();
field.setText("\u2460, \u2760, \u2380, \u2C60, \u5000, \u03E0");
frm.add(field, BorderLayout.SOUTH);
frm.setLocation(100, 100);
frm.pack();
frm.setVisible(true);
jta.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
fnt = ge.getAvailableFontFamilyNames();
mas = jta.getInputAttributes();
new Thread(this).start();
}
@Override
public void run() {
for (int i = 0; i < fnt.length; i++) {
StyleConstants.setBold(mas, false);
StyleConstants.setItalic(mas, false);
StyleConstants.setFontFamily(mas, fnt[i]);
StyleConstants.setFontSize(mas, 16);
//dis(fnt[i]);
dis("\u2460, \u2760, \u2380, \u2C60, \u5000, \u03E0");
field.setFont(new Font(fnt[i], Font.PLAIN, 14));
try {
Thread.sleep(450);
} catch (Exception e) {
e.printStackTrace();
}
/*StyleConstants.setBold(mas, true);
dis(fnt[i] + " Bold");
try {
Thread.sleep(75);
} catch (Exception e) {
e.printStackTrace();
}
StyleConstants.setItalic(mas, true);
dis(fnt[i] + " Bold & Italic");
try {
Thread.sleep(75);
} catch (Exception e) {
e.printStackTrace();
}
StyleConstants.setBold(mas, false);
dis(fnt[i] + " Italic");
try {
Thread.sleep(75);
} catch (Exception e) {
e.printStackTrace();
}*/
}
jta.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
public void dis(String s) {
_count++;
_lenght = jta.getText().length();
try {
doc.insertString(cp, s, mas);
doc.insertString(cp, "\n", mas);
} catch (Exception bla_bla_bla_bla) {
bla_bla_bla_bla.printStackTrace();
}
if (_count % 2 == 0) {
try {
jta.getHighlighter().addHighlight(1, _lenght - 1, cyanPainter);
} catch (BadLocationException bla_bla_bla_bla) {
}
} else if (_count % 3 == 0) {
try {
jta.getHighlighter().addHighlight(1, _lenght - 1, redPainter);
} catch (BadLocationException bla_bla_bla_bla) {
}
} else {
try {
jta.getHighlighter().addHighlight(1, _lenght - 1, whitePainter);
} catch (BadLocationException bla_bla_bla_bla) {
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Fonts fs = new Fonts();
}
});
}
}