Java - TitledBorder takes up too much vertical space (on Windows only) - java

I want to use a TitledBorder around a JTextField without it taking up too much vertical space.
In the top it applies way more spacing for title font than is needed. Also in the bottom there's a whopping 4 pixels I can't use.
This occurs only on Windows; on Mac OSX the example below looks fine while on W10 the JTextField content is horribly cropped.
Can I reduce this in any way?
import java.awt.Dimension;
import java.awt.Font;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
public class MoreSpace {
static public void main(String args[]) {
EmptyBorder eb = new EmptyBorder(0, 0, 0, 0);
TitledBorder tb = new TitledBorder(eb, "Title");
Font font = new Font("dialog", Font.BOLD, 10);
tb.setTitleFont(font);
JTextField textField = new JTextField();
textField.setPreferredSize(new Dimension(300,26));
textField.setBorder(tb);
textField.setText("I cant breathe in here");
JOptionPane.showMessageDialog(null, textField, "",JOptionPane.PLAIN_MESSAGE);
}
}

Create a custom TitledBorder class(from package javax.swing.border) and reduce the maximum EDGE_SPACING as desired.
// Space between the border and the component's edge
static protected final int EDGE_SPACING = 2;
this means 2 pixels above and below as padding by default for the TitledBorder. This should explain the 4 pixels you are seeing.
Setting EDGE_SPACING to 0 will do what you are looking for. :)

Related

Prevent JLabel with html from breaking line

Wondering if anyone knows how to disable line break when using html in JLabel.
Here is the code:
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import java.awt.GridLayout;
public class Main
{
private static final int[] TEXT =
{ 0x05D0, 0x05B2, 0x05DC,
0x05B5, 0x05D9, 0x05DB,
0x05B6, 0x05DD
};
public static void main(String[] args)
{
String text = "";
for(int cp : TEXT)
text += Character.toString(cp);
String html = "<html>" + text + "</html>";
JLabel label = new JLabel(html);
JLabel msg = new JLabel("The text should at least go out to here.");
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2,1));
panel.add(label);
panel.add(msg);
JOptionPane.showMessageDialog(null, panel);
}
}
The bidi text breaks into two lines. I am trying to write html to a JTree node so it will support multiple font families. I can't get it to work with a JLabel. I'm thinking I might need to paint it in a cell renderer. I was hoping to get the html to work. It would make things a lot easier.
Any suggestions?
=== Edit ===
When my display setting in Windows is at 125% it breaks the line; however, when I change my display setting in Windows to 100% it does not break the line. Running 1920 x 1080 display. Anyone have any ideas? Or, is anyone able to repeat the breaking of the line?
=== Edit ===
Interestingly when I pass -Dsun.java2d.uiScale= with 1.0 or 2.0 it works. When I use 3.0, 4.0, 1.25 or 1.5 or 0.8 it does not work.
Well, I submitted a bug report. I managed to find a workaround that seems to work for all Windows Display Scale's but it is quite a hacky workaround. But it will be sufficient until the bug is fixed.
Here it is:
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.GridLayout;
import java.awt.font.FontRenderContext;
public class Main
{
private static final String TEXT =
"\u05D0\u05B2\u05DC\u05B5\u05D9\u05DB\u05B6\u05DD";
public static void main(String[] args)
{
JLabel label = new JLabel();
Graphics2D g2 = (Graphics2D)new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).getGraphics();
FontRenderContext frc = g2.getFontRenderContext();
String[] split = TEXT.split("");
double width = 0;
for(String chr : split)
width += label.getFont().getStringBounds(chr, frc).getWidth();
double scale = Toolkit.getDefaultToolkit().getScreenResolution()/96.0;
String html = "<html><p style=\"width:"+Math.ceil(width/scale)+"px;\">" + TEXT + "</p></html>";
label.setText(html);
JLabel msg = new JLabel("The text should at least go out to here.");
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2,1));
panel.add(label);
panel.add(msg);
JOptionPane.showMessageDialog(null, panel);
}
}
Note: If I don't get the individual character lengths then the width doesn't come out right in a JTree node. Also, for some reason when I use bidi text the resultant width of the nodes JLabel is about twice the width of the text. Any shorter and it does not display correctly. However, the width is correct with Non-Bidirectional text. Also, width: does not work with span tag, it only works with p tag

Why don't size and preferredSize make this label bigger?

