Часть 2. Как получить согласованный рендеринг при масштабировании JTextPane?
Ранее я отправил еще одну версию этого вопроса и пример программы: как получить согласованный рендеринг при масштабировании JTextPane?
Повторим проблему: я хотел бы позволить пользователям увеличивать или уменьшать масштаб нередактируемой JTextPane. Запуск примера программы, представленной в предыдущем вопросе, который просто масштабировал объект Graphics, приводил к непоследовательному интервалу между сериями полужирного и не полужирного текста.
Приведенный ниже пример программы пытается решить проблему, рисуя текстовую панель в BufferedImage со значением 100%, а затем масштабируя изображение. Это решает проблему непоследовательного пробела, но получающемуся тексту не хватает четкости. Есть ли какая-то комбинация подсказок по рендерингу (или другое изменение), которые приведут к хорошему четкому тексту?
Заранее благодарим за любые предложения или комментарии о целесообразности такого подхода.
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();
}
});
}
}
3 ответа
Может быть это может помочь http://java-sl.com/Scale_In_JEditorPane.html.
К сожалению, масштабирование до большего размера с фиксированным разрешением всегда приведет к некоторому артефакту сглаживания. Вот альтернативный подход, который масштабирует шрифт, используемый JTextPane
,
Для контроля низкого уровня, рассмотрим TextLayout
, который включает в себя FontRenderContext
который может управлять настройками сглаживания и дробных метрик, как показано в этом примере.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
/** @see https://stackru.com/questions/4566211 */
public class ScaledJTextPane {
private static final int SIZE = 14;
private static final String FONT = "Dialog";
private static void createAndShowGUI() {
JFrame frame = new JFrame("ScaledJTextPane using BufferedImage");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTextPane tp = new JTextPane();
tp.setFont(new Font(FONT, Font.PLAIN, SIZE));
tp.setPreferredSize(new Dimension(400, 300));
StyledDocument doc = tp.getStyledDocument();
Style defaultStyle = StyleContext.getDefaultStyleContext()
.getStyle(StyleContext.DEFAULT_STYLE);
Style boldStyle = doc.addStyle("bold", defaultStyle);
StyleConstants.setBold(boldStyle, true);
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) {
ble.printStackTrace(System.err);
}
final JPanel panel = new JPanel();
panel.add(tp);
final JComboBox zoomCombo = new JComboBox(new String[]{
"75%", "100%", "150%", "175%", "200%"});
zoomCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String s = (String) zoomCombo.getSelectedItem();
s = s.substring(0, s.length() - 1);
double scale = new Double(s).doubleValue() / 100;
int size = (int) (SIZE * scale);
tp.setFont(new Font(FONT, Font.PLAIN, size));
}
});
zoomCombo.setSelectedItem("100%");
JPanel optionsPanel = new JPanel();
optionsPanel.add(zoomCombo);
panel.setBackground(Color.WHITE);
frame.add(panel, BorderLayout.CENTER);
frame.add(optionsPanel, BorderLayout.NORTH);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}
}
Я хотел бы позволить пользователям увеличивать или уменьшать масштаб нередактируемого JTextPane.
Поскольку текстовая панель недоступна для редактирования, возможно, вы можете создать изображение текстовой панели с помощью класса Screen Image. Затем вы можете нарисовать изображение на панели, используя соответствующий коэффициент масштабирования.