Two Components on top of each other using MigLayout - java

I'm trying to get two components,
frame.getContentPane().setLayout(new MigLayout("", "[53px,grow][57px][grow]", "[23px][][][]"));
JTextPane itemTitle = new JTextPane();
frame.getContentPane().add(itemTitle,"cell 0 4,alignx left,aligny top");
itemTitle.setVisible(true);
itemTitle.setMinimumSize(new Dimension(50, 50));
List choices = new List();
frame.add(choices, "cell 0 4,alignx left,aligny top");
choices.setVisible(true);
to be in the same place, but all the happens is this:
The two components highlighted at itemTitle and choices.
My aim is to have the buttons above set one "setVisible" to true and the other to false. They would never both be true. How can I get two components in one cell at the same time? It also puts my above buttons out of place and I'm not too sure why. I put above the important code referring to the two components, I could put the full GUI code if you requested.
I found this: Fill Entire Cell With Two Components Using MigLayout However it is over years old and to be honest, I don't understand the solution.
I'm sort of learning as I go, I've never used MigLayout before. Should I be using a different layout?
Thanks for any help

to be in the same place... My aim is to have the buttons above set one "setVisible" to true and the other to false. They would never both be true
Then you should be using a JPanel that contains those two components. Then you use a Card Layout on that panel and use the CardLayout to determine which component is visible at any given time. This panel can be added to the panel using the MigLayout just like any other component.
List choices = new List();
Looks to me like you are using an AWT component. You should be using JList for a Swing application.

Should I be using a different layout?
No, stick with MigLayout. You have chosen the right layout manager.
I advice you to invest some time into learning this manager; create couple
of smaller practical examples, learn the numerous constraints that this
manager provides.
It also puts my above buttons out of place and I'm not too sure why.
MigLayout is a grid-based layout manager. (Its most important mode is.)
The gap between the New and Open buttons is created because the
highlighted components and the New button form a column. The column width
is determined by the width of the largest cell. To bypass this, we can
use the split constraint. (Often used in combination with span constraint.)
In my example I use this technique to center two buttons above the
currently visible label.
If we are not sure about something in the layout, we can use the
debug layout constraint which paints the lines of the grid and bounds
of the components.
frame.getContentPane().setLayout(new MigLayout("", "[53px,grow][57px][grow]", "[23px][][][]"));
Do not set bounds in pixels. You are not utilizing of one of the
most important advantages of this manager -- independence of resolution and
DPI. Bounds in pixels are not portable. A 3px gap between buttons looks OK on a smaller screen but is not acceptable on a larger one.
MigLayout provides several options to choose from including related and unrelated gaps, logical pixels, points, or centimeters.
itemTitle.setMinimumSize(new Dimension(50, 50));
Setting a minimum size of a component is usually not necessary. But if we need to
do it, we have the wmin and wmax constraints. This should be done by the
layout manager, not by code outside of it. The set(Minimum|Maximum|Preferred)size
methods should be avoided. (With poorer managers, one cannot do without them, however.)
And again, setting dimensions in pixels is not optimal.
Now we get to the solution. MigLayout has hidemode constraint to deal
with your requirement. There are four hide modes. I assume that we need
the hidemode 3, in which all invisible components do not participate in the
layout.
package com.zetcode;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class HidingComponentsEx extends JFrame {
private ArrayList<JLabel> lbls;
private int itemVisible = 0;
public HidingComponentsEx() {
initUI();
}
private void initUI() {
createLabels();
JButton prevBtn = new JButton("Previous");
prevBtn.addActionListener(new PrevAction());
JButton nextBtn = new JButton("Next");
nextBtn.addActionListener(new NextAction());
JPanel pnl = new JPanel(new MigLayout("ins dialog"));
pnl.add(prevBtn, "split 2, center");
pnl.add(nextBtn, "wrap");
for (JLabel lbl : lbls) {
pnl.add(lbl, "cell 0 1, w 250lp, h 100lp, hidemode 3");
}
add(pnl);
pack();
setTitle("MigLayout example");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void createLabels() {
lbls = new ArrayList<>();
lbls.add(createLabel("North Sea"));
lbls.add(createLabel("Ionian Sea"));
lbls.add(createLabel("Norwegian Sea"));
lbls.add(createLabel("Bering Sea"));
lbls.add(createLabel("Dead Sea"));
lbls.get(itemVisible).setVisible(true);
}
private class NextAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
lbls.get(itemVisible).setVisible(false);
itemVisible++;
if (itemVisible > 4) {
itemVisible = 0;
}
lbls.get(itemVisible).setVisible(true);
}
}
private class PrevAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
lbls.get(itemVisible).setVisible(false);
itemVisible--;
if (itemVisible < 0) {
itemVisible = 4;
}
lbls.get(itemVisible).setVisible(true);
}
}
private JLabel createLabel(String text) {
JLabel lbl = new JLabel(text, JLabel.CENTER);
lbl.setVisible(false);
lbl.setBorder(BorderFactory.createEtchedBorder());
return lbl;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
HidingComponentsEx ex = new HidingComponentsEx();
ex.setVisible(true);
}
});
}
}
Our example has two buttons and five labels. The buttons dynamically change their
visibility.