I'm building up a panel that will go in a larger program; the following program still illustrates my question, but it looks a bit more complicated than it absolutely has to because there are places I will add things later.
package sandbox;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class SpacingPlay extends JFrame
{
private static final long serialVersionUID = 1L;
public static void main(String[] args)
{
SpacingPlay sp = new SpacingPlay();
sp.setVisible(true);
}
public SpacingPlay()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new DragNDropPanel();
add(panel);
pack();
}
class DragNDropPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public DragNDropPanel()
{
JPanel currentImagePanel = getCurrentImagePanel();
JPanel leftPanel = new JPanel();
leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS));
leftPanel.add(currentImagePanel);
// other things will go here; I cut them out to make this simpler.
setLayout(new BorderLayout());
// put things in a containing panel so that they aren't stretched being in the WEST part of a borderlayout.
JPanel leftContainingPanel = new JPanel();
leftContainingPanel.add(leftPanel);
add(leftContainingPanel, BorderLayout.WEST);
}
private Component createStandardSpace()
{
return Box.createRigidArea(new Dimension(0, 15));
}
private JPanel getCurrentImagePanel()
{
JPanel currentImagePanel = new JPanel();
currentImagePanel.setLayout(new BoxLayout(currentImagePanel, BoxLayout.PAGE_AXIS));
JLabel currentImageLabel = new JLabel("none");
currentImageLabel.setBorder(BorderFactory.createDashedBorder(Color.BLUE));
currentImageLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
Dimension defaultLabelSize = new Dimension(150,150); // was expecting this to enlarge the label.
currentImageLabel.setPreferredSize(defaultLabelSize);
currentImageLabel.setSize(defaultLabelSize);
JButton clearButton = new JButton("Clear");
clearButton.setAlignmentX(Component.CENTER_ALIGNMENT);
clearButton.setBorder(BorderFactory.createLineBorder(Color.GREEN));
currentImagePanel.add(currentImageLabel);
currentImagePanel.add(createStandardSpace());
currentImagePanel.add(clearButton);
currentImagePanel.setBorder(BorderFactory.createLineBorder(Color.ORANGE));
return currentImagePanel;
}
}
}
I would like the currentImageLabel to be a standard size; I intend for it to get different images put into it during the program, and want it to get these without changing size. My idea was to set a size and preferred size and then scale the images I put there to that size.
However, the defaultLabelSize doesn't have the effect I thought it would. The label goes into a boxLayout panel; it is added, then a rigid space, then a button. I expected the label to be the default size, not shrunk to min allowed. I've put in colored borders to try to understand better what's happening; it appears that the preferred size is honored for the overall boxLayout panel, but not for the placement of the button below the label. EDIT: In other words, I want the button below the label to be placed below the label when the label is forced to be bigger. But the size I put on the label doesn't seem to work.
What do I need to do to fix the size of currentImageLabel?
Not 100% why the label is only sized to the text and not the (hard coded) preferred size. I have not been able to duplicate this behaviour using other combinations of panels and layout managers.
You are using pack so all components should be sized to their preferred sizes.
Dimension defaultLabelSize = new Dimension(150,150); // was expecting this to enlarge the label.
currentImageLabel.setPreferredSize(defaultLabelSize);
currentImageLabel.setSize(defaultLabelSize);
A few comments:
Setting the size will never work. The layout manager will always override the size/location based on the rules of the layout manager.
The layout manager can use (or ignore) the preferred, minimum and maximum sizes of a component. In the case of the BoxLayout is does attempt to use the preferred size but will respect the minimum and maximum sizes (depending on the available space in the parent panel).
What do I need to do to fix the size of currentImageLabel?
So, to achieve your desired goal of a fixed preferred size for the JLabel you can use:
Dimension defaultLabelSize = new Dimension(150,150); // was expecting this to enlarge the label.
currentImageLabel.setPreferredSize(defaultLabelSize);
currentImageLabel.setMinimumSize(defaultLabelSize);
currentImageLabel.setMaximumSize(defaultLabelSize);
//currentImageLabel.setSize(defaultLabelSize);
Edit:
was looking for why this doesn't seem to work
For further clarification, change your original code to:
currentImageLabel.setPreferredSize(defaultLabelSize);
System.out.println(currentImageLabel.getPreferredSize());
System.out.println(currentImageLabel.getMinimumSize());
System.out.println(currentImageLabel.getMaximumSize());
You will see the min/max sizes of the label are not affected.
From point 2 above you will see that the BoxLayout is respecting the maximum size.
Therefore, by also overriding the maximum size, you allow the label to be displayed at is preferred size.
However, when you calculate the preferred size of the "currentImagePanel" the ( hardcoded) preferred size of the label is used in the preferred size calculation of the panel, so that panel is displayed at the preferred size.
Another note. The "leftContainingPanel" is not needed. You can just add the "leftPanel" to the BorderLayout.WEST, since the BorderLayout will respect the width of the component you add.

Java. Prevent enlarging of Button

