Change JTextField scrollpane text padding/offset by some pixels - java

I'm trying to align the position (start + end) of text inside a JTextField, but i haven't been able to find and/or understand how to do this...
example of what is wrong and what i'm looking for:
The setHorizontalAlignment method only allows this..:
•JTextField.LEFT
•JTextField.CENTER
•JTextField.RIGHT
•JTextField.LEADING
•JTextField.TRAILING
With android projects, this is so easy...but for the sake of me, i can't figure this one out, when doing a swing project...How can this be done?
EDIT:
I've been able to sort this one, by using double (aka layered) JTextFields. emptyborder(), although easier code wise, removes all JTextField frame borders, leaving you with a big empty square, which, for an input box, it's not a good idea...here's a picture and some code sample:
JTextField Padding Working example
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
public class TextBoxOffset {
public static void main(String[] a) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
frame.setSize(300, 300);
frame.setVisible(true);
JLabel label1 = new JLabel("JTextField, using CreateEmptyBorder");
label1.setHorizontalAlignment(SwingConstants.CENTER);
label1.setFont(new Font("Tahoma", Font.PLAIN, 11));
label1.setBounds(0, 125, 284, 23);
frame.getContentPane().add(label1);
//Creates a new JTextField with a emptyborder
JTextField emptyborder = new JTextField();
emptyborder.setBounds(22, 164, 250, 43);
emptyborder.setBorder(new EmptyBorder(5, 17, 5, 15));
frame.getContentPane().add(emptyborder);
JLabel label2 = new JLabel("JTextField, using double (layered) JTextFields");
label2.setFont(new Font("Tahoma", Font.PLAIN, 11));
label2.setHorizontalAlignment(SwingConstants.CENTER);
label2.setBounds(0, 22, 284, 23);
frame.getContentPane().add(label2);
// Creates a new input field, layered above the (disabled) JTextField background object
JTextField inputbox = new JTextField();
inputbox.setBounds(40, 61, 216, 31);
inputbox.setBorder(null);
frame.getContentPane().add(inputbox);
// Creates a border for the input text field that will serve as a background
JTextField bg = new JTextField();
bg.setBounds(22, 56, 250, 43);
frame.getContentPane().add(bg);
bg.setEnabled(false);
// Grab the overlayed inputbox focus
inputbox.requestFocusInWindow();
}
}
If anyone knows a better, easier way of doing this, meaning, control the text padding on all sides (TOP,LEFT,BOTTOM,RIGHT), inside a JTextField (or any other field for what matters (e.g.: control the position of the text inside a button) without using double JTextFields, please post a reply.

I think you want to add a Border to your text field:
textField.add( new EmptyBorder(...) );
Read the section from the Swing tutorial on How to Use Borders for more information and examples.
i can't figure this one out, when doing a swing project.
Keep the link to the Swing tutorial handy for Swing basics.
Edit:
Oops, I forgot a JTextField also has a special method to control this:
textField.setInsets(...);
So you don't need the CompoundBorder, however so you still be aware of the flexibility provided by a CompoundBorder.

I think the easiest way to achieve this is by using :
textField.setMargin(new Insets(...));
I was looking for the same kind of result and this literally made my day, I hope it'll help others too.

Related

JButton over JScrollPane

I have such piece of code which shoud add button over JTextArea placed in JScrollPane. Button isn't inside scroll pane!
JScrollPane scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setBounds(10, 340, 375, 242);
contentPane.add(scrollPane);
JButton btnClean = new JButton();
btnClean.setBounds(340, 341, 26, 23);
contentPane.add(btnClean);
taLog = new JTextArea();
taLog.setEditable(false);
taLog.setLineWrap(true);
taLog.setFont(new Font("Arial", Font.PLAIN, 12));
scrollPane.setViewportView(taLog);
epInfo = new JEditorPane();
epInfo.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
epInfo.setFont(new Font("Tahoma", Font.PLAIN, 12));
epInfo.setContentType("text/html");
epInfo.setEditable(false);
epInfo.setBackground(null);
epInfo.setBorder(null);
epInfo.setBounds(10, 241, 375, 37);
setInfoText();
contentPane.add(epInfo);
Problem is whenever JTextArea changes its value button is not refreshed - it just dissapears - until I will drag mouse cursor over it. I suppose then some repaint() is launched.
I figured out I can add DocumentListener to JTextArea and there manually refresh button but it works until scroll bar appears in JScrollPane.
I can also use
scrollPane.getViewport().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e)
{}});
but it is invoked many times and all those refreshes are not neccesary.
Is there any reasonable (and efficient) way to check if JScrollPane changed?
Null layout is useful in this case because main window is fixed
No it is not useful.
Any time you code uses random numbers (ie to set the size/location) of components) the code is not easily maintainable.
Also I use WindowBuilder
Code generated by an IDE is not maintainable in another IDE.
Learn to use layout managers. The point of using layout managers is to avoid hard coding of numbers and to make the code maintainable in any environment.
Problem is whenever JTextArea changes its value button is not refreshed
contentPane.add(scrollPane);
...
contentPane.add(btnClean);
Swing is designed to display components in two dimension when added to the same container.
If you want components displayed in two dimension then you need to have a parent / child relationship:
- content pane
- text area
button
So the code should be something like:
textArea.setLayout( new FlowLayout(FlowLayout.RIGHT) );
//contentPane.add(btnClean);
textArea.add(btnClean);
Note: you can configure the FlowLayout to remove the spacing on the top and right.
The problem with this is that the button will cover any text that displayed in the text area.
So the better solution is to make the button external to the text area.

