Swing has a nice feature where some components allow text to be specified using html. For example, the JLabel component can use html formatting simply using:
JLabel jl = new JLabel("<html><body><h1>Hello World</h1></body></html>");
I find this feature to be really convenient and I am using it in several places in my app.
I would like to know what the default styling is when I use this feature. I know that I can easily override these by adding my own style attributes, but I would like to know what the starting set is, because it is different than most browser defaults.
Where can I find out the default styling (font, line spacing, etc)? I have not seen anything in the documentation. I tried to browse through the source code, but I was unable to see where the tag gets parsed and the styling gets applied.
Can someone give me a pointer as to where to look for this information, possibly in the OpenJDK source?
The default style sheet is default.css, which can be found in resources.jar under the directory javax/swing/text/html/default.css.
You can also obtain the styles programmatically:
StyleSheet sheet = new HTMLEditorKit().getStyleSheet();
I believe the first answer is correct but incomplete.
Check out SwingUtilities2.displayPropertiesToCSS().
It adds a rule to the document stylesheet based on the component's font and foreground color. It is used by BasicHTML.BasicDocument.
I'm successfully exporting from mxGraph (Java) using the approach presented in the mxGraph exportPdf example.
However I'd like to specify a font that can support more asian-languag utf-8 encoded text, as the default font does not seem to be able to do so.
I came across this other SO question. An answer states the following "Note that you need to setup iText to map every font you need in the PDF" Can anyone provide any information as to the process involved to set up iText fonts for use by mxGraph java?
I've never tried it, but my understanding is that you need to pull in iTextAsian.jar and follow the CJK example, the key part of which is:
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font FontChinese = new Font(bfChinese, 12, Font.NORMAL);
Paragraph p = new Paragraph(chinese, FontChinese);
document.add(p);
I'm developing a web application which use JFreeChart to render chart. However, when server dose not have any Chinese font installed, JFreeChart dose not display Chinese character even if I have set the font.
Then I write a small testing code and find out that add this line of code before drawing the chart can solve the problem.
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font);
So my questions are -
Why do I have to register font into JVM even if I create my font from File? Does that mean JFreeChart do not use the font I set directly?
When I deploy my program into server, even if I add this line of code, it dose not display Chinese characters. How do I make it always use the font I set in order to display character properly in all environment?
I know I can make a fallback directory in $JAVA_HOME/jre/lib and put my font into it. But that dose not explain why JFreeChart cannot display with the font I set.
UPDATE
I'm pretty sure the font were load correctly, and so does registerFont() return true when I deploy the program into Tomcat.
UPDATE 2
According to JAVA 2D FAQ, now I realize I have to call registerFont() in order to make my own font "installed" into JVM, and my font will be available through Font constructor.
As of Java SE 6, there is a method :
GraphicsEnvironment.registerFont() which gives you the ability to make
a "created" font available to Font constructors and to be listed via
Font enumeration APIs. Font.createFont() and this method combine to
provide a way to "install" a Font into the running JRE so it is
available just as O/S installed fonts are. However this Font does not
persist across JRE invocations.
But, since I already have Font instances created/derived from createFont(), why doesn't my program still need to create other Font?
Following is the code I used, it simply output a chart in PNG format. If you want to run the code, you should change the output location and font to fit your need, and here is the SourceForge link for Chinese font I use in code.
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.io.File;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
public class Problem {
public static void main(String[] args) throws Exception {
setJFreeChartTheme();
PieDataset dataset = createDataSet();
JFreeChart chart = ChartFactory.createPieChart(
"Chinese Testing", dataset, true, true, false);
ChartUtilities.saveChartAsJPEG(new File("/tmp/output.png"),
chart, 800, 600);
System.out.println("Done");
}
private static void setJFreeChartTheme() throws Exception {
Font font = loadFont();
//==================================================================
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font);
//==================================================================
StandardChartTheme theme = new StandardChartTheme("Chinese font", true);
theme.setExtraLargeFont(font.deriveFont(Font.BOLD, 20));
theme.setLargeFont(font.deriveFont(Font.BOLD, 16));
theme.setRegularFont(font.deriveFont(Font.PLAIN, 14));
theme.setSmallFont(font.deriveFont(Font.PLAIN, 12));
ChartFactory.setChartTheme(theme);
}
private static Font loadFont() throws Exception {
File file = new File("/tmp/wqy-zenhei.ttc");
return Font.createFont(Font.TRUETYPE_FONT, file);
}
private static PieDataset createDataSet() {
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setValue("種類1", Integer.valueOf(1));
dataset.setValue("種類2", Integer.valueOf(2));
dataset.setValue("種類3", Integer.valueOf(3));
return dataset;
}
}
When you create a Font directly from the TTF, Java obviously knows where to get a copy of the font file itself from within that single Font object. So why does the font also need to be registered in order to use it? The answer is that it does not always have to be registered, or at least not so long as the entire chain of control uses the original Font object directly.
What really happens when Java tries to render the font?
The nuance is in how JFreeChart asks to render the text. Rendering of text is performed in the TextUtilities#drawRotatedString method from jcommon. On JDK7, this method will, by default:
create an AttributedString based on the "attributes" of the font that you have passed in,
call Graphics2D#drawString on the attributed string, which then
creates a new TextLayout object.
TextLayout is the class that selects the actual Font object to be provided to Graphics2D. TextLayout is designed to support the rendering of multilingual text using various fonts (even if the same single source String needs to be rendered in multiple fonts) by using automatic font selection to find an appropriate font for each piece of the string.
The "attributes" mentioned above are simple facts about the font (like font family name, size, etc) that are derived from the Font that you provide. In the event that the font you've provided is unable to render all of the characters in the input string, the attributes are used to select similar fonts to use for those runs of text that need to use a different font.
When JFreeChart invokes TextLayout, it always functions like this:
extract the attributes from the Font object you supplied,
call the static Font#getFont to get a font that matches the supplied attributes (see TextLayout#singleFont), and
uses the returned (possibly different) Font object to draw the text.
If you have not statically registered your font somewhere (like with GraphicsEnvironment#registerFont), then all that the static Font#getFont method will have to go on is the attribute string containing the font family name. It won't know where to access the Font object that contains the reference to the TTF, let alone any of the data needed to actually render the font.
OK, but I thought you said that I didn't need to register the font?
If you don't want to register the font, then the trick is in making sure that your text is rendered only with the Font object that you provide. It so happens that there is another constructor for TextLayout that accepts a Font object directly, rather than a set of attributes that are used to look up a font.
Helpfully, JFreeChart even provides a way to force it to use this constructor instead. In TextUtilities#drawRotatedString, a special configuration parameter can be used to force JFreeChart to construct the TextLayout object itself using the exact Font object you provide.
To do this, you can either set up a jcommon.properties file like this:
create a resource file named jcommon.properties (which should end up in the root level of your classpath/JAR), and
add the following line to it:
org.jfree.text.UseDrawRotatedStringWorkaround=true
or else simply make a call to the static function:
TextUtilities.setUseDrawRotatedStringWorkaround(true)
This will ask JFreeChart to render the text using your font directly, and...voila! It works even without having registered the font. This was tested in the context of the question above, which is that of using JFreeChart to render the text directly to a raster image. Your mileage might vary if you are trying to render to a display device (which I did not try).
Is it wise not to register the font?
I can't say for sure. One of my applications runs inside an OSGi container and I was wary of creating PermGen classloader leaks by statically registering a Font that can never be unregistered. Using the Font object directly avoids that problem, which is why I wanted to go this route. I suppose it's always possible that a specific Java platform might have trouble if you did this, but this works fine in my tests on at least Windows, Linux, and OS X hosts with Oracle JDK 7.
Why do I have to register font into JVM even if I create my font from file?
How else is the JVM going to know your font exists?
Your font has to be registered with the JVM so that Java knows how to draw your font in the graphics environment that JFreeChart uses to render charts.
How do I make it always use the font I set in order to display character properly in all environment ?
You need to check that the registerFont() method returns true. If it returns false, your font is not available.
It looks like you're loading the font correctly. Maybe the file path of your font isn't correct on your server. You might want to try
getClass().getResource(fontPath);
I know this is an old question, but I was searching for the answer myself and having seen the responses above, I still didn't really understand the purpose of registering a font. Having researched the issue, this is what I found:
You don't have to register your font with the graphics environment, but doing so comes with the advantage of being able to use the registered font in 'new Font()' constructors.
You can use the following code to get a list of all the fonts which are currently available (i.e installed and ready to use in your application):
String fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
Assuming you're on Windows, and one of the installed fonts is Arial, you can use this font in your application like this:
JButton yesButton = new JButton ("Yes");
yesButton.setFont(new Font("Arial", Font.PLAIN,30));
Now Suppose you want to load in and use your own custom font from a file:
Font robotoFont = Font.createFont(Font.TRUETYPE_FONT,getClass().getResourceAsStream("/res/fonts/Roboto/Roboto-Light.ttf"));
If you wanted to set that as the font for a JButton, you might write this code:
JButton yesButton = new JButton("Yes");
yesButton.setFont(robotoFont.deriveFont(Font.PLAIN, 30f));
But if you tried to write some code like:
JButton yesButton = new JButton("Yes");
yesButton.setFont(new Font ("Roboto Light", Font.PLAIN,30));
The JButton would just be given a default font, because the graphics environment is not aware of any font named "Roboto Light". The solution to this is to register your font with the graphics environment :
GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment();
genv.registerFont(robotoFont);
You will then be able to use this font in 'new Font()' constructors like this:
JButton yesButton = new JButton("Yes");
bestButton.setFont(new Font ("Roboto Light", Font.PLAIN,30));
How can I change the font color, size and button color from a Java file in Eclipse, not from an XML file?
For font size you can write it as
tv.setTextSize(20.0f);
For font color you can write it as
tv.setTextColor(Color.BLUE);
For button background color you can write it as
btn.setBackgroundColor(Color.CYAN);
button.setTextColor(Color.WHITE);
button.setBackgroundColor(Color.BLUE);
In the "Inherited XML Attributes" paragraph of the official documentation you can see either XML attributes (that you can change from XML) or related methods (which you can use in your Java code).
Others already posted answers on how to do it in Java, but I guess these could help you as well.
How to do it in XML:
Font Styling
Button Styling --Link changed.
I want to display HTML in a JEditorPane or JTextPane, but I want the style (font size) to come from the Look and Feel. Is there a way to do this, or do you have to use embedded HTML styling?
Here is an example:
epText = new JEditorPane("text/html", content);
StyleSheet ss = ((HTMLEditorKit)epText.getEditorKit()).getStyleSheet();
ss.addRule("p {font-size:" + FontManager.getManager().getFontSize() + "}");
HTMLEditorKit kit = (HTMLEditorKit) epText.getEditorKit();
kit.setStyleSheet(ss);
epText.setEditorKit(kit);
Whenever I set the editor kit, all text disappears. Do I need to set the text everytime?
Yes.
Dig into this snippet, from the Java API for HTMLEditorKit:
Customization from current LAF
HTML provides a well known set of features without exactly specifying
the display characteristics. Swing has
a theme mechanism for its
look-and-feel implementations. It is
desirable for the look-and-feel to
feed display characteristics into the
HTML views. An user with poor vision
for example would want high contrast
and larger than typical fonts.
The support for this is provided by the StyleSheet class. The
presentation of the HTML can be
heavily influenced by the setting of
the StyleSheet property on the EditorKit.
Edit: when you set the Editor Kit, it de-installs the old kit and installs the new one. This changes the underlying model, which is why the text 'disappears'.
Read the API for more info.
But you may not need to re-create the entire kit... just add a new sheet to your style.
Call this from the main method after you set L&F.
public static void setDefaultStyle()
{
// looks like WTF but that is the way to set default CSS
StyleSheet sheet=new HTMLEditorKit().getStyleSheet();
// add your rules
sheet.addRule("...");
sheet.addRule("...");
}
EDIT: At least this should work for JTextPane.