Related

Fixed height and width for JTextField

I've been working with Java Swing recently and when I try to add 3 JTextFields beneath each other they fill out the whole JFrame. But I want them to have a fixed height and width. What can I do?
Since I'm new to this topic I wasn't able to try out many things. I haven't found anything in other forums either.
My goal was to make a simple GUI for Users to fill in their credentials. Those credentials should be filled into an array but I haven't got there yet.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class PeopleGUI extends JFrame{
JPanel jp = new JPanel();
JLabel jl = new JLabel();
JTextField jt = new JTextField(30);
JTextField jt1 = new JTextField(30);
JTextField jt2 = new JTextField(30);
JButton jb = new JButton("Enter");
public PeopleGUI(){
setTitle("PeopleGUI");
setVisible(true);
setSize(400,200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
jp.setLayout(new BoxLayout(jp, BoxLayout.Y_AXIS));
jp.add(jt);
jp.add(jt1);
jp.add(jt2);
jt.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
String input = jt.getText();
jl.setText(input);
}
});
jp.add(jb);
jb.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
String input = jt.getText();
jl.setText(input);
}
});
jp.add(jl);
add(jp);
}
public static void main(String[] args) {
PeopleGUI p = new PeopleGUI();
}
}
I expect JTextFields that don't adjust to the size of the window.
Currently, it is looking like this:
.
But it should rather look like:
.
That layout is easily reproduced by putting 3 panels, each with a centered FlowLayout, into a single column GridLayout.
The important part is the FlowLayout, which will respect the preferred size of the components it is displaying.
Combinations of different layouts are often used when making a GUI. The idea is for each to handle a small part of the layout needs of the entire user interface. Here is a screenshot from that answer which lists the layouts used, by way of titled borders for each one.
But I think it would be better if the RHS of the label and the LHS of the fields are aligned vertically. To do that, use a single GridBagLayout.
You have to use a Layout e.g. BoxLayout. You will find some documentation here

Why does a GroupLayout not having a result as per requirement

