I am using a Swing application which on my computer shows text with a ridiculously small font size.
Is there a way to change the font size, or maybe some kind of DPI setting, from the command line or with some kind of configuration file (for example, something like a swing.properties file)?
I don't have access to the source code.
EDIT:
Small font sizes should not be a problem any more since Java 9. Swing has started to scale its GUI components depending on the screen resolution.
There is no command line switch to change the font size for Swing. What you would have to do is to invoke the following method:
public static void adjustFontSize(int adjustment) {
UIDefaults defaults = UIManager.getDefaults();
List<Object> newDefaults = new ArrayList<Object>();
Map<Object, Font> newFonts = new HashMap<Object, Font>();
Enumeration<Object> en = defaults.keys();
while (en.hasMoreElements()) {
Object key = en.nextElement();
Object value = defaults.get(key);
if (value instanceof Font) {
Font oldFont = (Font)value;
Font newFont = newFonts.get(oldFont);
if (newFont == null) {
newFont = new Font(oldFont.getName(), oldFont.getStyle(), oldFont.getSize() + adjustment);
newFonts.put(oldFont, newFont);
}
newDefaults.add(key);
newDefaults.add(newFont);
}
}
defaults.putDefaults(newDefaults.toArray());
}
where adjustment is the number of points that should be added to each font size.
If you don't have access to the source code, you can always write your own wrapper main class where you call
UIManager.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
if (event.getPropertyName().equals("lookAndFeel")) {
adjustFontSize(5);
}
}
});
before invoking the main method of the actual application.
However, if the font size is very small, it has likely been set explicitly, so changing the defaults might not help.
I don't think there are such options since all the component Font sizes are defined in Look and Feel (L&F) default values. Some of L&Fs allow quick font changes, some of them doesn't. In most cases you should be able change the font size by changing the UI defaults:
UIManager.put ( "Button.font", new SwingLazyValue ( "javax.swing.plaf.FontUIResource", null, new Object[]{ fontName, fontStyle, fontSize } ) );
UIManager.put ( "Label.font", new SwingLazyValue ( "javax.swing.plaf.FontUIResource", null, new Object[]{ fontName, fontStyle, fontSize } ) );
UIManager.put ( "TextField.font", new SwingLazyValue ( "javax.swing.plaf.FontUIResource", null, new Object[]{ fontName, fontStyle, fontSize } ) );
e.t.c for each component.
And i am not sure if those values could be passed to application without changing its code or atleast having some font-size change support inside the application.
I have not tested it, but you might try launching the app. using Java Web Start. It allows properties like swing.useSystemFontSettings & swing.metalTheme to be specified even for sand-boxed apps. Doing either might 'override' small fonts set in the code.
See the JNLP file syntax for more details.
Related
I'm noticing differences in font spacing using OpenJDK compared to OracleJDK. I've narrowed this down to the fonts. They are rendered by OpenJDK ever so slightly wider... Careful visual inspection of the screenshot above shows the character widths are identical, the only difference is the spacing. I also confirmed this with programmatic check of font metrics for all characters A-Za-z0-9.
e.g. the String "Dialog - plain" at 12pt is
125px wide in OpenJDK - my build of 8u131-b11
125px wide in OpenJDK - stock RPM from redhat disk - 1.8u45-b13
120px wide in OracleJDK - 8u131-b11 release from Oracle website
I've searched extensively for information on this and found various options including -Dawt.useSystemAAFontSettings, -Dswing.useSystemFontSettings, -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel from Java_Runtime_Environment_fonts. I've tried altering all of these but the results remain the same.
Further investigation has found sun.font.FontScaler, this uses different underlying fontscaler. This appears partially configurable in sun.font.FontUtilities which checks the system property for -Dsun.java2d.font.scaler=t2k, however setting this makes no difference.
My question: can FreetypeFontScaler be configured to behave in a similar or closer way to T2KFontScaler?
if (FontUtilities.isOpenJDK) {
scalerClass = Class.forName("sun.font.FreetypeFontScaler");
} else {
scalerClass = Class.forName("sun.font.T2KFontScaler");
}
This is the test program I've been using
public class FontTester {
public static void main(String[] args) throws Exception {
System.out.println(String.format("java.home=%s", System.getProperty("java.home")));
String family = Font.DIALOG;
int style = Font.PLAIN;
describeFont(new Font(family, style, 12));
JFrame frame = new JFrame();
frame.setSize(800, 600);
frame.add(new DemoPanel());
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
private static class DemoPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
String family = Font.DIALOG;
int style = Font.PLAIN;
Font font = new Font(family, style, 20);
g.setFont(font);
String str = family + " - " + name(font) + " ";
Rectangle2D bounds = g.getFontMetrics().getStringBounds(str, g);
str += String.format("%f x %f", bounds.getWidth(), bounds.getHeight());
g.drawString(str, 10, 50);
}
private String name(Font font) {
List<String> attrs = new ArrayList<>();
if (font.isBold()) {
attrs.add("bold");
}
if (font.isItalic()) {
attrs.add("italic");
}
if (font.isPlain()) {
attrs.add("plain");
}
return String.join(",", attrs);
}
}
private static void describeFont(Font font) throws Exception {
Method method = Font.class.getDeclaredMethod("getFont2D");
method.setAccessible(true);
Font2D font2d = (Font2D) method.invoke(font);
System.out.print(String.format("%s: ", font));
describeFont2D(font2d);
}
private static void describeFont2D(Font2D font) {
if (font instanceof CompositeFont) {
CompositeFont cf = (CompositeFont) font;
for (int i = 0; i < cf.getNumSlots(); i++) {
PhysicalFont pf = cf.getSlotFont(i);
describeFont2D(pf);
break;
}
} else {
System.out.print(String.format("-> %s \n", font));
}
}
}
Yet more investigation has traced this though to sun.font.FontStrike.getGlyphMetrics(int) returning different results. For a glyph-id 39 ("D") the advance X value is returned as 14.0px using Oracle JDK (via T2KFontScaler) but 15.0px using OpenJDK (via FreetypeFontScaler)
To figure which is "correct" I used the fontbox Java parser to extract the advance X value for Glyph-ID 39 from the HMTX table within the TTF file LiberationSans-Regular.ttf. The value is 1479 font design units - which maps to 14.44px at 20pt font size.
There is no difference for the next character "i" - glyph-id 76. This is 4.44 according to fontbox, and returned as 4 by both T2KScaler and FreetypeScaler
I've further narrowed this down to the rounding / calculation used when standard "non-fractional" metrics are used. If fractional metrics are enabled then both Oracle and Open JDKs behave identically, although the widths are still slighly smaller than the Oracle non-fractional case.
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
Update - Jan 2020
* In Java 11 there is new option which may be related - see https://bugs.openjdk.java.net/browse/JDK-8217731
FREETYPE_PROPERTIES=truetype:interpreter-version=35
Further investigation has found sun.font.FontScaler, this uses different underlying fontscaler. This appears partially configurable in sun.font.FontUtilities which checks the system property for -Dsun.java2d.font.scaler=t2k, however setting this makes no difference.
You're correct in that the underlying font scaler is different between Oracle and OpenJDK - unfortunately however, this is hard coded and not configurable.
The relevant code is in FontScaler:97:
if (FontUtilities.isOpenJDK) {
scalerClass = Class.forName("sun.font.FreetypeFontScaler");
} else {
scalerClass = Class.forName("sun.font.T2KFontScaler");
}
And the isOpenJDK flag? It's set by FontUtilities:125:
File lucidaFile = new File(jreFontDirName + File.separator + LUCIDA_FILE_NAME);
isOpenJDK = !lucidaFile.exists();
And that constant:
static final String LUCIDA_FILE_NAME = "LucidaSansRegular.ttf";
Unless I've missed something in those source files, there's no other configuration flag or any other condition that will change that scaler class being used.
So the only vaguely sensible way of doing this (I'm excluding horrible classloader / reflection hacks here) is to add that Lucida file in place. Unfortunately though in most scenarios I can think of (assuming you're not distributing the JRE along with the package) this isn't really going to be a viable solution either.
I added a new font for my project in java. However upon rendering it the text size is always at 1 it appears. The text basically appears as just a few little lines. I tried this with multiple fonts and they all did it. This is my code.
public static void intializeFonts(){
try{
File font = new File("C:/The Woods/Fonts/script.ttf");
Font scriptFontU = Font.createFont(Font.TRUETYPE_FONT, font);
Font scriptFont = scriptFontU.deriveFont(20);
script = new TrueTypeFont(scriptFont, false);
} catch(Exception e){
System.out.println("Error Loading Font");
}
}
This is also what I am using to render it if this helps.
g.setFont(Fonts.script);
g.drawString("Weight: "+ItemContainer.getWeight()+"lbs", 30, 600);
Any help would be great. Thank You.
When you call scriptFontU.deriveFont(20), you are calling Font.deriveFont(int). In this function, the first argument is an integer representing a style. Instead, you want to call Font.deriveFont(float), which takes a size and leaves the style unchanged. You can do this by calling scriptFontU.deriveFont(20.0), or equivalent; or call Font.deriveFont(int, float) as scriptFontU.deriveFont(Font.PLAIN, 20.0) to make it unambiguous.
I'm writing a Java app that needs to run on a device with a very high screen resolution. The only UI component that I need to display is a JFileChooser.
Since the screen resolution so high, the FileChooser appears too small. Is there a simple command I can use to make it bigger? Ideally, I'd like to keep the proportions of the components the same, so that the icons grow just as much as the text.
Also, it's important that any changes modify only my application. A global approach to changing the size of the graphics, like using a lower resolution, or changing a system-wide font size, isn't an option for me.
Any ideas?
This class works fine, both resizing JFileChooser window and fonts.
public class JFileChooserArqs {
private Font font = new Font("monospaced",Font.BOLD,16);
private String fileName;
public JFileChooserArqs(String title)
{
fileName = null;
JFileChooser fc = new JFileChooser(".");
fc.setPreferredSize(new Dimension(800,600));
fc.setDialogTitle(title);
setFileChooserFont(fc.getComponents());
int returnVal = fc.showOpenDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
fileName = fc.getSelectedFile().getAbsolutePath();
}
}
private void setFileChooserFont(Component[] comp)
{
for(int x = 0; x < comp.length; x++)
{
if(comp[x] instanceof Container) setFileChooserFont(((Container)comp[x]).getComponents());
try{comp[x].setFont(font);}
catch(Exception e){}//do nothing
}
}
public String obtemNomeArquivo() {
return fileName;
}
}
I know the answer. Just use chooser.setPreferredSize(new Dimension(int width,int height)); method where chooser is your JFileChooser .
Example:
public class MyFrame extends JFrame(){
JFileChooser chooser = new JFileChooser();
chooser.setPreferredSize(new Dimension(800,600));
//Here show your dialog and do the rest
}
You need to choose suitable layouts to design the user interface. Have a look at CodeRanch thread.
I was going to suggest adding the JFileChooser to a container having a suitable layout, as #AVD suggests. For example, ImageDisplay adds the chooser to BorderLayout.WEST where it's free to grow vertically while adopting the UI delegate's preferred width. Before you abandon that approach, verify that you are not inadvertently defeating that design feature.
If you really need control over the display characteristics of the chooser's subcomponents, you may want to look at these variations of FileBrowser.
i want to make my JCheckboxes in a JTable bigger (for Touchscreen), but it doesn't change the size.
I tried it with
setPrefferedSize
setSize
What should I do?..
I assume you mean you want a bigger check box. If so then you need to create images to represent the unselected and selected icons of the check box. Then you can create a renderer and editor using these icons. Finally you would need to increase the height of each row in the table. The code might look something like:
Icon normal = new ImageIcon(...);
Icon selected = new ImageIcon(...);
JTable table = new JTable(...);
table.setRowHeight(...);
TableCellRenderer renderer = table.getDefaultRenderer(Boolean.class);
JCheckBox checkBoxRenderer = (JCheckBox)renderer;
checkBoxRenderer.setIcon( normal );
checkBoxRenderer.setSelectedIcon( selected );
DefaultCellEditor editor = (DefaultCellEditor)table.getDefaultEditor(Boolean.class);
JCheckBox checkBoxEditor = (JCheckBox)editor.getComponent();
checkBoxEditor.setIcon( normal );
checkBoxEditor.setSelectedIcon( selected );
IMPORTANT NOTE: This was only tested with the default 'Metal' look and feel. I do not guarantee that this will work for any other look and feel. Also I am not entirely sure how it works because it is admittedly a bit of a hack.
I was able to solve this in a slightly different way.
I wanted to use the existing images and just apply a scale to it. I am already scaling the font of my application using the UI defaults and so I have a rather large font. I wondered if I could leverage that and scale the check boxes accordingly.
After scouring the internet and trying a bunch of things I came up with this method:
public static void scaleCheckBoxIcon(JCheckBox checkbox){
boolean previousState = checkbox.isSelected();
checkbox.setSelected(false);
FontMetrics boxFontMetrics = checkbox.getFontMetrics(checkbox.getFont());
Icon boxIcon = UIManager.getIcon("CheckBox.icon");
BufferedImage boxImage = new BufferedImage(
boxIcon.getIconWidth(), boxIcon.getIconHeight(), BufferedImage.TYPE_INT_ARGB
);
Graphics graphics = boxImage.createGraphics();
try{
boxIcon.paintIcon(checkbox, graphics, 0, 0);
}finally{
graphics.dispose();
}
ImageIcon newBoxImage = new ImageIcon(boxImage);
Image finalBoxImage = newBoxImage.getImage().getScaledInstance(
boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
);
checkbox.setIcon(new ImageIcon(finalBoxImage));
checkbox.setSelected(true);
Icon checkedBoxIcon = UIManager.getIcon("CheckBox.icon");
BufferedImage checkedBoxImage = new BufferedImage(
checkedBoxIcon.getIconWidth(), checkedBoxIcon.getIconHeight(), BufferedImage.TYPE_INT_ARGB
);
Graphics checkedGraphics = checkedBoxImage.createGraphics();
try{
checkedBoxIcon.paintIcon(checkbox, checkedGraphics, 0, 0);
}finally{
checkedGraphics.dispose();
}
ImageIcon newCheckedBoxImage = new ImageIcon(checkedBoxImage);
Image finalCheckedBoxImage = newCheckedBoxImage.getImage().getScaledInstance(
boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
);
checkbox.setSelectedIcon(new ImageIcon(finalCheckedBoxImage));
checkbox.setSelected(false);
checkbox.setSelected(previousState);
}
What it does is get the size of the font from the checkbox's font metrics. Then using that it derives a new icon based on the icon found in the 'Look and Feel'.
One odd thing that I am not able to explain is how the icon for the checkbox in its 'un-selected' or default state, changes to the 'selected' icon, when I am accessing the same property to get each one.
I start by saving the state of the control so I can restore it at the end. This is done because in order for the icons to be set properly, the state needs to be unchecked when you first request the icon from the UIManager and then it will need to be checked when you request the icon the second time to get the 'selected' icon.
I am not entirely sure how the UIManager works or why the checkbox icon changes when we call the same property just by setting the 'selected' value of a single checkbox, but that is what is required in order to get both the necessary icons.
If you did not want to base the size on the font you could easily just pass in the height and width as parameters and use them instead of the font's height when setting the buffered image size.
I might mention that this same methodology works with radiobuttons
(source: google.com)
Recently, I realize the Chinese Character displayed are rather ugly in my application.
I thought I should make them to "anti-alias". But, how can I do that in Java?
FYI, I didn't explicitly choose the font I want to use in my GUI application. I solely let the system decide their own during startup. I however, do explicitly set the locale, before show up the GUI.
Locale.setDefault(locale);
The system will always choose
javax.swing.plaf.FontUIResource[family=Tahoma,name=Tahoma,style=plain,size=11]
no matter I am in English or Chinese locale.
Anti-aliasing considered harmful: http://www.joelonsoftware.com/articles/fog0000000041.html
The point is, that beauty of characters is not necessarily the user interface goal. It is not everything. What you should look for, is readability of text. When your Chinese characters look not smooth, it may be exactly what helps human eye's control loop to know that it is in focus and stop blaming the eye muscules for blurriness. Really, don't fall in this pitfal.
Here's a method to read a truetype font from the classpath and register it with the graphics environment:
private static Font readFont(String name) {
InputStream in = Fonts.class.getResourceAsStream(name + ".ttf");
if (in == null) {
throw new IllegalArgumentException(name);
}
try {
Font retval = Font.createFont(Font.TRUETYPE_FONT, in);
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(retval);
return retval;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
You can then use this font object to derive characters of different sizes, or you could try applying this font using Swing CSS. In this case, the value you would put in the "font-family" attribute is the value returned by Font.getName().
For example:
static {
Font font = readFont("VeraMono");
if (font != null) {
font = font.deriveFont(14f);
} else {
throw new IllegalStateException();
}
MONOSPACED_TEXT_FONT = font;
MONOSPACED_TEXT_FONT_STYLE = "font-family: " + font.getName() + "; font-size: 14pt; font-weight: normal;";
}