Is there a way to improve font rendering in Swing JTextFields? Here's what I'm getting right now:
As you can see, it looks pretty jagged. Is there a way I can improve that? I'm using the GTKLookAndFeel, just in case anyone needs to know.
(I looked at this question, but it didn't help much.)
SSCCE:
public class foo extends JFrame{
foo(){
add(new JTextField);
setVisible(true);
}
}
I'm on Linux, so that might have something to do with it. I'm using Infinality in linux for better fonts.
Using the sscce below, I see the following appearance with the GTK+ L&F.
Addendum: As a workaround, you might try setting a UI delegate property, for example,
JTextField tf = new JTextField();
UIManager.put("TextField.font", tf.getFont().deriveFont(Font.BOLD));
import component.Laf;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
/** #see http://stackoverflow.com/a/18969361/230513 */
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(0, 1));
// http://stackoverflow.com/a/11949899/230513
f.add(Laf.createToolBar(f));
f.add(new JTextField("bla#foo.com"));
f.add(new JPasswordField("*****"));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}
To get a smother text, you should enable anti-aliasing:
$ java -jar lib/application.jar -Dswing.aatext=true
Using this code you can change the font and font color in a JTextArea.
We have created a JTextArea called txt. With a few simple lines of code you can change its font, color & size settings:
Font font = new Font("Verdana", Font.BOLD, 12);
txt.setFont(font);
txt.setForeground(Color.BLUE);
There are several font settings in the Font class including PLAIN, BOLD, ITALIC and 13 different colors in the Color class (listed below).
BLACK
BLUE
CYAN
DARK_GRAY
GRAY GREEN
LIGHT_GRAY
MAGENTA
ORANGE
PINK
RED
WHITE
YELLOW
Related
For example if you set the color of a textfield as Color.RED, is there a method to actually return that color?
I found a method in the Oracle logs called getCaretColor() but it doesn't seem to return the right thing...
JTextField inherits getBackground() and getForeground() from Component. If I understand your question, that should get you the values.
The below code will return a JTextField with a black background and red text.
import javax.swing.JTextField;
import javax.swing.JFrame;
import java.awt.Color;
import java.awt.FlowLayout;
public class test
{
public static void main(String[] args)
{
JTextField textField = new JTextField(20);
JFrame frame = new JFrame("Java"); // Just the window title, name doesn't matter
frame.setLayout(new FlowLayout());
Color color = new Color(255,0,0); // Set the text color
textField.setBackground(Color.BLACK); // Set the black background
textField.setForeground(color);
frame.add(textField);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,200);
frame.setVisible(true);
}
}
I have a frame with a very standard JLabel.
No matter how big the font, or how small/big the JLabel, the text is always sharp.
I'd like for it to be antialiased.
Looking up on so, I found a few questions but no solutions.
Using this answer:
Anti-aliased JLabel
I understood that it's useless to set the hints.
I have also tried to no avail:
String property = "swing.aatext";
if (null == System.getProperty(property))
System.setProperty(property, "true");
And here's the screenshot of the text, font Comfortaa, size 90:
The same problem comes with all fonts and sizes I have tried so far.
Am I missing out on some way to enable the antialiasing?
I have not changed the JLabel in any way, added custom graphics, code, or anything at all. It's a black JPanel on a JFrame, with a JLabel in the middle.
FAQ:
Java 8
Run from Eclipse 4.1
Window 10
Both on 4k and FHD Screen
Nimbus
Both with decorated and undecorated frames
Both with black and transparent background
Font installed on windows, not loaded as resource
Same behaviour with any font
I have used swing in the past, same machine, same version of everything, no issues that I can remember
Am I doing something wrong? Any ideas?
MCVE: ---> The code is mine, I just changed the font because you might not have Comfortaa installed.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class TestFrame extends JFrame {
private JPanel panel;
private JLabel mcveLabel;
private JLabel mcveLabel2;
public TestFrame() {
setSize(374, 153);
setLocationRelativeTo(null);
setDefaultCloseOperation(3);
panel = new JPanel();
panel.setBackground(Color.BLACK);
getContentPane().add(panel, BorderLayout.CENTER);
panel.setLayout(new BorderLayout(0, 0));
mcveLabel = new JLabel("Antialias");
mcveLabel.setFont(new Font("Arial", Font.BOLD, 60));
mcveLabel.setHorizontalAlignment(SwingConstants.CENTER);
mcveLabel.setForeground(Color.WHITE);
panel.add(mcveLabel, BorderLayout.CENTER);
mcveLabel2 = new JLabel("NEEDED");
mcveLabel2.setFont(new Font("SansSerif", Font.PLAIN, 30));
mcveLabel2.setForeground(Color.GREEN);
mcveLabel2.setHorizontalAlignment(SwingConstants.CENTER);
panel.add(mcveLabel2, BorderLayout.SOUTH);
setVisible(true);
}
public static void main(String[] args) {
new TestFrame();
}
}
EDIT:
Added screen with the same font as the MCVE.
When I add Swing component (like a JButton) to a JPanel, it renders with it's 'preferred size'.
However, the preferred size is actually larger than the painted button. There appears to be an invisible border around it.
Here's a simple frame with my test panel:
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TestPanel pnl = new TestPanel();
frame.getContentPane().add(pnl);
frame.pack();
frame.setVisible(true);
Here's my test panel ...
public class TestPanel extends JPanel {
JButton btn1 = new JButton("Test1");
JButton btn2 = new JButton("Test2");
public TestPanel() {
this.add(btn1);
this.add(btn2);
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.RED);
Dimension dim = btn1.getPreferredSize();
g.drawRect(btn1.getX(), btn1.getY(), (int)(dim.getWidth()), (int)(dim.getHeight()));
}
}
Notice I painted btn1's "PreferredSize" in RED to demonstrate that the preferredSize is actually larger than the button itself.
My question is, how can I determine the width and height of the painted button, not the JButton's preferredSize?
Any help is greatly appreciated, thanks!
UPDATE
Because I actually need this to work for all Swing components, here's a screen shot with the more components.
Unfortunately, I need to figure this out, determining the "real" size of the visible widget is crucial to my application.
I don't think this is particular or practically achievable.
The problem is, the button is using the "unpainted" area to paint other elements, like the focus highlight.
You could try look at the AbstractButton#set/getMargin
If nothing better comes along, note that the authors "recommend that you put the component in a JPanel and set the border on the JPanel."
Addendum: Based on your comments below, it's clear that your question is not about rendering borders but about establishing a component's boundary. What you perceive as unused space is actually reserved by the UI delegate for any number of uses, e.g. selection highlighting or esthetic coherence. You can get an idea of how this varies by selecting different Look & Feel themes in the examples here and here.
Using getbounds():
Using setBorder():
import component.Laf;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* #see https://stackoverflow.com/a/15490187/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new FlowLayout());
// https://stackoverflow.com/a/11949899/230513
f.add(Laf.createToolBar(f));
f.add(decorate(new JButton("Test")));
f.add(decorate(new JTextField("Test")));
f.add(decorate(new JTextArea(3, 8)));
f.add(decorate(new JCheckBox("Test")));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JPanel decorate(final JComponent c) {
JPanel p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle r = c.getBounds();
g.setColor(Color.red);
// NB pen hangs down and to the right
g.drawRect(r.x - 1, r.y - 1, r.width + 1, r.height + 1);
}
};
p.add(c);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}
I'm trying to create two JLabels - one for icon (UIManager.getIcon("OptionPane.informationIcon") - one of Java's standart icons) and one for text. Sure, I know there is a JLabel's constructor which can make one label from icon and text, but I need exactly two labels, because one of them should be highlighted when mouse moves through it, I omit this part of code.
The problem is I can't find out how to change Icon size. At least I want to set manually height of icon, but it would be better if its height calculated automatically to fit text with specified font. I spent several hours trying to find information in the Web, but couldn't find anything relative.
I tried to implement Icon class and override getIconHeight() and getIconWidth() methods, but I don't know what to do next with my Icon object, because Icon is an interface so it has no constructors.
Here is my simplified code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import net.miginfocom.swing.MigLayout;
public class AppView
{
private final JFrame main_frame;
public AppView()
{
main_frame = new JFrame();
main_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main_frame.setTitle("Example");
JPanel main_panel = new JPanel() {
private static final long serialVersionUID = 1L;
public Dimension getPreferredSize()
{
return new Dimension(200, 200);
}
};
main_frame.getContentPane().add(main_panel, BorderLayout.CENTER);
main_panel.setLayout(new MigLayout());
JLabel label_icon = new JLabel(UIManager.getIcon("OptionPane.informationIcon"));
JLabel label_text = new JLabel("Text goes here");
label_text.setFont(new Font("sans-serif", Font.PLAIN, 12));
main_panel.add(label_icon);
main_panel.add(label_text);
main_frame.pack();
main_frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new AppView();
}
});
}
}
Here is the result, as you can see, Icon is higher than text:
Thanks in advance!
I would like to understand why a JLabel, rendering HTML, shifts the vertical position of it's output text, whereas a JLabel which renders non-HTML, does not.
Java version used: 1.6.0_37
Swing Look and Feel used: Windows ("com.sun.java.swing.plaf.windows.WindowsLookAndFeel")
OS: Windows 7 64 Bit
I did not put a SSCCE together since the code is really trivial. But if it helps please say so.
I rather give an examples using an images displaying the behavior:
I put a JPanel as the container around the JLabel to visualize the label's bounds. After setting the font and text for the JLabel, the
jLabel.getPreferredSize()
method returns the bounds of the rendered plain text or HTML (and this is the exact size I set for the surrounding JPanel). You can clearly see, that, if rendering HTML, the whole text is shifted a small amount down.
I would like to know why this happens and what I can do to correct the placement.
One workaround would be to translate the Graphics2D on which to render the text, to compensate the vertical shift, like this:
g2d.translate( 0, -20 );
But I don't know the correct y value in relation to the font metrics (e.g. font size). Anyway, this workaround also feels "wrong".
I really appreciate your answers, thanks a lot!
It seems that if we set the Font (family,size etc) for the HTML JLabel using setFont(..) the font is not rendered to the correct metrics of JLabel.
Here is an example I made to demonstrate (Both JLabels shown are using HTML):
A simple work around is to the the font size, family etc in HTML too.
As we can see the cyan HTML JLabel used setFont(..) (and was incorrectly rendered) while the green HTML JLabel used HTML to set the font and was rendered correctly:
JLabel labelHtml2 = new JLabel("<html><font size=10 family='Calibri'>" + text + "</font></html>");
Test.java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static Font font = new Font("Calibri", Font.PLAIN, 38);
public Test() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new Test();
}
});
}
private void initComponents() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String text = "Hello world";
//this label will not render correctly due to setting font via setFont(..)
JLabel labelHtml1 = new JLabel("<html>" + text + "</html>");
labelHtml1.setBackground(Color.CYAN);
labelHtml1.setOpaque(true);//so background will be painted
labelHtml1.setFont(font);
//this label will render correcty font is set via html
JLabel labelHtml2 = new JLabel("<html><font size=10 family='Calibri'>" + text + "</font></html>");
labelHtml2.setBackground(Color.GREEN);
labelHtml2.setOpaque(true);
//labelHtml2.setFont(font);
frame.add(labelHtml1, BorderLayout.NORTH);
frame.add(labelHtml2, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}