Here I want to add buttons as per 4-3-3 formation in football but i am getting 3-3-3. how can i put 4 buttons in one row??
I have been referral to this site: https://weblogs.java.net/blog/tpavek/archive/2006/02/getting_to_know_2.html
Code:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import static javax.swing.GroupLayout.Alignment.*;
class Abc extends JFrame
{
JButton b[];
Abc()
{
b=new JButton[11];
JPanel jp=new JPanel();
for(int i=0;i<b.length;i++)
{
b[i]=new JButton();
}
GroupLayout layout=new GroupLayout(jp);
jp.setLayout(layout);
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
layout.setHorizontalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(LEADING)
.addComponent(b[0])
.addComponent(b[1])
.addGroup(layout.createSequentialGroup())
.addComponent(b[2])
.addComponent(b[3]))
.addGroup(layout.createParallelGroup(LEADING)
.addComponent(b[4])
.addComponent(b[5])
.addGroup(layout.createSequentialGroup())
.addComponent(b[6]))
.addComponent(b[7])
.addGroup(layout.createParallelGroup(LEADING)
.addComponent(b[8])
.addComponent(b[9])
.addGroup(layout.createSequentialGroup())
.addComponent(b[10]))
);
layout.setVerticalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(BASELINE)
.addComponent(b[0])
.addComponent(b[4])
.addComponent(b[8]))
.addGroup(layout.createParallelGroup(BASELINE)
.addComponent(b[1])
.addComponent(b[5])
.addComponent(b[9]))
.addGroup(layout.createParallelGroup(BASELINE)
.addComponent(b[2])
.addComponent(b[3])
.addComponent(b[6])
.addComponent(b[10]))
.addComponent(b[7])
);
setTitle("kuvh b");
setSize(1000,1000);
for(int i=0;i<11;i++)
{
add(b[i]);
}
add(jp);
pack();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(
"javax.swing.plaf.metal.MetalLookAndFeel");
// "com.sun.java.swing.plaf.motif.MotifLookAndFeel");
//UIManager.getCrossPlatformLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
new Abc().setVisible(true);
}
});
}
}
I want to make a structure of 4-3-3 formation with this. Please help me
The code is resulting in 3-3-3 formation. there are 3 buttons on third row but i want 4 how can i do this please help
See the output:
[1]:
http://imgur.com/jxADf2t
i hope i will find my solution as far as possible
I've found two ways to do something like you want; centering the buttons turns out to be something that Swing does not make as easy as it might, but then centering components is probably not as common as other alignments.
You can center components in a FlowLayout; the disadvantage in a FlowLayout is that, if the user shrinks the window to the point the components no longer fit, the layout wraps the components. This is very useful for some things, but not for your football players. I've wrapped my example in a scrollpane so this won't happen.
The other way to center components is with GroupLayout, but GroupLayout is not good for the overall layout you are trying to achieve. GroupLayout is intended for use where you have overall rows and columns in which to line things up, and your four lines of football players are not lined up that way vertically, only horizontally. But you can use the centering characteristic of GroupLayout to do the horizontal centering, and make a separate GroupLayout for each line.
My example uses FlowLayout for the first line, and GroupLayout for the second, just to show how it could be done. I did not address the problem of the gap that appears between the players' lines when the window is made large enough. Especially for examples, I do not use the style of tacking method invocations onto other method invocations and constructors; I think the deeply nested parentheses and non-straightforward logic of this style makes it more difficult to figure out (or keep track of) what's going on.
You can use GridBagLayout to center things, also, but I don't use it at all if anything else will do what I need.
I hope this answers your question.
package grouplayout;
import java.awt.FlowLayout;
import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Main2 extends JFrame
{
public static void main(String ... arguments)
{
Main2 main2 = new Main2();
main2.createUI();
main2.setVisible(true);
}
public void createUI()
{
JPanel wingPanel = new JPanel();
FlowLayout flowLayout = new FlowLayout();
flowLayout.setHgap(35);
wingPanel.setLayout(flowLayout);
JButton btnone = new JButton("Lwing");
JButton btntwo = new JButton("center");
JButton btnthr = new JButton("Rwing");
wingPanel.add(btnone);
wingPanel.add(btntwo);
wingPanel.add(btnthr);
// -------------------------------------------
JButton mid1 = new JButton("mid1");
JButton mid2 = new JButton("mid2");
JButton mid3 = new JButton("mid3");
JButton mid4 = new JButton("mid4");
JPanel midfieldPanel = new JPanel();
GroupLayout groupLayout = new GroupLayout(midfieldPanel);
GroupLayout.SequentialGroup horizontalGroup = groupLayout.createSequentialGroup();
groupLayout.setHorizontalGroup(horizontalGroup);
horizontalGroup.addComponent(mid1);
horizontalGroup.addComponent(mid2);
horizontalGroup.addComponent(mid3);
horizontalGroup.addComponent(mid4);
GroupLayout.SequentialGroup verticalGroup = groupLayout.createSequentialGroup();
groupLayout.setVerticalGroup(verticalGroup);
GroupLayout.ParallelGroup midButtonGroup = groupLayout.createParallelGroup(GroupLayout.Alignment.CENTER);
midButtonGroup.addComponent(mid1);
midButtonGroup.addComponent(mid2);
midButtonGroup.addComponent(mid3);
midButtonGroup.addComponent(mid4);
verticalGroup.addGroup(midButtonGroup);
JPanel teamPanel = new JPanel();
BoxLayout boxLayout = new BoxLayout(teamPanel, BoxLayout.PAGE_AXIS);
teamPanel.setLayout(boxLayout);
teamPanel.add(wingPanel);
teamPanel.add(midfieldPanel);
JScrollPane scrollPane = new JScrollPane(teamPanel);
getContentPane().add(scrollPane);
pack();
}
}
EDIT: as requested, the below does the same thing with only GroupLayout.
There is no interaction between the two groups, because GroupLayout aligns things in columns, and your players are not in columns.
And yes, I suppose it is difficult -- GroupLayout, as I understand it, was really intended for use by GUI builder tools, not really for building UIs by hand. I personally have a supporter class or two that allows GroupLayout UIs to be built with slightly simpler logic. But in any event, I think you need to understand the building blocks:
GroupLayout allows - and requires - that you place each component in both horizontal and vertical row/column position independently; this is useful since so many UIs require rows and columns of mixed components and variable extra components.
A sequential group of components in dimension X is arranged sequentially in dimension X; a parallel group in dimension X is also arranged sequentially, but perpendicular to dimension X.
The layout maintains preferred sizes of components; row width and column height are set at the maximum preferred size of the constituent components.
The overall GroupLayout object has one vertical and one horizontal grouping; within that, sequential and parallel groups are created to create the overall layout desired.
I know the examples in the tutorial(s) I've read do not create separate variables to hold the internal sequential and parallel groups, preferring to use forms like new X().addComponent().addGroup() etc. But I think that makes it harder to understand what the code is actually doing, not easier; and the nested parentheses become their own maintenance problem. So I think this is a better way to do things, especially for those just getting started with this layout.
package grouplayout;
import java.awt.FlowLayout;
import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Main3 extends JFrame
{
public static void main(String ... arguments)
{
Main3 main2 = new Main3();
main2.createUI();
main2.setVisible(true);
}
public void createUI()
{
JButton btnone = new JButton("Lwing");
JButton btntwo = new JButton("center");
JButton btnthr = new JButton("Rwing");
JPanel wingPanel = new JPanel();
GroupLayout wingGroupLayout = new GroupLayout(wingPanel);
GroupLayout.SequentialGroup wingHorizontalGroup = wingGroupLayout.createSequentialGroup();
wingGroupLayout.setHorizontalGroup(wingHorizontalGroup);
wingHorizontalGroup.addComponent(btnone);
wingHorizontalGroup.addComponent(btntwo);
wingHorizontalGroup.addComponent(btnthr);
GroupLayout.SequentialGroup wingVerticalGroup = wingGroupLayout.createSequentialGroup();
wingGroupLayout.setVerticalGroup(wingVerticalGroup);
GroupLayout.ParallelGroup wingButtonGroup = wingGroupLayout.createParallelGroup();
wingButtonGroup.addComponent(btnone);
wingButtonGroup.addComponent(btntwo);
wingButtonGroup.addComponent(btnthr);
wingVerticalGroup.addGroup(wingButtonGroup);
// -------------------------------------------
JButton mid1 = new JButton("mid1");
JButton mid2 = new JButton("mid2");
JButton mid3 = new JButton("mid3");
JButton mid4 = new JButton("mid4");
JPanel midfieldPanel = new JPanel();
GroupLayout groupLayout = new GroupLayout(midfieldPanel);
GroupLayout.SequentialGroup horizontalGroup = groupLayout.createSequentialGroup();
groupLayout.setHorizontalGroup(horizontalGroup);
horizontalGroup.addComponent(mid1);
horizontalGroup.addComponent(mid2);
horizontalGroup.addComponent(mid3);
horizontalGroup.addComponent(mid4);
GroupLayout.SequentialGroup verticalGroup = groupLayout.createSequentialGroup();
groupLayout.setVerticalGroup(verticalGroup);
GroupLayout.ParallelGroup midButtonGroup = groupLayout.createParallelGroup(GroupLayout.Alignment.CENTER);
midButtonGroup.addComponent(mid1);
midButtonGroup.addComponent(mid2);
midButtonGroup.addComponent(mid3);
midButtonGroup.addComponent(mid4);
verticalGroup.addGroup(midButtonGroup);
JPanel teamPanel = new JPanel();
BoxLayout boxLayout = new BoxLayout(teamPanel, BoxLayout.PAGE_AXIS);
teamPanel.setLayout(boxLayout);
teamPanel.add(wingPanel);
teamPanel.add(midfieldPanel);
JScrollPane scrollPane = new JScrollPane(teamPanel);
getContentPane().add(scrollPane);
pack();
}
}

