JTextField margin doesnt work with border - java

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

Related

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.

Need help in understanding the value returned by JButton's getInsets() method

I'm having a difficult time in understanding the return value of JButton's getInsets() method. On reading the documentation, I got that the getInsets() method returns the insets of the button's border (if a border is set on the button), which specifies the amount of space the border needs to draw itself.
However, on executing the following code:
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ButtonMarginInsets {
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.setTitle("Test Frame");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
JButton button = new JButton();
button.setText("Test Button");
System.out.println("Button Border Insets " + button.getBorder().getBorderInsets(button));
button.setMargin(new Insets(100, 10, 10, 10));
System.out.println("Button Insets " + button.getInsets());
contentPane.add(button);
frame.setContentPane(contentPane);
frame.pack();
frame.setVisible(true);
}
}
I'm getting the following console output:
Button Border Insets java.awt.Insets[top=5,left=17,bottom=5,right=17]
Button Insets java.awt.Insets[top=103,left=13,bottom=13,right=13]
and the following frame:
Frame Image
My questions are:
How the top, left, bottom, right values specify the amount of space
the border needs to draw itself?
Why these insets change on setting the margin?
Okay, first things first. Both your calls to button.getInsets() and getBorderInsets(button) are identical, as you have seen in the documentation, and confirmed by the source (internally, getInsets() just calls getBorderInsets(this) anyway).
Now that that's out of the way, by default a JButton is decorated with a CompoundBorder. If you look at the source, you can see that the CompoundBorder used for buttons consists of:
An outside border of type BasicBorders.ButtonBorder, and
An inside border of type MarginBorder.
The MarginBorder is probably your point of interest here. It has an override for getBorderInsets() that returns the component's margins.
So, in conclusion, a JButton's border is actually composite of TWO borders. The actual bounding lines outside (that you traditionally would think as a 'border', making it look 3d), plus a margin border inside. So when you do a setMargin(), you are also affecting the inside part of your compound border.
This explains your result of:
Button Insets java.awt.Insets[top=103,left=13,bottom=13,right=13]
The outside lines are 3px wide each, and your margin is (100,10,10,10) giving you the above total border inset.
I think you do this using the components insets. So call something like:
Insets insets = component.getInsets();
insets.set(top, left, bottom, right);
You should do this after setting the border on the component.
An Insets is a simple class that contains 4 fields: top, left, bottom
and right. Insets are used to describe the padding surrounding a
component. Every Border in Swing is expected to return an Insets
object describing how much padding to add to the component for the
Border to render correctly.
Custom Swing Component Development Tip: Insets Matter

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

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

