How to move components to next line in FlowLayout? - java

I am adding components in JPanel which is set as FlowLayout, they are not moving on next line even there is no space in left in that line.
Here is the screenshot of the problem
import javax.swing.*;
import java.awt.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.TitledBorder;
public class GUI extends JFrame
{
private JLabel jlfname;
private JPanel p1;
private JTextField t1;
private JLabel jllname;
private JTextField t2;
private JLabel jltitle;
private JTextField t3;
GUI()
{
jlfname=new JLabel("First Name : ");
p1=new JPanel();
TitledBorder titled = new TitledBorder("Name");
p1.setBorder(titled);
t1=new JTextField(10);
jllname=new JLabel("Last Name : ");
t2=new JTextField(10);
jltitle=new JLabel("Title : ");
t3=new JTextField(10);
//Add in Pannel
p1.setLayout(new FlowLayout());
p1.add(jlfname);
p1.add(t1);
p1.add(jllname);
p1.add(t2);
p1.add(jltitle);
p1.add(t3);
//Add in Frame
add(p1);
setSize(550,500);
setTitle("JFrame Tutorial");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout(FlowLayout.LEFT));
setResizable(false);
setVisible(true);
}
public static void main(String [] args)
{
new GUI();
}
}
I have also tried to set width of the panel but it doesn't work!

FlowLayout is designed to calculate its preferred size based on all components being displayed on a single line. The FlowLayout also respects the preferred size of components.
setLayout(new FlowLayout(FlowLayout.LEFT));
You are overriding the default layout manager of the frame, so now the frame will respect the preferred size of the panel added to the frame, which means all the components will be displayed on a single line.
Get rid of that statement.
Now the components will be able to wrap in the space available because by default the panel will be added to the BorderLayout.CENTER which takes up all the space available in the frame.
However the above solution will only work when components are added to the CENTER of the BorderLayout. Normally you should not be using setSize() but instead use pack() to all a frame to display at its preferred size.
For a more flexible layout that will calculate a proper preferred size of a panel check out the Wrap Layout. This class extends FlowLayout to calculate the preferred size.

Related

Auto resizing a JFrame with pack() without collapsing its jPanels

i am trying to design a JFrame with 2 different JPanels in it, one on the left with AbsoluteLayout and one on the right with a GridLayout with variable dimensions.
After adding some components to the JPanels, i add them to the JFrame contentPane and use the method JFrame.pack() hoping to get a JFrame with the minimum size possible that can show all of its components, but what i am getting is the minimum size to show only the JPanel on the right with the GridLayout, the JPanel on the left gets overlapped by the one on the right.
Is there any good way to use the JFrame.pack() method and it still shows both JPanel completly?
Here is the code:
public class GameGUI extends JFrame{
private int labSize;
private JFrame mainFrame;
private JPanel labPanel;
private JPanel choicesPanel;
private JButton exitButton;
private JButton replayButton;
public GameGUI(int n) {
labSize=n;
mainFrame = new JFrame("Maze Game");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.getContentPane().setLayout(new GridLayout(1, 0));
mainFrame.setVisible(false);
labPanel=new JPanel(new GridLayout(labSize,labSize));
choicesPanel=new JPanel(new GridLayout(0, 1));
choicesPanel.setLayout(null);
replayButton=new JButton("Replay");
replayButton.setBounds(10, 11, 80, 30);
exitButton=new JButton("Exit");
exitButton.setBounds(10, 51, 80, 30);
choicesPanel.add(replayButton);
choicesPanel.add(exitButton);
mainFrame.getContentPane().add(choicesPanel);
mainFrame.getContentPane().add(labPanel);
}
public void refreshLabShowing(char[][] lab){
labPanel.removeAll();
for(int i=0;i<labSize;i++){
for(int u=0;u<labSize;u++){
labPanel.add(new JLabel(String.valueOf(lab[i][u])));
}
}
mainFrame.pack();
mainFrame.setVisible(true);
}
}
pack() will only work if with layout managers, as pack() itself queries layout manager for required dimension so here, you cannot use absolute layout and pack().