Using Java pack() method

I can't make the pack() method work. I tried several things. My code looks like this at the moment:
Class 1:
public static void main( String[] args )
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run()
{
JavaGui mygui = new JavaGui();
// mygui.setSize(1154, 753);
mygui.setVisible(true);
mygui.pack();
Class 2:
public class JavaGui extends javax.swing.JFrame
{
public JavaGui()
{
getContentPane().setLayout(null);
..
getContentPane().add(panelLeft);
...
getContentPane().add(panelRight);
I tried putting the pack method in everywhere, but it's not going to work with this way of adding gui elements. Any suggestions why? I also tried adding everything to a JFrame instead of the getContentPane(), but I can't make that work either.
Don't use null layouts together with pack(). The pack method tells the layout managers and components to size themselves optimally, and if you instead use null layouts, then the gui risks shrinking to a minimal size, since there is no layout to hold it together.
Don't use null layouts at all for the most part. Using these risk your creating rigid GUI's that are almost impossible to extend, improve, debug.
Don't use setSize(...) and pack(). The layouts mostly respect the preferred sizes of components, not their sizes.
Instead:
Use a pleasing and sensible combination of nested JPanels, each using its own layout manager.
Let the components and the layout managers size themselves.
Then pack should help.
The general order that I do is to add all components to the GUI, then call pack(), then setLocationByPlatform(true) (I think), then setVisible(true).
For better help, please check out the Swing Layout Manager Tutorials.
Here are a couple examples to other questions on this site that use various layout managers:
A combination of BorderLayout and GridLayout to create a calculator
BorderLayout and BoxLayout Combination for labels and JTextFields
Using GridBagLayout to create flexible label/textfield grid
I would recommened beginners on building up swing guis to use a good ide with a builtin gui designer like eclipse and windowbuilder or netbeans with matisse. It will help you building up a prototype of your desired gui and gives you an insight how the layouting is done in the source code.
Experiment with the differenet layouts and what is happening when some values are changed.
one does not simply build up a well behaving gui without understanding how the layout works, so doing the recommended tutorials and looking at examples as already posted by Hovercraft Full Of Eels is absolutely necessary.
For your case i just guess what you were up to. Because youre mentioning left and right panels i suggest a JSplitPane which let you divide your screen in two areas which are customizable in size and orientation.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
public class JavaGui extends JFrame {
//SerialVersionId http://stackoverflow.com/questions/285793/what-is-a-serialversionuid-and-why-should-i-use-it
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
//Calls to Gui Code must happen on the event dispatch thread that the gui does not get stuck
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new JavaGui().setVisible(true);
}
});
}
public JavaGui() {
// Set the desired size of the frame to determine the maximum size of its components
setPreferredSize(new Dimension(1024, 768));
// Set the default close operation, if press x on frame, destroy the frame and exit the application - others are just destroy the frame or just hide the
// frame
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// BorderLayout because we just need a centric gui with one component, here JSplitPane in full size
getContentPane().setLayout(new BorderLayout(0, 0));
// JsplitPane is a bit special as it depends on the divider location between both panels, for the sake of a small example we take the default -1,
JSplitPane splitPane = new JSplitPane();
// 0.5 divides extra space equally to left and right component when resizing the frame - so specifiying a size for the left and right component is not
// necessary
// use the divider location default -1 to let the width of the left component decide where the right component begins, in that case because of the
// resize weight half and half
splitPane.setDividerLocation(-1);
splitPane.setResizeWeight(0.5);
getContentPane().add(splitPane, BorderLayout.CENTER);
// For the panels the same layout as default as the intention is not stated in your question
JPanel leftPanel = new JPanel();
splitPane.setLeftComponent(leftPanel);
leftPanel.setLayout(new BorderLayout(0, 0));
JPanel rightPanel = new JPanel();
splitPane.setRightComponent(rightPanel);
rightPanel.setLayout(new BorderLayout(0, 0));
// Add a button Panel to the south for doing something - flow layout for letting the components flow to the right side
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
// Close Button for closing the frame
JButton btnExit = new JButton("Destroy this frame, but let application run");
btnExit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
buttonPanel.add(btnExit);
// Set every component to its preferred size
pack();
// Make it visible
setVisible(true);
}
}
If you want your JFrame to work with a null layout, rearrange your code so that it looks like this:
public class JavaGui extends javax.swing.JFrame
{
public JavaGui()
{
setMinimumSize(1154, 753); // Make sure you do setMinimumSize() instead of setSize() when using pack() so that the JFrame does not shrink to 0 size
setLayout(null);
add(panelLeft);
add(panelRight);
pack();
}
// Next is main method
Main:
public static void main(String[] args)
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run()
{
new JavaGui().setVisible(true);
// Do not do any formatting for your JFrame here
}
});
Before, you were modifying the JFrame after it was set visible, so that usually does not work, except for pack(). All components and settings for your JFrame should not be in the main method if you are using an anonymous inner class.
You can also use other layouts. Null layouts are for getting pixels in precise locations, which is used for advanced GUI design such as creating a custom GUI, but it seems that you are making a generic GUI with JPanels. For this, I would recommend using a GridBagLayout, which keeps everything centered if the frame is resized and is easy to use. To use a GridBagLayout, you have to replace setLayout(null); with setLayout(new GridBagLayout()); and set GridBagConstraints. Here is some example code of making a panel with a component and a GridBagLayout:
JPanel pane = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
if (shouldFill) {
//natural height, maximum width
c.fill = GridBagConstraints.HORIZONTAL;
}
//For each component to be added to this container:
//...Create the component...
//...Set instance variables in the GridBagConstraints instance...
pane.add(theComponent, c);
// Source: Oracle Docs