Why does the JTable not show the Jtable heading even when added to JScrollPane?

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.TableColumn;
import java.awt.*;
import static java.awt.GraphicsDevice.WindowTranslucency.*;
import java.awt.Checkbox;
import java.awt.Paint;
import java.awt.Toolkit;
import java.awt.event.*;
public class Main extends JPanel {
static Object [][] Services = {{"Google.exe","Chickeaen.exe","Crp.exe"}};
static String [] ColNames = {"Processes:","Crolly:","Haler:"};
static JFrame Fram = new JFrame();
static JTextField CBox = new JTextField();
static JTable Tabs = new JTable(Services,ColNames);
JScrollPane ScrollArea = new JScrollPane();
static JButton ExitB = new JButton();
Dimension ScreenSize = new Dimension(Toolkit.getDefaultToolkit().getScreenSize());
Border BlackLineB = BorderFactory.createLineBorder(new Color(50,50,50));
public Main() {
Fram.setTitle("Jared Console");
Fram.setUndecorated(true);
Fram.setVisible(true);
Fram.setDefaultCloseOperation(Fram.EXIT_ON_CLOSE);
Fram.setResizable(false);
Fram.setSize((int)Math.round(ScreenSize.getWidth()*0.45),(int)Math.round(ScreenSize.getHeight()*0.33));
Fram.setBackground(new Color(0,0,0,150));
Fram.add(this);
CBox.setSize((int)Math.round(Fram.getWidth()*0.80),(int)Math.round(Fram.getHeight()*0.25));
CBox.setBackground(new Color(255,255,255));
CBox.setBorder(BorderFactory.createCompoundBorder(BlackLineB,BorderFactory.createEmptyBorder(0,20,0,0)));
CBox.setLocation((int)Math.round(Fram.getWidth()*0.1),(int)Math.round(Fram.getHeight()*0.70));
CBox.setFont(new Font("Arial",Font.BOLD,20));
CBox.setVisible(true);
ScrollArea.setSize((int)Math.round(Fram.getWidth()*0.80),(int)Math.round(Fram.getHeight()*0.50));
ScrollArea.setLocation((int)Math.round(Fram.getWidth()*0.10),(int)Math.round(Fram.getHeight()*0.10));
ScrollArea.setBorder(BlackLineB);
ScrollArea.setLayout(null);
ScrollArea.setVisible(true);
Tabs.setSize((int)Math.round(Fram.getWidth()*0.995),(int)Math.round(Fram.getHeight()*0.995));
Tabs.setLocation((int)Math.round(Fram.getWidth()*0.003),(int)Math.round(Fram.getHeight()*0.005));
Tabs.setFillsViewportHeight(true);
Tabs.setBackground(new Color(255,255,255));
this.add(CBox);
this.add(Tabs);
this.add(ExitB);
ScrollArea.add(Tabs);
this.add(ScrollArea);
this.setBorder(BorderFactory.createLineBorder(new Color(50,50,50),5));
this.setLayout(null);
this.setBackground(new Color(0,0,0));
this.setVisible(true);
}
public void paintComponent(Graphics Gla) {
Paint Plat = new GradientPaint(0f, 0f, new Color(0, 40, 0, 0), 0.0f, Fram.getHeight(), new Color(0, 0, 0, 150), true); //Made 200 equal to Fram Background Alpha.
Graphics2D Quo = (Graphics2D)Gla;
Quo.setPaint(Plat);
Quo.fillRect(0, 0, Fram.getWidth(), Fram.getHeight());
}
public static void main(String[] args) {
Main CScreen = new Main();
GraphicsEnvironment GE = GraphicsEnvironment.getLocalGraphicsEnvironment(); // Have to study lines 57,58 and 59
GraphicsDevice GD = GE.getDefaultScreenDevice();
boolean CheckTransL = GD.isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT);
if (!CheckTransL) {
System.out.println("PERPIXEL TRANSLUCENT NOT SUPPORTED - LOL UPDATESCRUB!");
System.exit(0);
};
}
}
Why does the JTable not show the Jtable heading even when added to JScrollPane?
Also the Console shows a error message at first then quickly goes away and launches the program? So yea I'd like to know what's wrong with this and also can you can note me of some bad habits in this program such as the way it's being typed.
Problems
null layout. Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify. See Laying Out Components Within a Container for more details
Over use of static. static is not your friend and you should avoid using it. It is not a cross object communication mechanism and over use like this will burn you
You don't actually wrap the JTable in JScrollPane
Breaking the paint chain by not calling super.paintComponent, this is going to produce a series of wonderful paint artifacts. See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing
You might like to have a read through Code Conventions for the Java TM Programming Language, it will make it easier for people to read your code and for you to read others
All interactions, creations and modifications to the UI should be done from within the context of the Event Dispatching Event, to reduce the risk of potential race conditions, dead locks and rendering artifacts. See Initial Threads for more details
Toolkit.getDefaultToolkit().getScreenSize() is a bad indicator for the viewable space of a screen, it does not take into account OS specific elements, like the dock or task bar, which could have your application appearing under them (and I really, really, REALLY hate it when that happens). Use appropriate layout managers and pack to pack the window around the content. You can then use JFrame#setLocationRelativeTo and pass it null and it will center the frame in the screen
JScrollPane issue...
The simply solution would be to use JScrollPane's constructor to pass it the reference of the JTable...
static JTable Tabs = new JTable(Services,ColNames);
JScrollPane ScrollArea = new JScrollPane(Tabs);
But, then you do this later in your code...
this.add(Tabs);
This will remove the table from the scroll pane to add it to you panel, as a component can only have a single parent.
Another option would be to specifiy the scroll pane's viewport's view component...
this.add(CBox);
//this.add(Tabs);
this.add(ExitB);
//ScrollArea.add(Tabs);
ScrollArea.setViewportView(Tabs);
this.add(ScrollArea);
You should never add components directly to a scroll pane (or it's underlying viewport), they have their own internal layout management functionality going on. Instead, you need to supply the component as the "view" to the JViewport
Take a look at How to Use Scroll Panes for more details.
First of all you should add a JTable to the ViewPort of the a JScrollPane in order to JTableHeader could be visible.
After that you should not add your JTable to both the JScrollPane and also the underlying container. You should:
add the JTable to the ViewPort of the JScrollPane.
add the JScrollPane to the underlying container.
and remove the line that add the JTable to the container explicitly.
Good Luck.

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