Increase JTextField height with GridBagLayout - java

I would like to have in my app text fields that span multiple rows. It seems to be no problem to get the desired result in Eclipse design viewer using GridBagLayout:
However, when I export it to jar, I see the window like this:
My code:
import java.awt.Color;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JTextField;
#SuppressWarnings("serial")
public class TestFrame extends JFrame {
GridBagConstraints constraints;
JTextField text0;
public TestFrame() {
super("Test window");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
Container container = getContentPane();
container.setLayout(new GridBagLayout());
container.setBackground(new Color(240,240,240));
JTextField editableTextField;
editableTextField = new JTextField("Enter text here");
constraints = new GridBagConstraints();
constraints.fill=GridBagConstraints.BOTH;
constraints.gridheight=2;
constraints.gridx=0;
constraints.gridy=0;
container.add(editableTextField, constraints);
pack();
}
public static void main(String args[]) {
new TestFrame();
}
}
I am using Eclipse 4.4.1 under MacOS 10.9.3.
Can anyone explain me, where the difference in view comes from and how can I get the proper text field height in jar?

how can I get the proper text field height in
You don't do anything. The Swing layout managers will determine the proper height for the text field based on the font of the text field.
In your case you only have a single component added to the frame so you can't tell the text field to have a gridHeight of 2 because there is only one row. That constraint is used when you have multiple rows of components in the frame. Then you can specify that a component spans two rows.
If you want extra space around the text field than you can change the Border:
JTextField textField = new JTextField(30);
Border empty = new EmptyBorder(10, 10, 10, 10);
Border compound = new CompoundBorder(textField.getBorder(), empty);
textField.setBorder(compound);
Read the section from the Swing tutorial on How to Use Borders for more information and examples.
The tutorial also has a section on How to Use GridBagLayout you should check out for more information about GridBagConstraints.

Related

How can i get rid of the blue highlight inside JCombobox?

The JCombobox's "content" window has this blue highlight that i don't know how to get rid of, please help.
Here is an example of the problem:
package example;
import java.awt.CardLayout;
import java.awt.Color;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(1);
frame.setSize(500, 500);
frame.setLayout(new CardLayout());
frame.setVisible(true);
JPanel panel=new JPanel();
panel.setLayout(null);
frame.add(panel);
String[] model = {"pres.", "PPS.", "P. inp.", "P. mais q."};
JComboBox combox;
combox = new JComboBox(model);
combox.setBounds(100, 100, 145, 30);
combox.setBackground(new Color(215, 211, 165));
combox.setFocusable(false);
panel.add(combox);
panel.updateUI();
}
}
The combo box is a complex components that uses multiple components internally. The UI determines how the components interact with one another.
For example change your code to the following:
JComboBox combox;
combox = new JComboBox(model);
combox.setBorder( new LineBorder(Color.YELLOW) );
BasicComboBoxRenderer renderer = new BasicComboBoxRenderer();
renderer.setBorder( new LineBorder(Color.RED) );
combox.setRenderer(renderer);
And you will notice that the blue highlight is not a border of the combo box or its render, implying there is another internal container we don't have access to.
If you really want to solve the problem then you will need to customize the MetalComboBoxUI class, which is never an easy task because many of the painting methods will be private. But take a look at the code of the class to see if it can be done.
Other issues with your code:
Don't use updateUI(). The method is invoked internally in Swing when the LAF is changed. You are not changing the LAF
Components should be added to the frame BEFORE the frame is visible. This will eliminate the need for the updateUI().

Layout - Relative to screensize