How to Correctly Set Minimum Sizes in Java?

For a GUI application I am creating in Java, I have the following:
A JFrame, set to have a minimum size of (300,200)
A JSplitPane, in which lies:
On the left, a JScrollPane (containing a JTree) with a minimum size of (100,0) (I only want to restrict the width to 200)
On the right, a JPanel with a minimum size of (200,0)
The sizing does not give me any issue under the following conditions:
Resizing the JSplitPane all the way to the left (to the JScrollPane's minimum size), and subsequently resize the window afterward
Just resizing the window, to a certain degree
The problem occurs when I move the JSplitPane too close to the right, whereupon resizing the window the JPanel in the right of the JSplitPane fails to adhere to the minimum width I set.
I attempted setting a maximum width on the JScrollPane, which did not seem to help at all.
Is there something involving maximum sizes I must do? Or perhaps there is a way to attach a Listener to one of the panels to force my desired behavior? Ultimately, I just want the right panel in the JSplitPane to never be less than 200px wide.
Here is an example with behavior I am experiencing:
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
public class ResizeTest
{
private JFrame frame;
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
ResizeTest window = new ResizeTest();
window.frame.setVisible(true);
}
catch(Exception e)
{
e.printStackTrace();
}
}
});
}
public ResizeTest()
{
initialize();
}
private void initialize()
{
frame = new JFrame();
frame.setMinimumSize(new Dimension(300, 200));
frame.setBounds(100,100,450,300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridLayout(0, 1, 0, 0));
JSplitPane splitPane = new JSplitPane();
frame.getContentPane().add(splitPane);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setMinimumSize(new Dimension(100, 0));
splitPane.setLeftComponent(scrollPane);
JTree tree = new JTree();
tree.setMinimumSize(new Dimension(100, 0));
scrollPane.setViewportView(tree);
JPanel panel = new JPanel();
panel.setMinimumSize(new Dimension(200, 0));
splitPane.setRightComponent(panel);
}
}
Update:
I'm afraid I don't fully understand the point trying to be made in the proposed solutions, except for that setPreferred() and setMinimum/Maximum() are better to be avoided.
My question in response to learning this is, what are my options for restricting the JSplitPane divider outside of using these methods? MadProgrammer mentioned listening for the componentResized event, but I need just a little more clarification as to why. Am I calling setDividerLocation() in response to this event?
I apologize in advance if the appended question is meant as a separate StackOverflow question entirely, I can post another and link here if necessary.
Update 2:
Is simply not regulating how the user chooses to size the window and having the right panel in a JScrollPane a viable option? This looks to me like somewhat of a standard practice.
Firstly, the method setMinimumSize is a suggestion to the LayoutManager API. A suggestion that may be ignored.
In order to be able to even come close to supporting this, you will need to use something like a ComponentListener and monitor the componentResized event.
The best solution I can think of is to use a LayoutManager that actually uses the minimum and maximum size constraints, something like GridBagLayout.
Use this on a "content" pane and place you're JSplitPane onto this (setting it's minimum and maximum size accordingly) then add the "content" pane to frame.
UPDATE
Sorry, I'm probably missing something really obvious, but I put this little test together, I hope it has some ideas that help :P
public class TestFrameSize extends JFrame {
public TestFrameSize() throws HeadlessException {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(600, 600);
setLocationRelativeTo(null);
setMinimumSize(new Dimension(250, 250));
JLabel left = new JLabel("Left");
JLabel right = new JLabel("Right");
Dimension pSize = new Dimension(100, 100);
Dimension mSize = new Dimension(25, 100);
left.setPreferredSize(pSize);
left.setMinimumSize(mSize);
right.setPreferredSize(pSize);
right.setMinimumSize(mSize);
JSplitPane pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right);
JPanel content = new JPanel(new GridBagLayout());
content.add(pane);
setLayout(new BorderLayout());
add(content);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new TestFrameSize().setVisible(true);
}
}
In this example, the preferred size of the content of a JSplitPane is initially set to a small multiple of the component's preferred size in getPreferredSize(). Note that the JSplitPane will become no smaller than the panel's minimum size, managed by the enclosed Jlabel.

