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.
Related
Many times over the years, I have been faced with the problem of resizing text in to fit in a certain area on a Java GUI. My solution was usually to work around the issue by:
Redesigning the interface to avoid the problem
Changing the area to fit the size of the text
Doing a binary search for the correct size font to fit the string(when I could not do either of the first 2)
While working on another project recently that needed to determine the correct font size for a given region quickly, my binary search method was too slow(I suspect because of the dynamic memory allocations involved with creating and measuring a font many times in sequence) and introduced noticeable lag into my application. What I needed was a faster easier way to calculate a font size that would allow a given string to be rendered to fit within a defined region of the GUI.
Finally it occurred to me that there was a much easier and faster way that only required a few allocations at run time. This new method eliminated the need for any kind of search and requires only 1 measurement to be taken, it does, however, need to make one assumption, one that is perfectly reasonable for most applications.
The width and height of the font must be the proportional to the point size of the font. This happens on all but the most obscure transformations done to a rendering context.
Using this assumption, we can compute the ratio of the font's dimensions to the point size, and linearly extrapolate to find the font size that we need for the given region. Some code that I wrote to do this is below:
Edit:
The accuracy of the initial measurement is limited by the size of the base font. Using a really small font size as the base can throw off the results. But the larger the size of the base font the more accurate the more accurate the linear approximation is.
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Shape;
import java.awt.font.GlyphVector;
import java.awt.geom.Rectangle2D;
public class FontUtilities
{
public static Font createFontToFit
(
String value,
double width,
double height,
Font base,
Graphics context
)
{
double measuredWidth;
double measuredHeight;
double baseFontSize;
FontMetrics ruler;
Rectangle2D bounds;
double heightBasedFontSize;
double widthBasedFontSize;
GlyphVector vector;
Shape outline;
if
(
(value == null) ||
(base == null) ||
(context == null) ||
(width != width) ||
(height != height)
)
{
return null;
}
//measure the size of the string in the current font size
baseFontSize = base.getSize2D();
ruler = context.getFontMetrics(base);
vector = base.createGlyphVector(ruler.getFontRenderContext(), value);
//use the bounds measurement on the outline of the text since this is the only
//measurement method that seems to be bug free and consistent in java
outline = vector.getOutline(0, 0);
bounds = outline.getBounds();
measuredWidth = bounds.getWidth();
measuredHeight = bounds.getHeight();
//assume that each of the width and the height of the string
//is proportional to the font size, calculate the ratio
//and extrapolate linearly to determine the needed font size.
//should have 2 font sizes one for matching the width, and one for
//matching the height, return the least of the 2
widthBasedFontSize = (baseFontSize*width)/measuredWidth;
heightBasedFontSize = (baseFontSize*height)/measuredHeight;
if(widthBasedFontSize < heightBasedFontSize)
{
return base.deriveFont(base.getStyle(), (float)widthBasedFontSize);
}
else
{
return base.deriveFont(base.getStyle(), (float)heightBasedFontSize);
}
}
}
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.
So my problem is this: I have a class extending JProgressBar and basically it looks like a flashing circle(it also breaks into segments depending on the amount of tasks, assigned to that indicator and I need to use setUI each time I switch indicator to the next task, which is pretty bad, but it'll do for now). I need to position 37 of those circles on a JPanel so that they form a circle of their own. Right now I do it like this:
private void addToPane(JPanel pane){
pane.setLayout(null);
Insets insets = pane.getInsets();
int width = pane.getWidth();
int height = pane.getHeight();
Dimension size = new Dimension(30, 30);
//Dimension mid = new Dimension(width/2, height/2);
Dimension mid = new Dimension(200, 250);
int r = 210;
double revox, revoy, angle = -Math.PI/2;
double revangle = 2*Math.PI/37;
for(int i=1; i<38; i++){
FlashingIndicator templabel = new FlashingIndicator();
templabel.setPreferredSize(size);
templabel.setUI(new ProgressIndicator(flash, 0, false));
templabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
indicate.add(templabel);
revox = r*Math.cos(angle);
revoy = r*Math.sin(angle);
indicate.get(i - 1).setBounds(insets.left + mid.width + (int) revox, insets.top + mid.height + (int) revoy, size.width, size.height);
pane.add(indicate.get(i - 1));
angle-=revangle;
}
}
No need to say: this is pretty bad. I wanted to locate them depending on the size of the panel, but when the function is being called in createUIComponents() (I use IntelliJ Idea's GUI builder) - the panel is not properly created yet, so getWidth() just returns 0. Using random numbers like 200 and 250 is bad for the obvious reasons. Also seems like the general consensus is: Null Layout is bad and I shouldn't use it. So here's the question:
Which LayoutManager should I use in order to locate indicators properly? All I can think of is GridLayout, but the way I do it now indicators nicely overlap a bit, using a grid will make it look rough. And if I can't use managers for this - how can I make it dependnant on the size of the panel?
Right now it looks like this:
Override the paintDeterminate() method in a custom BasicProgressBarUI to render your indicator; a related example is seen here. You can scale the rendering, as shown here, in a way that fills the component; this will obviate the need for a custom layout manager internal to your component. Override getPreferredSize(), as discussed here, so that your custom progress indicator works correctly with enclosing layouts.
I am generating pdf files by XML data.
I calculate the height of a paragraph element as :
float paraWidth = 0.0f;
for (Object o : el.getChunks()) {
paraWidth += ((Chunk) o).getWidthPoint();
}
float paraHeight = paraWidth/PageSize.A4.getWidth();
But this method does not works correctly.
Can you give me an idea?
Your question is strange. According to the header of your question, you want to know the height of a string, but your code shows that you are asking for the width of a String.
Please take a look at the FoobarFilmFestival example.
If bf is a BaseFont instance, then you can use:
float ascent = bf.getAscentPoint("Some String", 12);
float descent = bf.getDescentPoint("Some String", 12);
This will return the height above the baseline and the height below the baseline, when we use a font size of 12. As you probably know, the font size is an indication of the average height. It's not the actual height. It's just a number we work with.
The total height will be:
float height = ascent - descent;
Or maybe you want to know the number of lines taken by a Paragraph and multiply that with the leading. In that case, there are different possibilities. As it's not clear from your question what you want (height of chunks, width of chunks, vertical position of the baseline,...), you won't get any better answers than the ones that are already given. Please rephrase your question if the height of the glyphs in a Chunk wasn't what you expected.
Firstly why you iterating over Chunk collection casted to Object ? If all elements of this collection are Chunk, use this:
for (Chunk c : el.getChunks()) {
paraWidth += c.getWidthPoint();
}
What do you mean saying method does not works correctly ?
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).