我想允许用户放大或缩小不可编辑的 JTextPane。
运行下面的示例程序,我发现缩放 Graphics 对象会导致粗体文本和非粗体文本之间的间距不一致。如果粗体和非粗体之间有一个空格,有时它会被渲染得太宽,而在其他缩放级别上,空格会消失并且相邻的字符会重叠。
如果没有渲染提示,间距在 100% 时正确,但在其他缩放级别不正确。使用 KEY_FRACTIONALMETRICS 渲染提示,结果在所有缩放级别都是一致的,但粗体和非粗体之间的间距即使在 100% 时也是错误的。
我用 Java 1.6.0_13 和 1.6.0_23 都试过了。结果是一样的。有什么建议可以在所有缩放级别上实现有吸引力的缩放渲染吗?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
public class ScaledJTextPane extends JTextPane
{
double scale_;
public ScaledJTextPane()
{
scale_ = 1.0;
}
protected void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
// Try with and without the rendering hint
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2.scale(scale_, scale_);
super.paintComponent(g2);
}
public void setScale(double scale)
{
scale_ = scale;
}
private static void createAndShowGUI()
{
// Create and set up the window.
JFrame frame = new JFrame("ScaledJTextPane");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final ScaledJTextPane scaledTextPane = new ScaledJTextPane();
StyledDocument doc = scaledTextPane.getStyledDocument();
Style defaultStyle = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
Style boldStyle = doc.addStyle("bold", defaultStyle);
StyleConstants.setBold(boldStyle, true);
scaledTextPane.setFont(new Font("Dialog", Font.PLAIN, 14));
String boldText = "Four score and seven years ago ";
String plainText = "our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.";
try
{
doc.insertString(doc.getLength(), boldText, boldStyle);
doc.insertString(doc.getLength(), plainText, defaultStyle);
}
catch (BadLocationException ble)
{
System.err.println("Couldn't insert text into text pane.");
}
final JComboBox zoomCombo=new JComboBox(new String[] {"75%",
"100%", "150%", "175%", "200%"});
final JPanel panel = new JPanel()
{
protected void paintComponent(Graphics g)
{
super.paintChildren(g);
scaledTextPane.paint(g);
}
};
zoomCombo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String s = (String) zoomCombo.getSelectedItem();
s = s.substring(0, s.length() - 1);
double scale = new Double(s).doubleValue() / 100;
scaledTextPane.setScale(scale);
panel.invalidate();
panel.repaint();
}
});
zoomCombo.setSelectedItem("100%");
// Add content to the window.
scaledTextPane.setBounds(0, 0, 450, 300);
panel.setOpaque(true);
panel.setBackground(Color.WHITE);
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.getContentPane().add(zoomCombo, BorderLayout.NORTH);
frame.setSize(900, 300);
//Display the window.
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}