JPanel on a JPanel in a JFrame will not show

Hello
I'm an amateur trying to learn/improve my understanding of Java by writing a score card for archery. I ‘m trying to produce a GUI and so far have successfully produced on a JPanel a row of 18 labels of differing sizes and colours suitable for scoring a dozen.
I then tried to add five of these 'labels panels' to another panel to build up a grid and save having to create and add as many as 150 labels in some cases . No success so far as the original labels panels will not show up. All the panels are displayed on a JFrame
I've tried a number of different ways of getting the code to work, using the Java tutorial and googling the internet and studying similar problems on this site but I'm going round in circles. I must have missed something somewhere and hope that you may be able to help.
I'm using Java 6 and JGrasp v1.8.8_01 as an IDE
The following code for the labels panel has been cut down as much of it is repetitive.
import javax.swing.*;
import java.awt.*;
public class ArrowScoreLabels extends JPanel{
public JPanel createContentPane(){
JPanel panelForLabels = new JPanel();
panelForLabels.setLayout(null);
//Code creates 18 labels, sets the size, position, background colours, border and
//font and adds the labels to the’panelForLabels
JLabel scorelabel1;
scorelabel1 = new JLabel("",JLabel.CENTER);
scorelabel1.setBorder(BorderFactory.createLineBorder(Color.black));
scorelabel1.setFont(new Font("Arial", Font.ITALIC, 26));
scorelabel1.setLocation(0, 0);//first value differs for each label
scorelabel1.setSize(35, 35);
scorelabel1.setOpaque(true);
panelForLabels.add(scorelabel1);
panelForLabels.setOpaque(true);
return panelForLabels;
}
}
Running the following class shows the 18 labels on panel
import javax.swing.*;
import java.awt.*;
public class TestArrowScoreLabels {
private static void createAndShowArrowLabels() {
//Create and set up the window.
JFrame frame = new JFrame("To score one dozen");
//Create and set up the content pane.
ArrowScoreLabels asl = new ArrowScoreLabels();
frame.setContentPane(asl.createContentPane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(676, 73);
frame.setVisible(true);
}
//Main method to show the GUI/
public static void main(String[] args) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
createAndShowArrowLabels();
}
});
}
}
The following code for the second panel is similar, compiles but only shows the second green JPanel and not the panel with the labels.
import javax.swing.*;
import java.awt.*;
public class FiveDozenScorePanel{
public JPanel createContentPane(){
//A bottom JPanel on which to place five dozenpanels.
JPanel fivedozenpanel = new JPanel();
fivedozenpanel.setLayout(null); //requires absolute spacing
fivedozenpanel.setSize(676,185);
fivedozenpanel.setBackground(Color.green);
//Label panels for five dozen
ArrowScoreLabels dozenscorepanel1, dozenscorepanel2,
dozenscorepanel3,dozenscorepanel4,dozenscorepanel5;
//Create the 5 dozenscorelabels.
dozenscorepanel1 = new ArrowScoreLabels();
dozenscorepanel1.setLocation(5,5);//y value changes for each panel
fivedozenpanel.add(dozenscorepanel1);//plus the other 4
fivedozenpanel.setOpaque(true);
return fivedozenpanel;
}
private static void createAndShowDozenPanels() {
JFrame frame = new JFrame("To score five dozen");
FiveDozenScorePanel fdsp = new FiveDozenScorePanel();
frame.setContentPane(fdsp.createContentPane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Display the window
frame.setSize(700, 233);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
createAndShowDozenPanels();
}
});
}
}
I've also tried frame.getContentPane().add(fdsp); - frame.pack(); and read so much about paint methods that I'm totally confused.
I can get the ArrowScoreLabels image to appear directly onto a JFrame rather than a JPanel but only one of them and not five.
I would appreciate being pointed in the right direction. Thankyou for your time.
Update - 14th Dec 2010
I have managed to display the panelForLabels Jpanel on another Jpanel on a JFrame. This was done by adding the following code to the class ArrowScoreLabels. The original createContentPane() method was renamed createRowOne(). The panelForLabels was coloured red and the fivedozen panel yellow to ascertain which was showing. However I was only able to persuade the programme to display one row of labels despite a great deal of experimentation and research.
public static JPanel createContentPane(){
//Bottom panelto hold rows of labels
JPanel fivedozenscorepanel = new JPanel();
fivedozenscorepanel.setLayout(null);//requires absolute spacing
fivedozenscorepanel.setSize(660,180);
fivedozenscorepanel.setBackground(Color.yellow);
fivedozenscorepanel.add(createRowOne());
fivedozenscorepanel.setOpaque(true);
return fivedozenscorepanel;
}
The only way I displayed the 5 rows of 18 labels was to create all 90 in the ArrowScoreLabels class and then add them to one JPanel using absolute spacing and then to a JFrame.
I've taken note of pstantons advice - thankyou for that - and I'm looking into using the MigLayout Manager.
simple answer: use a layout manager. don't use absolute positioning.
just comment out all of your calls to setLocation and setLayout and swing will use the default FlowLayout.
for more control over the display, use a different layout manager.
also, if you use multiple panels you will have trouble aligning things in different panels unless they contain the same number of components which are exactly the same size so consider using one panel for all of the labels.
you can achieve just about any layout you need using MigLayout.
EDIT: in your example, there's no need for ArrowScoreLabels need to extend JPanel since you are doing the work in createContentPane to construct a separate JPanel. later in your code you call new ArrowScoreLabels() wich will just return a blank JPanel, instead you need to call new ArrowScoreLabels().createContentPane()
if you want ArrowScoreLabels to extend JPanel, implement public ArrowScoreLabels() ie the constructor instead of createContentPane.
I've the impression you don't set a size to your dozenscorepanel1. So, set a size :-)
Be careful with the layout null, because it's a pain ; you always forget something. Write your own, or use an existing one.

Categories

Resources