JLabel Width dependent from Text Length - java

So I have a JLabel here that's text is set from a String taken from a file seen here:
Label lName = new JLabel("Charater Name: " + data[FileIO.NAME]);
lName.setForeground(Color.WHITE);
lName.setBounds(640 - 110, 5, 110, 30);
add(lName);
Since the name could be 3 letters long to 24 letters long I don't want to use a fixed width, I want the label's width to wrap around the text enough so that the text isn't cut off but so that it's not wasting a bunch of space, how can I do this?
Edit:
The JLabel's location will be set programmatically depending on it's width.
Currently my only solution is setting the width to this:
(int) (lName.getText().length() * (double) 6.8)
Which lasts for around 40 letters before being cut off.

Related

libgdx: Label height multiple lines

I have a Label object with a text in it...
Label label = new Label(text);
..and I get the height by...
label.pack();
GlyphLayout layout = label.getGlyphLayout();
float height = layout.height;
When I add them to a table I just said
Table t = new Table();
t.add(label).width(200).height(height);
Currently I work on a chat window and each entry of the
window is a Label containing a colored name and text, like...
Note: The debug lines are drawn. Please ignore the blue line, it's from another table in the scene
Now my question: The 1-liner has a glyphlayout height of 38 and the 3-liner 139. Does someone know why there's such a big gap between the 2 entries resp. why the 3-liner height doesn't seem to be correct? No extra spacing / padding.
I would appreciate any ideas to solve this.
SOLVED:
My post was incomplete, sorry. I set the width of the label before calling...
label.setWidth(x); // where x was < chatbox width
label.pack();
So the GlyphLayout assumed a width which was smaller than the actual chatbox width. The result is of course a bigger height...
Thanks a lot to the libgdx IRC, especially Tomski :)

setBounds value for width that will set width to minimum?

Is there a value that can be put into setBounds to set the width to the minimum needed?
JLabel title = new JLabel("Title Text");
title.setBounds(50, 20, ?, 13);
Rather than using guess & check to find the minimum width, is there a value I can use?
If you already know the text that will be in the JLabel (i.e., if that text won't change after being assigned once), there is no need to set the minimum width; the JLabel should do so automatically.

Using 'small' values in progressBar with 9 patch looks bad

I'm using libGDX ProgressBar. I create it with the next code:
style = new ProgressBar.ProgressBarStyle();
style.background = new SpriteDrawable(backgroundImage);
NinePatch fillImage = new NinePatch(new TextureRegion(img2, 1, 1, img2.getWidth(), img2.getHeight()), 25, 26, 30, 30);
style.knobBefore = new NinePatchDrawable(fillImage);
style.knobBefore.setMinWidth(0);
style.knobBefore.setRightWidth(0);
style.knobBefore.setLeftWidth(0);
progress = new ProgressBar(0, 30, 0.1f, false, style);
When I set a value to a big number, for example 15 this is how it looks:[1]
but when I set a small value 1/30 (smaller the the basic 9 patch image) it looks bad:
Any ideas how to handle this problem?
You are setting your NinePatch width to be less than the minimum. The left and right do not change, so the minimum width your NinePatch can be is 25 + 26 = 51px. Any less than this you will get erroneous results. I believe the reason it looks like that is because your sides are actually pushing through each other, creating a negative width for the centre, which is still completely acceptable to draw with. (You can see in your image that the right is at the very far left, the left is most likely at the very far right but behind the reversed middle) The simplest solution would just be to limit the progress bar width to the proper minimum with something like this (if progress value is between 0 and 1);
//convert min width to a ratio
float minProgress = style.knobBefore.getMinWidth() / progressBarLength;
float progress = Math.max(progress, minProgress);
getMinWidth() would probably tell you it is 51/52px. You also shouldn't force setMinWidth(), setLeftWidht(), setRightWidth().

I want to decrease the font size if text doesn't fit in JLabel

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).

Why do JTextArea and TextLayout wrap words differently?

We have an app that draws text, but then displays a JTextArea for the user to edit the text when they click on the text. However, the wrapping between these two text-handling components differs. They use the same width, text String, and Font.
For the text-drawing, I'm using the from the Java tutorial, which I've also seen used by others in related questions here and other forums. Here's that part of the code:
FontRenderContext frc = g2d.getFontRenderContext();
TextLayout layout;
AttributedString attrString = new AttributedString(myText);
AttributedCharacterIterator charIterator;
int paragraphStart;
int paragraphEnd;
LineBreakMeasurer lineMeasurer;
float breakWidth;
float drawPosX;
float drawPosY;
attrString.addAttribute(TextAttribute.FONT, myFont);
charIterator = attrString.getIterator();
paragraphStart = charIterator.getBeginIndex();
paragraphEnd = charIterator.getEndIndex();
lineMeasurer = new LineBreakMeasurer(charIterator, frc);
// Set break width to width of Component.
breakWidth = myTextWidth;
drawPosY = startY
// Set position to the index of the first character in the paragraph.
lineMeasurer.setPosition(paragraphStart);
textBounds = new Rectangle(startX, startY(), 0, 0);
// Get lines from until the entire paragraph has been displayed.
while (lineMeasurer.getPosition() < paragraphEnd) {
layout = lineMeasurer.nextLayout(breakWidth);
// Compute pen x position. If the paragraph is right-to-left we
// will align the TextLayouts to the right edge of the panel.
drawPosX = layout.isLeftToRight()
? startX() : breakWidth - layout.getAdvance();
// Draw the TextLayout at (drawPosX, drawPosY).
layout.draw(g2d, drawPosX, drawPosY);
lineBounds = new Rectangle2D.Float(drawPosX, drawPosY - layout.getAscent(), layout.getAdvance(), (layout.getAscent() + layout.getDescent() + layout.getLeading()));
// Move y-coordinate in preparation for next layout.
drawPosY += layout.getAscent() + layout.getDescent() + layout.getLeading();
}
The JTextArea is much simpler:
JTextArea textArea = new JTextArea(myText);
textArea.setSize(myTextWidth, myTextThing.getHeight());
textArea.setOpaque(true);
textArea.setVisible(true);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setFont(myFont);
textArea.setBorder(null);
I set the border to null because I have another rectangle drawn outside the bounds of the text area with a dashed area to show where it is. Might seem silly now, but we use it to show the bounds of the text area when the user first selects the text they want to edit. At that point, the JTextArea isn't yet created. They have to click on it again to begin editing. The reason for this is that once a text area is selected, they may also drag and resize the text area, and that gets messy and more confusing if they had a live JTextArea when they started dragging and resizing.
Separately, both the drawn TextLayouts and the JTextArea appear to wrap words just fine. but when used together you can see the difference. The problem with this is that while the user is editing the text, the JTextArea is doing its thing to wrap the text. But when the user JTextArea loses focus, it is converted to the drawn text, and then the words may be wrapped differently.
Fill the text area with i or l characters. Grab a UI ruler or magnifying glass and count the size of your text area in pixels from the leftmost character of the longest line to the rightmost. Do the same with n, m, and a few other characters for a few more data points. I suspect that the text area has an invisible border of a few pixels it uses even when set to no border. If this is the case, add the same border around the TextLayout component and they should appear identical.
(Alternatively to counting pixels, you could set a background color for the text or the components, but I wouldn't necessarily trust it.)

Categories