How do I query the current anti-aliasing settings in Swing L&F?
TL; DR: What is the simplest and most correct way to set up an instance Graphics
to use default options for rendering strings? Or how to render the string using the default anti-aliasing settings to make it look like a JLabel? A more detailed description of the problem follows ...
I am trying to create my own JComponent subclass. In fact, it is kind of TableCellRenderer
capable of displaying rich text. The extension is JEditorPane
too heavy and slow (tried it really) and the JLabel cannot display rich text, so I decided to implement my own, lightweight and fast. Now it (obviously) needs to draw text in paintComponent()
, and I would like that text to look in all other text components like the JLabel.
However, when I do this, it seems to be using different anti-aliasing options from the rest of the application, so it looks pretty ugly. I understand that I can just use Graphics
to Graphics2D
to use the appropriate API, but the question is, which settings should I use? That is, what to pass in setRenderingHint()
as the second parameter?
I can get it to look great on my system by playing around with different AA values, but doesn't it suddenly look terrible on some other system with different default settings?
I tried looking at the JLabel and LabelUI sources, but they seem to use a lot of black magic, like asking for some hidden properties using JComponent.getClientProperty()
and SwingUtilities2
, which aren't even part of official Swing. Of course, I could try to emulate this, but it is a) too tedious and b) obliged to use some not too documented functions for which a guaranteed stable API is not guaranteed.
Or maybe there is a way to reuse some existing UI delegate? Basically, I just want my text to look exactly as shown JLabel
. I could even use an instance JLabel
or a subclass of it as a kind of rubber stamp for drawing text, but it looks a little ugly and I'm not sure about the performance. I realize I JTable
actually does exactly that, but using it JLabel
to draw a whole cell is one thing, using it to draw parts of a cell just doesn't seem right. For example, it may happen that some L&F decorate these in a JLabel
special way that looks ugly.
Ideally, I would like to have something like this (imaginary code):
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
JLabel.getDefaultUI().getRenderingHint());
Or better yet (customize everything, not just AA):
JLabel.getDefaultUI().setupGraphics(g); // this sets up g just like for drawing a JLabel
But there seems to be no such simple thing as far as I can see.
source to share
Sometimes we cannot see the forest for the trees ...
and JLabel cannot display rich text
If your need is rich text in a table renderer, then (maybe) that is the question!
JLabel
actually makes rich text via HTML [Doc] , and even you can use JXLabel
from SwingX for further functionality (turn! line break!).
Given what DefaultTableRenderer
it actually is JLabel
, perhaps you can extend it and make a simple modification:
public class AATableRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
DefaultTableCellRenderer c = (DefaultTableCellRenderer) super
.getTableCellRendererComponent(table, value, isSelected,
hasFocus, row, column);
String text = c.getText();
// Do some style transformations maybe...
c.setText("<html>" + text + "</html>");
return c;
}
}
or you can change yours JTable
in the methodprepareRenderer()
public class AATable extends JTable {
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
if (c instanceof JLabel) {
JLabel l = (JLabel) c;
String text = l.getText();
// Do some style transformations maybe...
l.setText("<html>" + text + "</html>");
}
return c;
}
}
But maybe you can't use the HTML thing ... In this case, if you need to stick with your custom component, you might have to do it for each look and feel, since each is handled differently. For example, note that sometimes these properties are set on the system, and most Swing L&Fs respect them (Windows 7 configures this in My Computer> Properties> Advanced System Settings> Performance> Smooth Fonts (check in the list)).
I don't think you can reuse LabelUI
(basic) because maybe all this magic tampering with how you want to paint when you just want anti-aliasing ... Not sure if it's not impossible, but I can't tell ...
THIS IS AN ANSWER TO THE ORIGINAL QUESTION
Short answer
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Long answer
The reason your component uses different settings is because Swing uses a delegation architecture for painting: the L&F contains delegate prototypes for each component type, when the component is instantiated, which is instantiated and injected by the component, and painting is done there (and behavior). When you just inject a method paintComponent(Graphics)
, you skip this whole architecture and execute the picture directly, and you miss the parameters that can be performed in delegates *. [Doc]
The most correct ("correct" is not always the best solution!) To make your custom component is to create your user interface delegate, register it, and execute the appropriate procedures. [Doc]
It's a long tedious job anyway, so keep it practical: If your application just uses one look and feel, if you're not going to reuse that component, if your time constraints don't allow you to spend a lot of time developing one component ... if you just need to set your antialiasing component, use this code snippet:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JComponent;
public class AAComponent extends JComponent {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // Maybe you want to skip this, up to your needs...
Graphics2D g2 = null;
try {
g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Your painting procedures
} finally {
if (g2 != null) {
g2.dispose();
}
}
}
}
The creation may g2
look a little strange, but it is quite optimal, it is a way not to propagate changes in yours Graphics
, and the computational cost is less than the minimum. Also, if you want to extend the anti-aliasing to the picture of the superclass (does JComponent
nothing in this case ) just call the super-implementation after setting the render hint.
* This is a bit inaccurate because the configuration does not necessarily rely on L&F, but in conjunction with delegates, but I think this is a good way to illustrate what is going on.
source to share
For general purposes, the following attributes should set anti-aliasing in your application.
System.out.println(System.getProperty("awt.useSystemAAFontSettings"));
System.setProperty("awt.useSystemAAFontSettings","on");
System.out.println(System.getProperty("awt.useSystemAAFontSettings"));
System.setProperty("swing.aatext", "true");
// etc.
Alternatively, when overridden paintComponent()
in the graphical context, your JLabel
or JPanel
:
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
try {
// you can query the RenderingHints here
g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
} finally {
if(g2 != null) {
g2.dispose();
}
}
}
source to share