Add Scroll bar in JEditorPane, setLayout null

I can't add scroll bar on EditorPane.
private JEditorPane editorPane;
private JScrollPane scrollpane;
Container :
Container c = getContentPane();
c.setLayout(null);
setBounds(100, 100, 450, 300);
editorPane = new JEditorPane();
editorPane.setBounds(0, 54, 434, 208);
scrollpane = new JScrollPane(editorPane);
scrollpane.setPreferredSize(new Dimension(350, 110));
c.add(scrollpane);
..
..
Nothing added
You're shooting yourself in the foot here:
editorPane.setBounds(0, 54, 434, 208);
By setting the editorPane's absolute size, you prevent it from expanding when it needs to do so, preventing the JScrollBars from having to show.
Solution: don't do this. And yeah, avoid using null layouts. They'll bite you, as you're finding out. Set the width using CSS
getContentPane().setLayout(null);
This means "I give a damn on the help of others because I know better that anyone else how to layout a GUI!"
So this is where you are.
I'd recomment to go through the tutorials and learn how to build GUIs using LayoutManagers.

How do I use GroupLayout properly to move components/panels?

First off, I apologize for the long post, I just wanted to be clear and show you my issue so it can better be resolved.
I have the following code:
JPanel panelCard = new JPanel();
String[] cards = {"VISA", "MASTERCARD", "DISCOVER"};
JComboBox cardType = new JComboBox(cards);
panelCard.add(cardType);
GroupLayout layout2 = new GroupLayout(panelCCInfo);
panelCCInfo.setLayout(layout2);
layout2.setAutoCreateGaps(true);
layout2.setAutoCreateContainerGaps(true);
GroupLayout.SequentialGroup hGroup2 = layout2.createSequentialGroup();
hGroup2.addGroup(layout2.createParallelGroup()
.addComponent(cardName)
.addComponent(cardNumber)
.addComponent(expDate));
hGroup2.addGroup(layout2.createParallelGroup()
.addComponent(cardNameField)
.addComponent(cardNumberField)
.addComponent(expDateField));
hGroup2.addGroup(layout2.createParallelGroup()
.addComponent(panelCard));
layout2.setHorizontalGroup(hGroup2);
GroupLayout.SequentialGroup vGroup2 = layout2.createSequentialGroup();
vGroup2.addGroup(layout2.createParallelGroup(Alignment.BASELINE)
.addComponent(cardName)
.addComponent(cardNameField));
vGroup2.addGroup(layout2.createParallelGroup(Alignment.BASELINE)
.addComponent(cardNumber)
.addComponent(cardNumberField));
vGroup2.addGroup(layout2.createParallelGroup(Alignment.BASELINE)
.addComponent(expDate)
.addComponent(expDateField)
.addComponent(panelCard));
layout2.setVerticalGroup(vGroup2);
panelCheckout.add(panelCCInfo, BorderLayout.CENTER);
And when I run it, it displays this window:
But I would like to achieve this:
The problem occurs when I try to add a 3rd vertical group with the panelCard in
the code:
hGroup2.addGroup(layout2.createParallelGroup().addComponent(panelCard));
It would seem that the 2 text field are cut off because of this, but I dont want it cut off.
What can I do to achieve the 2nd picture?
Thanks so much!
Here is how I'd do it:
import javax.swing.*;
import static javax.swing.GroupLayout.*;
import static javax.swing.GroupLayout.Alignment.*;
public class Mastercard {
public static void main(String[] args) {
JLabel lblCardHolder = new JLabel("Card holder");
JTextField tfCardHolder = new JTextField();
JLabel lblCardNumber = new JLabel("Card number");
JTextField tfCardNumber = new JTextField();
JLabel lblExpirationDate = new JLabel("Expiration date");
JTextField tfExpirationDate = new JTextField();
JComboBox combo = new JComboBox(new String[]{"Visa"});
JPanel panel = new JPanel();
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
layout.setAutoCreateContainerGaps(true);
layout.setAutoCreateGaps(true);
layout.setHorizontalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup()
.addComponent(lblCardHolder)
.addComponent(lblCardNumber)
.addComponent(lblExpirationDate))
.addGroup(layout.createParallelGroup()
.addComponent(tfCardHolder)
.addComponent(tfCardNumber)
.addGroup(layout.createSequentialGroup()
.addComponent(tfExpirationDate)
.addComponent(combo, DEFAULT_SIZE, 100, PREFERRED_SIZE))));
layout.setVerticalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(BASELINE)
.addComponent(lblCardHolder)
.addComponent(tfCardHolder))
.addGroup(layout.createParallelGroup(BASELINE)
.addComponent(lblCardNumber)
.addComponent(tfCardNumber))
.addGroup(layout.createParallelGroup(BASELINE)
.addComponent(lblExpirationDate)
.addComponent(tfExpirationDate)
.addComponent(combo)));
JFrame f = new JFrame();
f.setContentPane(panel);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
This is the result:
GroupLayout is a powerful constraint-based layout manager. When writing a group layout, you basically just describe whether components (or group of components) should be placed in sequence or in parallel. This description is done independently for the horizontal and vertical axis.
Horizontally, there are 2 groups in sequence : the labels, and the rest. The rest is composed of 3 parallel things : 2 textfields, and a sequence of tfExpirationDate and combo. This is, in plain english, what the layout.setHorizontalGroup(... describes.
Vertically, there are 3 groups in sequence : one composed of a label and a textfield in parallel, another composed of a label and a textfield in parallel, and yet another composed of a label, a textfield and a combobox in parallel. This is what layout.setVerticalGroup(... describes.
The nesting of these groups and components is important, this is why I indented everything correctly.
I find this approach of describing constraints quite easy to reason about, using only 2 concepts : sequential groups and parallel groups. Compared to grid-based layouts, it has the advantage that you don't break everything each time you want to add or move a component.
Ok I figured it out using a complex combination of GridBagLayout and BorderLayout
what a mess.... :)

Java not rendering components after adding a JTextfield

I know this question was asked before, but there was no answer to it.
In Java, when I am adding components to the frame, all the elements after adding a JTextField are not rendered when the application is initialized. They are rendered after you refresh the screen e.g. minimize and maximize the screen. In the following only the textfield is rendered. It looks like some Java rendering issue.
My code is as follows:
private void initialize() {
frame = new JFrame();
frame.setVisible(true);
frame.setBounds(100, 100, 569, 321);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
txtGenerationRate = new JTextField();
txtGenerationRate.setBounds(322, 29, 86, 20);
frame.getContentPane().add(txtGenerationRate);
txtGenerationRate.setColumns(10);
lblAmountOfSolarPanelsText = new JLabel("Amount of solar panels:");
lblAmountOfSolarPanelsText.setBounds(10, 57, 159, 14);
frame.getContentPane().add(lblAmountOfSolarPanelsText);
frame.setVisible(true); // added it for the second time, just to make sure
}
Can anyone help, please?
Piotr
At first, you should definitely read about how to use layouts: http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html
The second thing, you should set your frame visible after all components are added, if you do not, you have to call repaint().
Try putting this at the bottom of the initialize method
frame.setVisible(true);
frame.setBounds(100, 100, 569, 321);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
you could also try frame.revalidate(); and frame.repaint();
This seems working for me, I see both label and text field when the window first appears. The label text does not fit into label so is truncated, but apart that everything looks as expected. Maybe the wrong fragment has been removed from the code while trying to simplify it?

Swing - how to mix JTextField and JTextAreas and have same visual appearance?

I am using miglayout to create a form in which there are JTextFields (short input answers) as well as JTextAreas (Longer answers). The problem is twofold.
The border placed around a Scrollpane wrapped text area does not match that of a Text Field.
The width and placement of the textarea/textfield differ, causing them not to line up correctly.
alt text http://grab.by/3O0V
After changing from right/left to right/fill:
alt text http://grab.by/3RMk
You can see that the bounds line up, but that there are still gaps. I tried setting novisualpadding but this did not fix it.
Source code:
package test2;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import net.miginfocom.swing.MigLayout;
public class Test extends JPanel {
private static final int NUM_CHARACTERS_WIDTH = 20;
private static final int NUM_ROWS = 5;
public Test() {
setLayout(new MigLayout(
"wrap 2",
// Align text labels on the so their right edge meets left edge of the text fields
"[right][left]"
));
add(new JLabel("Text field:"));
add(new JTextField(NUM_CHARACTERS_WIDTH));
add(new JLabel("No scrollpane text area:"));
add(new JTextArea(NUM_ROWS, NUM_CHARACTERS_WIDTH));
add(new JLabel("Scrollpane text area:"));
add(new JScrollPane(new JTextArea(NUM_ROWS, NUM_CHARACTERS_WIDTH)));
add(new JLabel("Text field:"));
add(new JTextField(NUM_CHARACTERS_WIDTH));
}
public static void main(String[] args) {
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new Test();
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
What's the preferred way to mix and match jtextfield and jtextareas, while still maintaining visual harmony? I notice now that the text field has a blue highlight around it when focus is in it, as opposed to the text area... another source of visual discontinuity.
I know this question is pretty old, but to get the border for a TextArea to match that of a TextField:
(myTextArea).setBorder(new JTextField().getBorder());
That should give a border to your TextArea like the one around a TextField.
Not sure how you can fix your border problem but to fix your layout situation I would just use springlayout. Springlayout is just a way to better layout your elements within the JPanel. You can find out more about it Java Sun Tutorial
Specifically you use it by setting where you want your North, South, West and East borders of each element. To do this you would have to first take your label calls out of the add so each one can be named. So instead of:
add(new JLabel("Text field:"));
Do:
JLabel myLabelName = new JLabel("Text field:");
add(myLabelName);
For each of your elements (JLabels, JTextAreas and JTextField). Once this is done you can easily set the layout.
Springlayout layout = new SpringLayout();
setLayout(layout);
Then for each of the elements you have to set any of the borders you want. They have to be in the specific order South, the North, West then East. Though you don't have to use all four borders if you don't want to. Here is an example on how to set your first text area, the one on the top.
layout.putConstraint(SpringLayout.NORTH, FirstTextAreaName, 10, SpringLayout.NORTH, this);
layout.putConstraint(SpringLayout.WEST, FirstTextAreaName, this.getWidth()/2, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.EAST, FirstTextAreaName, -10, SpringLayout.EAST, this);
This example doesn't set the south of the text area but if you did want to it would have to be first. The first line sets the north side of the text area to be 10 pixels away from the top. When setting the other areas you but the previous (above) areas name instead of this and say it is 10 pixels away from the south of the previous one:
layout.putConstraint(SpringLayout.NORTH, SecondTextAreaName, 10, SpringLayout.SOUTH, FirstTextAreaName);
The second line in the above example sets the east side of the text area to start halfway through your main panel. The last, third, line sets the east side of the text area to be 10 pixels from the east side of your main panel.
I know that MiGLAyout (which I love, BTW) has the ability to do special handling for visual alignment vs strict pixel alignment. You may be running into this... The 'al' unit identifier is used for this, but I haven't had to use it so can't provide examples. It would probably be worth downloading the MiG sample project and see if they have the same alignment issue (I'm sure they have panels similar to yours).
For what it's worth, we mix text fields and areas in the same panel quite frequently and don't run into this... We do have to set the border of the scroll pane to be the same as the border of the text field as suggested by Noel Ang.
Also, instead of specifying constraints in the layout constructor, we generally specify them as we add each component - not sure if that makes a difference or not...
For the layout problem, try a columnConstraints value of [right][fill] instead of [right][left].
For the other issue, this appears to be a look-and-feel inconsistency. I ran your code in Windows, and the differences are there too, but less flagrant. My suggestion would be to set identifical borders explicitly for text fields and text areas.
setLayout(new MigLayout(
"wrap 2",
"[right][fill]"
));
JTextField textField;
JScrollPane scrollPane;
add(new JLabel("Text field:"));
textField = new JTextField(NUM_CHARACTERS_WIDTH);
textField.setBorder( new EtchedBorder( EtchedBorder.LOWERED ) );
add(textField);
add(new JLabel("No scrollpane text area:"));
add(new JTextArea(NUM_ROWS, NUM_CHARACTERS_WIDTH));
add(new JLabel("Scrollpane text area:"));
scrollPane = new JScrollPane(new JTextArea(NUM_ROWS, NUM_CHARACTERS_WIDTH));
scrollPane.setBorder( new EtchedBorder( EtchedBorder.LOWERED ) );
add(scrollPane);
add(new JLabel("Text field:"));
textField = new JTextField(NUM_CHARACTERS_WIDTH);
textField.setBorder( new EtchedBorder( EtchedBorder.LOWERED ) );
add(textField);
If you can't get MigLayout to align your components, considering using java.awt.GridBagLayout:
import static java.awt.GridBagConstraints.*;
setLayout( new GridBagLayout() );
GridBagConstraints leftCons = new GridBagConstraints();
leftCons.anchor = NORTHEAST;
leftCons.fill = NONE;
leftCons.weightx = 1.0;
leftCons.gridy = RELATIVE;
leftCons.gridx = 0;
leftCons.insets = new Insets( 4, 8, 4, 8 );
GridBagConstraints rightCons = new GridBagConstraints();
rightCons.anchor = NORTHWEST;
rightCons.fill = HORIZONTAL;
rightCons.weightx = 1.0;
rightCons.gridy = RELATIVE;
rightCons.gridx = 1;
rightCons.insets = leftCons.insets;
add(new JLabel("Text field:"), leftCons);
add(new JTextField(NUM_CHARACTERS_WIDTH), rightCons);
add(new JLabel("No scrollpane text area:"), leftCons);
add(new JTextArea(NUM_ROWS, NUM_CHARACTERS_WIDTH), rightCons);
add(new JLabel("Scrollpane text area:"), leftCons);
add(new JScrollPane(new JTextArea(NUM_ROWS, NUM_CHARACTERS_WIDTH)), rightCons);
add(new JLabel("Text field:"), leftCons);
add(new JTextField(NUM_CHARACTERS_WIDTH), rightCons);
First off +1 for screen shots.
Since you are using Mac, did you try Quaqua Look And Feel? It renders the textboxes/areas properly.
The answer is that MiG Layout folks are working on a fix for their next version.
Hello,
Apple has a nasty habbit of compensating by default and not let the developer decide. This is such a case where they have added a border to make it more visually like OS X. This should be the choice of the layout manager...
MigLayout can compensate for visual bounds like this but it is only done for JTabbedPane in Windows XP. I'm not sure it can be done 100% good in OS X though. I'll have to check. We don't want the text field to just grow into the bounds.
I have added this to the todo list for the next version.

Categories