Sending a String from JTextField on one JPanel to JTextArea on another JPanel via a button

I am currently trying to take the typed text in the textField 'itemName' and have it print out on the text area 'printArea.' When I have both printArea and itemName on the same JPanel (p1) it works just fine. When printArea is set to a separate JPanel (itemName on p1 and printArea on p2), nothing prints out. Two JPanels are used to make the GUI appear as it was assigned. The area i Believe to be the issue is where I added JPanel 'p1' to JPanel 'p2'.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MovieGUI extends JFrame{
JButton submit = new JButton("Submit");
JTextField itemName = new JTextField();
JTextField itemPrice = new JTextField();
JTextField itemQuantity = new JTextField();
JTextArea printArea = new JTextArea(400,400);
public MovieGUI(){
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(6, 2));
p1.add(new JLabel("Item Name"));
p1.add(itemName); //p1.add(new JTextField(8));
p1.add(new JLabel("Item Price"));
p1.add(itemPrice); // p1.add(new JTextField(8));
p1.add(new JLabel("Quantity"));
p1.add(itemQuantity); //p1.add(new JTextField(8));
p1.add(new JLabel("submit"));
p1.add(submit);
//Something is not working...
JPanel p2 = new JPanel(new BorderLayout());
p2.setLayout(new BorderLayout());
p2.add(p1, BorderLayout.NORTH);
p2.add(printArea, BorderLayout.SOUTH);
//add(p1);
add(p2);
event e = new event();
submit.addActionListener(e);
}
public class event implements ActionListener{
public void actionPerformed(ActionEvent e){
String text = itemName.getText();
printArea.setText(text); //printArea.setText("BUTTON");
}
}
public static void main(String[] args){
MovieGUI frame = new MovieGUI();
frame.setTitle("Submission");
frame.setSize(800, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Your JPanel p2 does not contain nothing on CENTER alignment, so printArea doesn't view on SOUTH alignment. To see the inputItem text on printArea change from
p2.add(printArea, BorderLayout.SOUTH);
to
p2.add(printArea, BorderLayout.CENTER);
Your text is being printed in printArea, but the first line (and more) of the printArea is hidden behind p1. This is because the south location with printArea is filling the entirety of p2, but it's z-index means it is behind p1. You can see this if you do:
p2.add(printArea, BorderLayout.SOUTH);
printArea.setBackground(Color.BLUE);
p2.setComponentZOrder(printArea, 0); // now the blue printArea hides the form elements in p1
To fix this: change printArea to CENTER instead of SOUTH.
Why?
It helps to understand how BorderLayout works to understand why. It is not splitting up the areas by percentage but it is used to arrange components around a centre panel. The order of the layout is:
North / South components will use their preferred height, and then the width of the component they're in.
I'll ignore East/West in here as you aren't using them.
Centre will use the remaining space after the N/S/E/W components have been sized
Your printArea's preferred height was "huge" (technical term!), so it was trying to use that. Once in a centre panel it is told to use the remaining space only: as p1 has a preferred height that is smaller than the p2 height, the centre panel gets the remaining height and you can still see the printArea. You can also see this effect if you reverse the addition order when using NORTH/SOUTH; you would then only see the printArea, not the p1 form.
If you take a look at the source of BorderLayout in the JDK, you can see the layoutContainer method where this all takes place.

Java Swing simple center of JPanel in other JPanel

I have this incredibly easy task of wanting a nice centered JPanel inside another JPanel. The parent is set to 900, 550, and the child should be approximately 200,400 or so.
To do this, I thought giving the parent a BorderLayout and then setting the setPreferredSize(200, 400) of the child. This child would be in the CENTER. Two empty JPanels would be on the EAST and WEST. Of course this did not work. Giving the two sidepanels a setPreferredSize() of course DID work. Problem with this is that narrowing the Frame causes the center pane to go away.
Here's some sample code that should give show the issue:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Temporary {
public static Temporary myObj = null;
private JFrame mainFrame;
public void go(){
mainFrame = new JFrame("Swing");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setPreferredSize(new Dimension(900,550));
JPanel mainCards = new JPanel(new CardLayout());
mainCards.add(loginLayer(), "Login");
mainFrame.setContentPane(mainCards);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
public JPanel loginLayer(){
JPanel masterPane = new JPanel(new BorderLayout());
JPanel centerPane = new JPanel();
centerPane.setLayout(new BoxLayout(centerPane, BoxLayout.Y_AXIS));
centerPane.setPreferredSize(new Dimension(100,200));
JLabel label = new JLabel("Swing is overly");
label.setAlignmentX(Component.CENTER_ALIGNMENT);
centerPane.add(label);
JButton button = new JButton("complicated");
button.setAlignmentX(Component.CENTER_ALIGNMENT);
centerPane.add(button);
JTextField textField = new JTextField(10);
centerPane.add(textField);
JPanel filler = new JPanel();
JPanel filler2 = new JPanel();
masterPane.add(filler, BorderLayout.WEST);
masterPane.add(centerPane, BorderLayout.CENTER);
masterPane.add(filler2, BorderLayout.EAST);
return masterPane;
}
public static void main(String[] args){
myObj = new Temporary();
myObj.go();
}
}
BorderLayout will, by it's nature, give as much of the available space as it can to the CENTER component. This is how it's designed.
If you want the component to be centered within the parent container, BUT maintain it's preferred size, you should consider using a GridBagLayout instead. Without any additional constraints, this should achieve the result you're after
For example...
public JPanel loginLayer(){
JPanel masterPane = new JPanel(new GridBagLayout);
JPanel centerPane = new JPanel();
centerPane.setLayout(new BoxLayout(centerPane, BoxLayout.Y_AXIS));
JLabel label = new JLabel("Swing is overly");
label.setAlignmentX(Component.CENTER_ALIGNMENT);
centerPane.add(label);
JButton button = new JButton("complicated");
button.setAlignmentX(Component.CENTER_ALIGNMENT);
centerPane.add(button);
JTextField textField = new JTextField(10);
centerPane.add(textField);
masterPane.add(centerPane);
// Add additional borders to providing padding around the center pane
// as you need
return masterPane;
}
I would also avoid actively setting the preferred size of component in this way, as it's possible that the components you're adding to it will exceed your expectations, instead, make use of things like EmptyBorder (for example) to add additional white space arouond the component and it's contents
In Java Swing, you generally want to avoid creating a bunch of statically positioned items with preferred sizes and absolute positions, because things get weird with resizing (as you've noticed). Instead you want to rely on the fluid LayoutManagers. There is an excellent tutorial here. Or, if you want to supply a mock-up of some sort to show the actual UI you are trying to create, I could provide some more feedback.

Changing layout of a JPanel sent to JOptionPane with the pane still running

Trying to change the look of a JOptionPane while its open, depending on which radiobutton the user clicks. What am I doing wrong? It works perfect if I for example add a button and move a JLabel from side to side of the window.
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import static javax.swing.JOptionPane.*;
public class ChangePanel extends JFrame{
private JButton click = new JButton("CLICK ME!");
ChangePanel(){
add(click, BorderLayout.SOUTH);
click.addActionListener(new ButtonListen());
setVisible(true);
setSize(300,100);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public class ButtonListen implements ActionListener{
public void actionPerformed(ActionEvent e){
PopUpPanel pop = new PopUpPanel();
showConfirmDialog(ChangePanel.this, pop, "Changeable", OK_CANCEL_OPTION);
}
}
//Send this as Parameter to the ConfirmDialog
public class PopUpPanel extends JPanel implements ActionListener{
JRadioButton jewelry = new JRadioButton("Jewelry");
JRadioButton shares = new JRadioButton("Shares");
JRadioButton machine = new JRadioButton("Machine");
PopUpPanel(){
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
ButtonGroup bg = new ButtonGroup();
JPanel north = new JPanel();
bg.add(jewelry);
jewelry.addActionListener(this);
bg.add(shares);
shares.addActionListener(this);
bg.add(machine);
machine.addActionListener(this);
north.add(jewelry);
north.add(shares);
north.add(machine);
add(north);
}
//Listener for RadioButtons
public void actionPerformed(ActionEvent e){
JTextField info1Txt = new JTextField(12);
JTextField info2Txt = new JTextField(12);
JTextField info3Txt = new JTextField(3);;
JRadioButton b = (JRadioButton)e.getSource();
if(b.getText().equals("Jewelry")){
//Dummy test text
System.out.println("Jewelry");
JPanel info1 = new JPanel();
info1.add(new JLabel("info1:"));
info1.add(info1Txt);
add(info1);
JPanel info2 = new JPanel();
info2.add(new JLabel("info2:"));
info2.add(info2Txt);
add(info2);
JPanel info3 = new JPanel();
info3.add(new JLabel("info3:"));
info3.add(info3Txt);
add(info3);
validate();
repaint();
}else if(b.getText().equals("Shares")){
//Dummy test text
System.out.println("Shares");
}else
//Dummy test text
System.out.println("Machine");
}
}
public static void main(String[] args){
new ChangePanel();
}
}
As you are working with BoxLayout, you should provide size hints to the PopUpPanel panel, which you haven't given.
When a BoxLayout lays out components from top to bottom, it tries to size each component at the component's preferred height. If the vertical space of the layout does not match the sum of the preferred heights, then BoxLayout tries to resize the components to fill the space. The components either grow or shrink to fill the space, with BoxLayout honoring the minimum and maximum sizes of each of the components.
check out the official tutorial page discussion: BoxLayout Feature
Call revalidate() and repaint() on the container after removing or adding components to it. So if you change the following lines:
validate();
repaint();
to:
revalidate();
repaint();
The content should appear. Though, it will not fit the original size of the JOptionPane. You can override PopUpPanel.getPreferredSize() to return desired size so that JOptionPane is packed properly, ie:
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
You can also use JDialog instead of JOptionPane.
Also, consider using CardLayout instead of swapping components manually. Check How to Use CardLayout for examples.
Why not just use setPreferredSize(new Dimension(300, 300)) in PopUpPanel constructor? Works fine for me. Good eye on revalidate and repaint.

Why is the window too small if I don't resize it?

I am wondering why when I enter this code without resizing the window, I cannot see anything:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GolfScoresGUI
{
public static void main(String[] args)
{
JFrame frame = new JFrame("GolfScoresGUI");
JLabel label = new JLabel("Did you score it? ");
JTextField textField = new JTextField(10);
frame.setVisible(true);
frame.getContentPane().add(textField);
}
}
add your components to a panel on which you call setPreferredSize, add the panel to the frame and call JFrame.pack().
JFrame.pack() updates the size of the frame to take the minimum possible size, given the size on its contained elements.
If you don't call it, the size will be something like 0x0, explaining why you don't see anything.
JFrame frame = new JFrame("GolfScoresGUI");
JPanel panel=new JPanel();
panel.setPreferredSize(new Dimension(600,400)); // Not mandatory. Without this, the frame will take the size of the JLabel + JTextField
frame.add(panel);
JLabel label = new JLabel("Did you score it? ");
JTextField textField = new JTextField(10);
panel.add(label);
panel.add(textField);
frame.setVisible(true);
frame.pack();
EDIT
btw, you should also add this line so that your application stops when you close the frame :
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Everything is fine but you are not specifying any size for that JFrame. That is the problem. Try giving frame.setSize(width,height), or frame.pack(). By using one of this your problem will be solved.
http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html
have a look at this to know about using JFrame in detailed.
Be carefull while using setVisible(true). Try to place setVisible(true) at the end of your GUI code, i.e: use it after adding all the GUI components to the container, because some times when you are adding more components it will not display some components until the frame is resized.

Categories

Resources