So I am a computer science student and I've finished my first year. I wanted to create a simple program and I realized that I am so tired of using no layout;
this.setLayout(null);
It is so tiresome to add bounds to every single component. Well, I have been using JPanel components and GridLayout a lot, which have made my work a bit easier. But I am tired of it.
I care very much about the look of the GUI I make and use almost half the time programming to make the GUI look good before I start adding the functionality of the code. By not using a layout and adding bounds I am forced to setResizable(false) because it looks bad if I change the size of the JFrame.
I've been searching a bit, and I know of BorderLayout, and FlowLayout, but I don't like them. Is there any Layout that keeps the relative size of the components with respect to the size of the window?
For example I want to make a simple program that looks like this: (Quick sketch in Photoshop)
I can easily make this with 3 panels, but as I said, if I change the size of the frame everything stays in place instead of being relative to the window-size.
Can you guys help me?
This design looks for me to fit the BorderLayout, where in the NORTH you have the values that changes the CENTER you have the main part, and the SOUTH you have the buttons.
Link to the Oracle Border Layout
You can apply this BorderLayout to the JFrame, then create 3 JPanels for each of the NORTH,CENTER and SOUTH sections. If you want to use responsive design for the components and panels, take a look at GridBagLayout which is much more flexible than the GridLayout
Layout management is a very complex problem, I don't think people really appreciate just how complex it really is.
No one layout is ever going to achieve everything your want, in most cases, you will need to resort to two or more layouts, especially as your requirements become more complex.
For example, the following is simply a BorderLayout at the base and the buttons on a JPanel using a FlowLayout
Which is achieved by using
JList listOfThings = new JList(...);
JTextField tf = new JTextField();
JButton add = new JButton("Add");
JButton delete = new JButton("Delete");
JButton go = new JButton("Go...");
JPanel buttons = new JPanel();
buttons.add(add);
buttons.add(delete);
buttons.add(go);
add(new BorderLayout());
add(tf, BorderLayout.NORTH);
add(new JScrollPane(listOfThings));
add(buttons, BorderLayout.SOUTH);
For more complex layouts, I would consider using something like GridBagLayout. You may also want to consider MigLayout as an alternative
Take a look at Laying Out Components Within a Container for more details about using layout managers
I'd like to use the combination of BorderLayout and BoxLayout. BorderLayout let me put the component based on their relative location's relation and BoxLayout let me manage the subtle distance ( create some white space). You can use component.setBorder(BorderFactory.createEmptyBorder(top, left, bottom, right)); to achieve this goal too.
Here is a demo and hope it can help you.
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class LayoutTest{
private JTextField jTextField;
public void createUI(){
JFrame frame = new JFrame("Layout Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
JPanel mainPanel = new JPanel();
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
mainPanel.add(new TextFieldPanel());
mainPanel.add(Box.createVerticalStrut(8));
mainPanel.add(new ListPanel());
mainPanel.add(Box.createVerticalStrut(8));
mainPanel.add(new ButtonPanel());
frame.add(mainPanel,BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
LayoutTest layoutTest = new LayoutTest();
layoutTest.createUI();
}
#SuppressWarnings("serial")
class TextFieldPanel extends JPanel{
public TextFieldPanel(){
setLayout(new BorderLayout());
jTextField = new JTextField();
jTextField.setEditable(false);
add(jTextField,BorderLayout.CENTER);
}
}
#SuppressWarnings("serial")
class ListPanel extends JPanel implements ListSelectionListener{
private JList<String> list;
public ListPanel(){
setLayout(new BorderLayout());
String stringArr[] = new String[30];
for (int i = 0; i < 30; i++) {
stringArr[i] = "JList :This line is item" + i;
}
list = new JList<String>(stringArr);
JScrollPane scrollPane = new JScrollPane(list);
add(scrollPane,BorderLayout.CENTER);
setBackground(new Color(211,211,211));
list.addListSelectionListener(this);
}
#Override
public void valueChanged(ListSelectionEvent e) {
// TODO Auto-generated method stub
jTextField.setText(list.getSelectedValue());
}
}
#SuppressWarnings("serial")
class ButtonPanel extends JPanel{
public ButtonPanel(){
JButton button1 = new JButton("Button1");
JButton button2 = new JButton("Button2");
JButton button3 = new JButton("Button3");
setLayout(new BorderLayout());
add(button1,BorderLayout.WEST);
add(button2,BorderLayout.CENTER);
add(button3,BorderLayout.EAST);
}
}
}
Here is the effect:
You can use BoxLayout for ButtonPanel if you don't want to let the button's size change.
#SuppressWarnings("serial")
class ButtonPanel extends JPanel{
public ButtonPanel(){
JButton button1 = new JButton("Button1");
JButton button2 = new JButton("Button2");
JButton button3 = new JButton("Button3");
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(button1);
add(Box.createHorizontalStrut(8));
add(button2);
add(Box.createHorizontalStrut(8));
add(button3);
}
}
And the effect is like this:
For more infomation about using BoxLayout to generate whitespace, you can refer to https://stackoverflow.com/a/22525005/3378204
Try GridBagLayout.
Your sketch is actually quite close to the one of the examples in the official tutorial.
HVLayout keeps the relative size of the components with respect to the size of the window, that is, if you configure components to have a relative size (e.g. buttons usually do not grow or shrink - they stick to their preferred size). This SO question was one of the motivations for me to push HVLayout to a release and a screenshot is included (showing big window size, smalll size and preferred "default" size):
Source code for the window is in RelativeToWindowSize.java
A number of helper-classes from HVLayout are used to build the window, so I don't think it will be of much use here, but to get an impression, the "build window" part shown below:
public RelativeToWindowSize build() {
CSize cs = new CSize();
CForm form = new CForm(new VBox(new Insets(2, 4, 2, 4)), cs);
addTitledBorder(form.get(), "Vertical box", Color.BLACK);
form.add(new JScrollPane(
tfield = new JTextArea("Value that changes with value choosen from list.\nhttp://stackoverflow.com/questions/24462297/layout-relative-to-screensize/")
)).csize().setAreaSize(1.0f, 2.5f).fixedMinHeight().setMaxHeight(4.0f);
// tfield shows mono-spaced font by default.
tfield.setFont(SwingUtils.getUIFont());
form.add(new JScrollPane(vlist = new JList<String>(getListValues())))
.csize().setAreaSize(1.0f, 5.0f);
form.addChild(new HBox());
addTitledBorder(form.get(), "Horizontal box", Color.RED);
form.addChild(new HBox(SwingConstants.CENTER));
addTitledBorder(form.get(), "Centered box.", Color.BLUE);
form.add(createButton(cs, "Add"));
form.add(createButton(cs, "Modify"));
form.up();
form.addChild(new HBox(SwingConstants.TRAILING));
addTitledBorder(form.get(), "Trailing box", Color.GREEN);
form.add(createButton(cs, "Delete"));
setContentPane(form.getRoot());
pack();
setLocationByPlatform(true);
//applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
vlist.addListSelectionListener(this);
log.debug(getClass().getName() + " build.");
return this;
}
private Component createButton(CSize cs, String text) {
// For purpose of demo, let button shrink in width.
return cs.set(new TButton(text)).setFixed().shrinkWidth(0.33f).get();
}

Add JTextField to OverlayLayout

I have a JTextField being added to an OverlayLayout, but the JTextField automatically scales to be the dimensions of the entire panel, which I don't want. I also don't want to mess with the dimensions of the JTextField because the default height is just right for the font, and the width is supposed to be defined by the number of columns in the constructor. What would be the right way to fix this?
Here's the relevant code that I have now:
frame = new JFrame("frame");
frame.setResizable(false);
panel = new GamePanel();
panel.setPreferredSize(new Dimension(500,300));
panel.setLayout(new OverlayLayout(panel));
JTextField t = new JTextField(50);
panel.add(t);
frame.add(panel);
frame.pack();
frame.setVisible(true);
GamePanel is just a subclass of JPanel; it doesn't do anything that would affect the JTextField.
EDIT: ok, I've heard now that using the default Swing layout managers isn't the best idea. kleopatra linked a page that refers to three third-party layouts that should accomplish pretty much everything you need to do, but I can't find anything that would let me overlay a text field (or other component) onto another custom-rendered panel. What would be the right approach?
Does this work as you want it?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.LayoutManager;
import javax.swing.JTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
public class OverlaySampleAlignment0 {
public static void main(String args[]) {
JFrame frame = new JFrame("Overlay Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(500,300));
LayoutManager overlay = new OverlayLayout(panel);
panel.setLayout(overlay);
JTextField field = new JTextField("", 12);
field.setMaximumSize(field.getPreferredSize());
//button.setMaximumSize(new Dimension(25, 25));
field.setBackground(Color.white);
field.setAlignmentX(0.0f);
field.setAlignmentY(0.0f);
panel.add(field);
frame.add(panel);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}
}
The height is exactly the height needed for the font, and the width is (in my example) 12 "columns" (JTextField does not use a monospaced font by default in my Java setup). Additionally I aligned it in the upper left corner.
This might also help trouble-shooting layout issues:
Link
Most of the code is copied from here: Link. I just added the setMaximumSize(...) and used a JTextField instead of buttons etc.

JTextField displayed as slit when using FlowLayout...please explain

Can someone please explain to me, why every time I use the FlowLayout Layout manager
my textfields are displayed as slits.
I have bumped my head against this problem for some time now, and I can't seem to figure
out why it goes wrong.
I get a feeling it is a simple thing that I am overlooking time and time again, so if
someone would please explain this phenomenon to me, I would be forever grateful.
import java.awt.Container;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class Console
{
public Console()
{
makeConsole();
}
private void makeConsole()
{
JFrame console = new JFrame("ArchiveConsole");
Container base = console.getContentPane();
base.setSize(400, 250);
console.setSize(base.getSize());
base.setLayout(new FlowLayout(FlowLayout.CENTER, 5,5));
JTextField tf = new JTextField();
tf.setSize(base.getWidth(), 25);
base.add(tf);
console.setVisible(true);
}
}
From the Swing layout manager tutorial
The FlowLayout class puts components in a row, sized at their preferred size. If the horizontal space in the container is too small to put all the components in one row, the FlowLayout class uses multiple rows. If the container is wider than necessary for a row of components, the row is, by default, centered horizontally within the container
So you need to adjust the preferred size of your textfield, preferably by using the setColumns method.
Note that if you want your text field to span the whole width you might want to use another layout then the FlowLayout for the reason quoted above
For example, the following code gives a nice looking JTextField, but I have hardcoded the number of columns
import javax.swing.JFrame;
import javax.swing.JTextField;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.FlowLayout;
public class TextFieldWithFlowLayout {
public static void main( String[] args ) {
EventQueue.invokeLater( new Runnable() {
#Override
public void run() {
JFrame console = new JFrame("ArchiveConsole");
Container base = console.getContentPane();
base.setLayout(new FlowLayout( FlowLayout.CENTER, 5,5));
JTextField tf = new JTextField();
tf.setColumns( 20 );
base.add(tf);
console.pack();
console.setVisible(true);
}
} );
}
}
Use:
JTextField tf = new JTextField(25);
Instead of:
JTextField tf = new JTextField();
tf.setSize(base.getWidth(), 25);
When you use LayoutManagers, don't try to set size and position manually. You are conflicting with what the LayoutManager does. Layoutmanagers size and position components based on constraints and preferred/minimum/maximum size. Most Swing components handle that automatically, so you should usually not force their preferred size.
As for your JTextField, since it does not contain any text, its preferred size is close to nothing. Use setColumns to indicate a preferredSize or invoke setPreferredSize
Thanks!
The parameter that using in the JTextField function is very important!
JPanel panel_buttons = new JPanel(new FlowLayout(FlowLayout.LEFT));
panel_buttons.add(...);
...
panel_buttons.add(...);
JTextField txt_search = new JTextField(20);
panel_buttons.add(txt_search);
If change 20 to 30 or large, may be u couldn't find it.May be the txt_search is in the next line.

Swing BoxLayout problem with JComboBox without using setXXXSize

here's an SSCCE:
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BoxLayoutTest extends JFrame {
public BoxLayoutTest(){
JPanel main = new JPanel();
main.setLayout(new BoxLayout(main, BoxLayout.Y_AXIS));
main.setBackground(Color.red);
this.add(main);
JPanel northPanel = new JPanel();
JPanel middle = new JPanel();
middle.setLayout(new BoxLayout(middle, BoxLayout.X_AXIS));
middle.add(new JButton("FOO"));
middle.add(Box.createHorizontalGlue());
JPanel aPanel = new JPanel();
aPanel.setBackground(Color.black);
JComboBox b = new JComboBox();
//b.setPreferredSize(new Dimension(100,16)); //uncomment this to see the layout I would like to achieve
//b.setMaximumSize(new Dimension(100,16));
//middle.add(b); //uncomment this line
middle.setBackground(Color.green);
northPanel.setBackground(Color.blue);
main.add(northPanel);
main.add(middle);
main.add(Box.createVerticalGlue());
this.setSize(800,600);
this.setResizable(true);
this.setVisible(true);
}
public static void main(String[] args) {
new BoxLayoutTest();
}
}
I'm trying to refactor some classes I wrote some time ago, when I didn't know that using setXXXSize methods on components is wrong.
Using a resizable frame ,the result I want to achieve is the following:
The northPanel should stay on top and change it's size accordingly to the frame size modifications (seems to work fine)
The green panel where I put the JButton should keep the maximum dimension of the JButton and stay just below the blue panel above (this works fine if I only put JButtons inside that panel).
The problem arise if I put a JComboBox inside the green panel (try to uncomment the line in the SSCCE). I guess JComboBox hasn't a maximum size specified, so it stretches with the frame. In the previous wrong version of my code I was using setxxxSize methods on the JComboBox to limit it's dimension(try to uncomment the line on setXXXSize methods to see it).
My question are:
Is it possible to achieve the same result using BoxLayout without invoking setXXXSize() methods?
If yes, how?
Is there any other LayoutManager that can I use to get that effect?
Please put me in the right direction
JComboBox is misbehaving (the same as JTextField) in reporting an unbounded max height: should never show more than a single line. Remedy is the same: subclass and return a reasonable height
JComboBox b = new JComboBox() {
/**
* #inherited <p>
*/
#Override
public Dimension getMaximumSize() {
Dimension max = super.getMaximumSize();
max.height = getPreferredSize().height;
return max;
}
};
just for fun, here's a snippet using MigLayout (which is my personal favorite currently :-)
// two panels as placeholders
JPanel northPanel = new JPanel();
northPanel.setBackground(Color.YELLOW);
JPanel southPanel = new JPanel();
southPanel.setBackground(Color.YELLOW);
// layout with two content columns
LC layoutContraints = new LC().wrapAfter(2)
.debug(1000);
AC columnContraints = new AC()
// first column pref, followed by greedy gap
.size("pref").gap("push")
// second
.size("pref");
// three rows, top/bottom growing, middle pref
AC rowContraints = new AC()
.grow().gap().size("pref").gap().grow();
MigLayout layout = new MigLayout(layoutContraints, columnContraints,
rowContraints);
JPanel main = new JPanel(layout);
main.setBackground(Color.WHITE);
// add top spanning columns and growing
main.add(northPanel, "spanx, grow");
main.add(new JButton("FOO"));
// well-behaved combo: max height == pref height
JComboBox combo = new JComboBox() {
#Override
public Dimension getMaximumSize() {
Dimension max = super.getMaximumSize();
max.height = getPreferredSize().height;
return max;
}
};
// set a prototype to keep it from constantly adjusting
combo.setPrototypeDisplayValue("somethingaslongasIwant");
main.add(combo);
// add top spanning columns and growing
main.add(southPanel, "spanx, grow");
I have always seen using the layout managers in the jdk are not easy. They are either too simple and inflexible or the gridbaglayout is just too much trouble. Instead I started using the jgoodies form layout and never looked back since.. Have a look at it. Its very simple and easy to use. Here's a link:
http://www.jgoodies.com/freeware/forms/
Make sure you go through the white paper.
And now, we also have google providing us a WYSISWG editor for the formlayout as a plugin for eclipse. This just makes life a lot lot easier.
http://code.google.com/javadevtools/wbpro/palettes/swing_palette.html

Categories