Java Get Size of Font - java

I have JFrame with a JTextArea inside of it.
Font font = new Font("monospaced", Font.PLAIN, 14);
textarea.setFont(font);
Since the font is monospaced, all characters are the same width and height.
I'd like to know what this width and height is in pixels.
For this, I could use font.getStringBounds but I have no Graphics context to pass to it. frame.getGraphics() returns null.
How can I find the size of a character? Can it be done without a Graphics instance? I don't want an instance of it anyway. I just want to know how big my characters are.

You can use JFrame#getFontMetrics since one of JFrame's Superclass is Component.
If this does not work, you can also use BufferedImage to get a Graphics object:
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
You can use the image object to get an instance of Graphics.

FYI, I am using a JFrame/JTextarea to render a text based game, so I'll use this info for scaling the text and getting the dimensions of the window in units of characters
It's probably not the best approach, it would be better to simply use JTextArea#setColumns and JTextArea#setRows which will use the font based information to make determinations about it's preferred size automatically
You can then make use of the LayoutManager APIs and simply call pack on the JFrame which will pack the window around the contents, based on it's preferred size
This will also affect the preferred size of JScrollPane

Related

Automatically changing the font size in a Swing component as the string length increases

I have a JTextField that displays a line number like this : 2 or 2.1 or 2.1.1 etc. I would like the size of the JTextField to always stay the same but I want the font size to decrease/increase so that the text is always fully displayed and it fills the text field.
I'm wondering if there's a simple way to do this (I don't mind using a different swing component) or will I have to do it manually i.e. by checking the size of the text and changing the text field size?
I'd obviously prefer not to do it this way since the size increment may not be a nice number to go from e.g. 2.1 to 2.1.1.
the JTextField becomes smaller as the font decreases.
The preferred size of the text field is based on the font. So the size will increase/decrease as the font size changes. Override the getPreferredSize() method of JTextField to provide your own implementation.
Maybe something like:
Font current = getFont();
setFont( UIManager.getFont("TextField.font") );
Dimension preferred = super.getPreferredSize();
setFont( current );
return preferred;
I don't know any component performing this, but you can write it yourself by extending jTextField and using
FontMetrics.stringWidth()
to determine the font size (e.g. on overloaded setText).

JDialog doesn't respect dimensions of child components

I have a setup that usually works, but I'm finding it a bit of a pain at the moment.
I have a JDialog (formerly a JFrame, but I've changed the UI flow recently to remove redundant JFrames) set to BorderLayout that contains three main JPanels, header, content and footer.
The header JPanel has a background image that is loading fine. However, I'm calling all manner of setMinimumSize / setPreferredSize / etc (I even tried setSize and setBounds out of desperation) and the JPanel isn't being sized correctly. The layout for that component is BoxLayout, and the children sit comfortably within it, but that shouldn't affect what I'm trying to do with the header panel itself.
The only thing that works is setting a size on the parent JDialog. But I don't want to do that / from what I've read it seems like bad design. I'd also have to maths out the potential width / height of all the children, add the margins, etc.
Advice I am not looking for: "use a different LayoutManager."
I want to understand if there's a reason for the child components not being respected.
I can provide code, but isolating a small, runnable segment is difficult given the amount of interlocked systems I'm juggling. Here is the relevant snippet to set the size of the JPanel. The image dimensions are 480 * 96.
public JPanelThemed(BufferedImage image) {
super();
this.backgroundImage = image;
setAllSimilarConstraints(new Dimension(image.getWidth(), image.getHeight()));
setOpaque(false);
}
// for use with BoxLayout as it requires explicit bounds to be set
public void setAllSimilarConstraints(Dimension dim) {
setPreferredSize(dim);
setMinimumSize(dim);
setMaximumSize(dim);
}
I would implement it a bit another way - to ensure that preferred/min/max/Size can not be changed from elsewhere:
public JPanelThemed(BufferedImage image) {
this.backgroundImage = image;
setOpaque(false);
}
public Dimension getPreferredSize() {
return new Dimension(this.backgroundImage.getWidth(), this.backgroundImage.getHeight());
}
If I don't define dimensions, how do I ensure the whole background I'm painting is displayed?
You could use a JLabel to display the ImageIcon. The size of the label will be the size of the image. You then set the layout manager of the label so you can add components to it.
Edit:
do you know why it's commonly-recommended to subclass JPanel when painting backgrounds in Java
When you use a JPanel the size of the panel is based on the components added to the panel and the layout manager you are using. Your custom painting code then needs to paint the image the way your want. That is you can paint the image from (0, 0), or you can center the image on the panel, you can scale the image to make it fit the pane, but the image in no way controls the size of the panel, unless you override the getPreferredSize() method of the panel to use custom code to base the size of the larger of the components or the image. So you are in full control.
When you use the JLabel approach suggested here, the size of the label is always the size of the image. Then components will be positioned based on the layout manager but can be truncated if the image is smaller than the space required by the components.
So based on your requirement that you want to make sure the entire image is displayed, I suggested the JLabel approach, since you don't need to write any custom code. I find this a simple approach when using popup non-resizable dialogs to display a background image and a few components and buttons to close the dialog.
You can also check out Background Panel which provides these common painting features in a reusable class.

increasing the size of spot indicator on JTextArea

I have a JTextArea in my java code, I want to increase the size of the cursor which points the writing position/spot on the JTextArea, I am not talking about the cursor which points the position of mouse, but the cursor/pointer which indicates the spot of writing on JTextArea. Please tell how I can increase its size?
The text cursor is called Caret. You can change the caret by setting a new caret with the JTextComponent.setCaret() method (JTextArea extends JTextComponent).
Carets are responsible rendering themselves, so you can paint as big caret as you would like to. Basically what you should do is extend DefaultCaret and override its paint() method.
Here's an example of a custom caret:
http://java-sl.com/tip_overwrite_mode.html
one way is to simply increase the font size. Is this what you want? or do you want to keep the font small?
Font font = new Font("Verdana", Font.BOLD, 30);
txt.setFont(font);

Java - Changing text size using canvas?

I am trying to change the size of the text I am drawing to my canvas. I have searched all the properties that the canvas method holds, but there are no options for text size.
canvas.drawText("TESTTT", 200, 200, colorCyan);
Obviously the text is way too small and the font is ugly :( What can I do?
You can set size to the paint object
colorCyan.setTextSize(40f); // takes a float as the param
http://developer.android.com/reference/android/graphics/Paint.html#setTextSize(float)
public void setTextSize (float textSize)
Added in API level 1 Set the paint's text size. This value must be > 0
Parameters textSize set the paint's text size.
You didn't search too much ;)
Paint paint = new Paint();
paint.setTextSize(...
before drawing if.

Swing: Resizing RadioButton

I need to implement font size switching in my app. But when I increase font's size RadioButtons remain same size and on small screen with high resolution my customer just can't hit it easily. Is there a way to resize RadioButton's round thing programmatically without diging into L&F and redrawing Icons manually (it's complicated since app targets multiple platforms with different UIs and each of them must have 7 icons).
Perfect solution could look like this:
Extraction of native UI icon.
Resizing it
Setting resized icon as component's icon.
How to implement step 1? Is it possible?
EDIT: this is what i tried so far
public class IconImageSaver extends JFrame{
public IconImageSaver() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(0,0,100,100);
setVisible(true);
JRadioButton rad1 = new JRadioButton();
rad1.setBounds(10,10,40,40);
add(rad1);
Icon icon = UIManager.getIcon("RadioButton.icon");//(1) trying to get icon
int w = icon.getIconWidth(),h = icon.getIconHeight();
Image i = rad1.createImage(w, h);
Image i2 = rad1.createImage(w,h);
Graphics g = i.getGraphics();
Graphics g2 = i2.getGraphics();
g.setColor(Color.CYAN);
g.fillRect(0, 0, w, h);
rad1.setIcon(new ImageIcon(i));//setting icons
g2.setColor(Color.RED);
g2.fillRect(0, 0, w, h);
rad1.setPressedIcon(new ImageIcon(i2));//setting icons
}
public static void main(String[] args) {
new IconImageSaver();
}
}
At position (1) i'm trying to get icon image, but it returns only background color.
Can't understand why.
Setting icons for various states works as intended.
Some L&Fs (e.g. Nimbus, Aqua) support a large JComponent.sizeVariant, as discussed in Resizing a Component and Using Client Properties.
Addendum: I must use pure native L&F.
The rendering of a JRadioButton is determined by its associated ButtonUI delegate. The internals of delegates supplied by the native L&F are generally inaccessible and rely on host platform APIs. You have to use the available feature(s) of the user's chosen L&F or supply your own. If you can explain more about the underlying problem, it may help to suggest better alternatives.
Addendum: Absent developing a complete L&F, it may be possible to work with the radio button's parent, JToggleButton. Such buttons work well in a ButtonGroup, as shown here, and they can be decorated arbitrarily, as outlined here.
is very L&F sensitive, by default you can
use proper L&F (only Nimbus has implemented auto_whatever) but we talking about Custom L&F
to override keys in UIManager, but these keys can, could (be presented or with value) or missing in compare with another L&F
create own (J)Component, to overide important methods and
a) put to the UIManger (one def. valid for whole JVM instace)
b) add to the selected, desired or part of (J)Components, e.i. .... in the visible GUI
notice for (I need to implement font size switching in my app) there is very important to test if is required to change (we'll talking about) Font or FontUIResources, part of implemented methods for part of (J)Components to pretty ignore Font and required FontUIResources, now not sure if vice versa too
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 a little bit differently.
I Was scaling my font globally using the UIManager defaults and so I wanted my radio buttons to scale with the font.
I found I could do this by extracting the Icon for the radio button from the UIManager, buffering them, re-sizing them and then deriving a new icon from the graphics of the buffered icons.
I ended up with this function:
public static void scaleRadioButtonIcon(JRadioButton rb){
boolean previousState = rb.isSelected();
rb.setSelected(false);
FontMetrics boxFontMetrics = rb.getFontMetrics(rb.getFont());
Icon radioIcon = UIManager.getIcon("RadioButton.icon");
BufferedImage radioImage = new BufferedImage(
radioIcon.getIconWidth(), radioIcon.getIconHeight(),BufferedImage.TYPE_INT_ARGB
);
Graphics graphics = radioImage.createGraphics();
try{
radioIcon.paintIcon(rb, graphics, 0, 0);
}finally{
graphics.dispose();
}
ImageIcon newRadioImage = new ImageIcon(radioImage);
Image finalRadioImage = newRadioImage.getImage().getScaledInstance(
boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
);
rb.setSelected(true);
Icon selectedRadioIcon = UIManager.getIcon("RadioButton.icon");
BufferedImage selectedRadioImage = new BufferedImage(
selectedRadioIcon.getIconWidth(), selectedRadioIcon.getIconHeight(),BufferedImage.TYPE_INT_ARGB
);
Graphics selectedGraphics = selectedRadioImage.createGraphics();
try{
selectedRadioIcon.paintIcon(rb, selectedGraphics, 0, 0);
}finally{
selectedGraphics.dispose();
}
ImageIcon newSelectedRadioImage = new ImageIcon(selectedRadioImage);
Image selectedFinalRadioImage = newSelectedRadioImage.getImage().getScaledInstance(
boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
);
rb.setSelected(previousState);
rb.setIcon(new ImageIcon(finalRadioImage));
rb.setSelectedIcon(new ImageIcon(selectedFinalRadioImage));
}
What it does is get the size of the font from the radiobuttons's font metrics. Using those metrics, it derives a new icon based on the icon found in the 'Look and Feel' and sizing it to the font's height.
One thing that I am not able to explain is how the icon for the radiobutton coming out of the UIManager changes to the 'selected' icon when I am accessing the same property to get both icons.
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.
Again, I am not entirely sure how the UIManager works or why the icon changes when we call the same property just by setting the 'selected' value of a single radiobutton, but that is what is required in order to get both the necessary icons.
If you did not want to use the font to size the controls, 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 checkboxes

Categories