I presented another version of this question and an example program before: How to get consistent rendering when scaling a JTextPane?
Recapulation of the problem: I would like to allow users to increase or decrease the inaccessible JTextPane. Running the sample program presented in the previous question, which simply scaled the Graphics object, resulted in an inconsistent distance between runs of bold text and bold.
The sample program below tries to solve the problem by drawing a text panel to BufferedImage 100% and then scaling the image. This solves the problem of inconsistent spacing, but the resulting text lacks clarity. Is there any combination of rendering hints (or some other changes) that will lead to nice clear text?
Thanks in advance for any suggestions or comments regarding the feasibility of this approach.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.Box;
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_;
BufferedImage raster_;
public ScaledJTextPane()
{
scale_ = 1.0;
raster_ = null;
}
public void draw(Graphics g)
{
if (raster_ == null)
{
raster_ = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = raster_.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
paint(g2);
}
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2.scale(scale_, scale_);
g2.drawImage(raster_, 0, 0, null);
}
public void setScale(double scale)
{
scale_ = scale;
raster_ = null;
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("ScaledJTextPane using BufferedImage");
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.paintComponent(g);
scaledTextPane.draw(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%");
JPanel optionsPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.anchor = GridBagConstraints.WEST;
optionsPanel.add(zoomCombo, c);
c.gridx++;
c.weightx = 1;
c.fill = GridBagConstraints.HORIZONTAL;
optionsPanel.add(Box.createHorizontalGlue(), c);
scaledTextPane.setBounds(0, 0, 450, 300);
panel.setOpaque(true);
panel.setBackground(Color.WHITE);
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.getContentPane().add(optionsPanel, BorderLayout.NORTH);
frame.setSize(900, 300);
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}