How to prevent Button from UpSize? I use a vertical Box with 2 lines, in first line → horizontal Box with many controls, in second line → Button, but button very enlarged, how to prevent this irritating behavior?
I was tried to set maximum size of button, it is works, but How to calculate this size correctly?
Sorry, I bad speak English.
Example:
import java.awt.Button;
import java.awt.Frame;
import java.awt.Label;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JProgressBar;
import javax.swing.JSpinner;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
public class TEST{
public static void main(String[] args){
Frame mainWindow = new Frame("hello");
Box vertBox = new Box(BoxLayout.Y_AXIS);
mainWindow.add(vertBox);
Box firstLine = new Box(BoxLayout.X_AXIS);
vertBox.add(firstLine);
SpinnerModel sm = new SpinnerNumberModel(100, 0, 200, 1);
for(int i = 0; i < 10; i++){
firstLine.add(new JSpinner(sm));
firstLine.add(new Label("Hello"));
}
Box secondLine = new Box(BoxLayout.X_AXIS);
vertBox.add(secondLine);
secondLine.add(new JProgressBar());
secondLine.add(new Button("RUN-THIS"));
mainWindow.pack();
mainWindow.setVisible(true);
}
}
Button, but button very enlarged, how to prevent this irritating behavior?
Don't use AWT components in a Swing application!
Swing components start with "J". You should be using JFrame, JLabel, JButton. This will fix your problem. A JButton will automatically calculate the maximum size equal to the preferred size and BoxLayout will respect this.
Also, class name should only start with a single upper case character. "TEST" should be "Test".

JTextField margin doesnt work with border

I have a JTextField and i want to setMargin. But when i set any border, it doesn' t properly work. It' s margin function doesn't work.
This is my code;
import java.awt.Color;
import java.awt.Insets;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
public class ImageField {
public static void main(String[] args) throws IOException {
JTextField textField = new JTextField();
textField.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
textField.setMargin(new Insets(0, 20, 0, 0));
JOptionPane.showMessageDialog(null, textField, "",
JOptionPane.PLAIN_MESSAGE);
}
}
If i commant this line, it works
//textField.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
Margin have some problem with Border, to work around the problem you can try using a CompoundBorder setting an EmptyBorder as inner border and the desired border (lineBorder in your case) as outer border.
Something like this should work :
Border line = BorderFactory.createLineBorder(Color.DARK_GRAY);
Border empty = new EmptyBorder(0, 20, 0, 0);
CompoundBorder border = new CompoundBorder(line, empty);
textField.setBorder(border);
Read it from the JavaDoc.
Sets margin space between the text component's border and its text. The text component's default Border object will use this value to create the proper margin. However, if a non-default border is set on the text component, it is that Border object's responsibility to create the appropriate margin space (else this property will effectively be ignored). This causes a redraw of the component. A PropertyChange event ("margin") is sent to all listeners.
You are probably looking for a compound border:
BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.DARK_GRAY),
BorderFactory.createEmptyBorder(0, 20, 0, 0));

How can I resize the background of a JLabel or apply top and bottom borders only?

I have something that looks like this:
As you can see, "Blambo" is a JLabel with an opaque, red background. The label sits on top of a little grey bar that has a single pixel blackish border all the way around it. I'd like my red warning to match the bar it's sitting on more nicely, i.e. I either need to make it two pixels shorter and move it down a pixel or I need to apply the same single pixel border to the top and bottom only. Of those two, the first is probably preferable as this piece of code is shared with other labels.
The code in question:
bgColor = Color.red;
textColor = Color.white;
setBackground(bgColor);
setOpaque(true);
// This line merely adds some padding on the left
setBorder(Global.border_left_margin);
setForeground(textColor);
setFont(font);
super.paint(g);
That border is defined thusly:
public static Border border_left_margin = new EmptyBorder(0,6,0,0);
You can create a new border for the label like this :
EDIT: after seeing your comment in another answer i created a compound border which gives you what you want.
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.border.Border;
/**
* #author Savvas Dalkitsis
*/
public class Test1 {
public static void main(String[] args) {
JFrame f = new JFrame("Test");
JLabel c = new JLabel("Hello");
Border b = BorderFactory.createCompoundBorder(
BorderFactory.createMatteBorder(2, 0, 2, 0, Color.black),
BorderFactory.createEmptyBorder(0, 100, 0, 0));
c.setBorder(b);
f.getContentPane().add(c);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
Without seeing your code, it's hard to know what you already know or have tried.
You explicitly set the border of a component like so:
myLabel.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.BLACK));
Now, JLabels are rather complicated beasts, with a lot of code for measuring its (optional) icon, and planning its layout around lots of general cases. You might be better off subclassing JComponent to write your own, very simple label.

Categories

Resources