I have a Font object and I need both the width and height of the font. I know that the getSize() returns the height of the font as the point-size of a font is generally the height, but I'm at a loss when it comes to determining the width of the font.
Alternatively, being able to determine the width of each specific character supported by the Font would also be an acceptable solution.
My best guess is that the width is specified when using the loadFont method, but the documentation does not specify whether the size parameter represents the width or the height of the font.
All fonts being used are mono-space fonts such as DejaVu Sans Mono, GNU FreeMono, and Lucida Sans Unicode.
I have run into the same problem, and there seems to be no easy way. My solution was to create a Text element with the correct font and check it's size:
double computeTextWidth(Font font, String text, double wrappingWidth) {
Text helper = new Text();
helper.setFont(font);
helper.setText(text);
// Note that the wrapping width needs to be set to zero before
// getting the text's real preferred width.
helper.setWrappingWidth(0);
helper.setLineSpacing(0);
double w = Math.min(helper.prefWidth(-1), wrappingWidth);
helper.setWrappingWidth((int)Math.ceil(w));
double textWidth = Math.ceil(helper.getLayoutBounds().getWidth());
return textWidth;
}
If I remember correctly the trick here is to set prefWidth to -1. See the JavaDoc.
FontMetrics metrics = Toolkit.getToolkit().getFontLoader().getFontMetrics(font);
float charWidth = metrics.computeStringWidth("a");
float charHeight = metrics.getLineHeight();
Related
I need to draw a special character using graphics2d but some characters are not avaiable. For example, the character ➿ is rendered like a box:
Here is my code:
private void drawIcon(Graphics2D g2d) {
g2d.setColor(iconColor);
g2d.setFont(iconFont);
FontMetrics fm = g2d.getFontMetrics();
Rectangle2D r = fm.getStringBounds(icon, g2d);
int x = (int) ((getSize().getWidth() - (int) r.getWidth()) / 2);
int y = (int) ((getSize().getHeight() - (int) r.getHeight()) / 2 + fm.getAscent());
System.out.println(x + " " + y);
System.out.println(icon);
g2d.drawString(icon, x, y);
}
Where icon is, for example, the string "\u27BF" which should be displayed as "➿".
How could I add support to this character in my code?
Look for a freely redistributable (e.g. open source) TrueType font which contains your character. Assuming the font license allows it, you could take an existing font containing your character, and subset it to have just the character you need - using e.g. Font Optimizer. Alternatively, you could create your own font containing just this character using font design tools (e.g. FontForge).
Then you can embed the font as a resource in your JAR, and load it like this:
InputStream inp = getClass().getResourceAsStream("/com/example/myfont.ttf");
Font font = Font.createFont(Font.TRUETYPE_FONT, inp).deriveFont(18f);
g2d.setFont(font);
The deriveFont() call is because by default the loaded font size will be tiny (1 point), so this resizes it to 18 points.
Of course, rather than loading it every time you want to draw, you should load it once, say in the constructor or a static initialiser, and then stash it in a field for use by your draw routine.
This way your character should be visible across all platforms, regardless of what fonts the user has installed, and furthermore should look the same (or very similar) across all platforms too.
I met a strange requirements:let the non-monospace font right align,is there are some way to do it?how can detect the actual length for the non-monospace font string?
use the class FontMetrics provided by
FontMetrics myFontMetrics = myGraphics.getFontMetrics()
the call
int width = myFontMetrics.stringWidth(myString);
gives you the string width in pixels, which you can subtract from your drawing coordinate.
There were many posts regarding this problem, but i couldn't understand the answers given by people in there.
Like in this post: "How to change the size of the font of a JLabel to take the maximum size" the answer converts the font size to 14! But that is static and further in other answers; their whole output screen seems to increase.
I display certain numbers in a JLabel named "lnum", it can show numbers upto 3 digits but after that it shows like "4..." I want that if the number is able to fit in the label, it should not change its font size but if like a number is 4 digit, it should decrease the font size in such a way that it fits. NOTE: i do not want that the dimensions of the jLabel change. I just want to change the text in It.
Edit:
Here is what code i tried
String text = lnum.getText();
System.out.println("String Text = "+text);//DEBUG
Font originalFont = (Font)lnum.getClientProperty("originalfont"); // Get the original Font from client properties
if (originalFont == null) { // First time we call it: add it
originalFont = lnum.getFont();
lnum.putClientProperty("originalfont", originalFont);
}
int stringWidth = lnum.getFontMetrics(originalFont).stringWidth(text);
int componentWidth = lnum.getWidth();
stringWidth = stringWidth + 25; //DEBUG TRY
if (stringWidth > componentWidth) { // Resize only if needed
// Find out how much the font can shrink in width.
double widthRatio = (double)componentWidth / (double)stringWidth;
int newFontSize = (int)Math.floor(originalFont.getSize() * widthRatio); // Keep the minimum size
// Set the label's font size to the newly determined size.
lnum.setFont(new Font(originalFont.getName(), originalFont.getStyle(), newFontSize));
}else{
lnum.setFont(originalFont); // Text fits, do not change font size
System.out.println("I didnt change it hahaha");//DEBUG
}
lnum.setText(text);
I have a problem that many a times it doesn't work, like if the text is "-28885" it shows "-28...".
stringWidth = stringWidth + 25; //DEBUG TRY
I had to add this code so that it increases the length that it gets. It was a code i added to just temporarly fix the problem. I want a permanent solution for this.
Adapted from an answer on the question you referred to:
void setTextFit(JLabel label, String text) {
Font originalFont = (Font)label.getClientProperty("originalfont"); // Get the original Font from client properties
if (originalFont == null) { // First time we call it: add it
originalFont = label.getFont();
label.putClientProperty("originalfont", originalFont);
}
int stringWidth = label.getFontMetrics(originalFont).stringWidth(text);
int componentWidth = label.getWidth();
if (stringWidth > componentWidth) { // Resize only if needed
// Find out how much the font can shrink in width.
double widthRatio = (double)componentWidth / (double)stringWidth;
int newFontSize = (int)Math.floor(originalFont.getSize() * widthRatio); // Keep the minimum size
// Set the label's font size to the newly determined size.
label.setFont(new Font(originalFont.getName(), originalFont.getStyle(), newFontSize));
} else
label.setFont(originalFont); // Text fits, do not change font size
label.setText(text);
}
When you'll display a number that would fit, you should reset the Font back to its original (see the else part).
EDIT: If you can't/don't want to keep a reference to the original Font, you can save it as a "client property" (see the first lines).
I want to label my hashmarks in my grid for my graph, however when I use even font size 1 it is way to big! Is there a way to make a font size smaller than 1? Am I missing something with how I'm coding it?
Here's the code which generates the grid and attempts to put a label on the hash.
for (double k = myStart1; k <= myEnd1; k = k + (myEnd1 - myStart1) / 8) {
g2.setColor(Color.BLACK);
g2.draw(new Line2D.Double(k, (max - min) / 60, k, -(max - min) / 60));
String labelx=String.valueOf(k);
Float xCo=Float.parseFloat(Double.toString(k));
g2.setFont(new Font("SansSerif",Font.PLAIN,1));
g2.drawString(labelx, xCo, 0);
}
Here's a screenshot of the graph produced by x^2.
As I'm sure you've already noted, the Font constructor takes an int for the size parameter- effectively rendering impossible the construction of a font (using this method, at least) which has a size between 0 and 1.
I did, however, find the deriveFont method of the Font class particularly interesting:
public Font deriveFont(float size)
Creates a new Font object by replicating the current Font object and applying a new size to it.
Parameters:
size - the size for the new Font.
The deriveFont method, which claims to construct a new Font with the given size, takes a float as the parameter- therefore, it might be possible to do something like this:
Font theFont = new Font("SansSerif",Font.PLAIN,1);
theFont = theFont.deriveFont(0.5);
g2.setFont(theFont);
Resulting in a font with a size of 0.5.
Now, I haven't tested this myself- setting up a Graphics program takes time, so you're in a much better position to try it out than me. But just throwing it out there as a possibility.
Is there any way how to determine the optimal canvas size for text rendering?
The input is a string with newlines, I want to contruct the canvas to fit (no insets) while using both font types - proportional and non-proportional, these types will be never mixed.
Thanks.
From the Java Tutorial Measuring Text
FontMetrics metrics = graphics.getFontMetrics(font);
int hgt = metrics.getHeight();
int adv = metrics.stringWidth(text);
Dimension size = new Dimension(adv+2, hgt+2);
You probably need to do this line by line of your text and detect whether your font changes between lines.