第 2 部分 - 缩放 JTextPane 时如何获得一致的渲染?
我之前提交了这个问题的另一个版本和示例程序: 缩放 JTextPane 时如何获得一致的渲染?
概括一下问题:我希望允许用户放大或缩小不可编辑的 JTextPane。运行前面问题中提交的示例程序(该程序只是缩放 Graphics 对象),导致粗体文本和非粗体文本之间的间距不一致。
下面的示例程序尝试通过将文本窗格绘制到 100% 的 BufferedImage 然后缩放图像来解决该问题。这解决了间距不一致的问题,但生成的文本缺乏清晰度。是否有某种渲染提示的组合(或其他一些更改)可以产生清晰的文本?
预先感谢您对此方法的可行性提出任何建议或意见。
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)
{
// Draw this text pane to a BufferedImage at 100%
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;
// Experiment with different rendering hints
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);
// Scale the BufferedImage
g2.scale(scale_, scale_);
g2.drawImage(raster_, 0, 0, null);
}
public void setScale(double scale)
{
scale_ = scale;
raster_ = null;
}
private static void createAndShowGUI()
{
// Create and set up the window.
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);
// 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(optionsPanel, 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();
}
});
}
}
I submitted another version of this question and a sample program before: How do I get consistent rendering when scaling a JTextPane?
Recapitulating the problem: I would like to allow users to zoom into or out of a non-editable JTextPane. Running the example program submitted in the earlier question, which simply scaled the Graphics object, resulted in inconsistent spacing between runs of bold text and non-bold text.
The sample program below attempts to solve the problem by drawing the text pane to a BufferedImage at 100% and then scaling the image. This solves the problem of inconsistent spacing but the resulting text lacks crispness. Is there some combination of rendering hints (or some other change) that will result in nice crisp text?
Thanks in advance for any suggestions or comments on 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)
{
// Draw this text pane to a BufferedImage at 100%
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;
// Experiment with different rendering hints
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);
// Scale the BufferedImage
g2.scale(scale_, scale_);
g2.drawImage(raster_, 0, 0, null);
}
public void setScale(double scale)
{
scale_ = scale;
raster_ = null;
}
private static void createAndShowGUI()
{
// Create and set up the window.
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);
// 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(optionsPanel, 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();
}
});
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
可能这个http://java-sl.com/Scale_In_JEditorPane.html可以帮助。
may be this http://java-sl.com/Scale_In_JEditorPane.html could help.
遗憾的是,从固定分辨率缩放到更大的尺寸总是会导致一些锯齿现象。这是缩放
JTextPane
使用的字体的替代方法。对于低级控制,请考虑
TextLayout
,其中包括FontRenderContext
可以管理抗锯齿和分数指标设置,如本示例所示。Sadly, scaling to a larger size from a fixed resolution will always result in some aliasing artifact. Here's an alternative approach that scales the font used by
JTextPane
.For low-level control, consider
TextLayout
, which includes aFontRenderContext
that can manage the anti-aliasing and fractional metrics settings, as seen in this example.由于文本窗格不可编辑,也许您可以使用 屏幕图像类。然后,您可以使用适当的缩放系数在面板上绘制图像。
Since the text pane is non-editable, maybe you can create an image of the text pane by using the Screen Image class. Then you can draw the image on a panel using the approriate scaling factor.