Change Background and size of panels in card layout - java

I have some panels in a card layout container (no idea if that is correct terminology). I can't find a way to set the location, or size of these panels inside the container. I tried setBounds and setLayout(null) and I still can't get anything to change.
These are my fields and the constructor. I've gotten my frame working and I can see and use the buttons to change cards, but I really can't change much else about the cards. I set the two card panels two have different backgrounds, but they only make a small boarder of color around the button and leave it in the centre of the screen.
I also don't understand why this isn't pasting my code properly... So sorry!
public class TestPanel extends JPanel implements ActionListener {
CardLayout cl = new CardLayout();
private JPanel panelCont = new JPanel();
private JPanel panel1 = new JPanel();
private JPanel panel2 = new JPanel();
private static JButton but1 = new JButton("Change panels");
private static JButton but2 = new JButton("Change back");
public TestPanel() {
panelCont.setLayout(cl);
panel1.add(but1);
panel2.add(but2);
panel1.setBackground(Color.black);
panel2.setBackground(Color.blue);
panelCont.add(panel1, "1");
panelCont.add(panel2, "2");
cl.show(panelCont, "1");
but1.addActionListener(this);
but2.addActionListener(this);
add(panelCont);
}
}
Thanks. I apologise in advance. I'm finding it hard to understand card layout.

A CardLayout respects the preferred size of the panels added to the layout. That is the size will be the size of the largest panel added to the layout.
I set the two card panels two have different backgrounds, but they only make a small boarder of color around the button and leave it in the centre of the screen.
The default layout for a panel is the FlowLayout. A FlowLayout by default has a 5 pixel horizontal/vertical gap around each component. So the preferred size of your panel is the size of the button plus the 5 pixel gap.
The panel is displaying correctly. When you add other components to the panel the size will change as required.

It's not clear where you pack() the enclosing Window. By default, pack() causes a panel having CardLayout to adopt the the size of the largest panel's preferred size, which is determined by the size of its contents. This example uses setPreferredSize() to specify an arbitrary size, but you can override getPreferredSize() as shown here.

Related

Java Swing BoxLayout layout of outer panel changes when I specify layout of inner panel

I'm very new to Java Swing. I'm using y-axis BoxLayout on an "outer" panel that contains 2 inner panels. Here you can see with this basic code, the 2 inner panels get an equal share of the height avaiable in the box layout (first inner panel yellow, second innner panel orange)
// main test frame
public class MainFrame extends JFrame {
public MainFrame()
{
this.setSize(500, 500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new GridLayout(1,1));
// outer panel: groupWrapPanel with BoxLayout
JPanel groupWrapPanel = new JPanel();
groupWrapPanel.setBackground(Color.blue);
groupWrapPanel.setLayout(new BoxLayout(groupWrapPanel, BoxLayout.Y_AXIS));
// inner panel 1: headerPanel (yellow)
JPanel headerPanel = new JPanel();
headerPanel.setBackground(Color.yellow);
groupWrapPanel.add(headerPanel);
// inner panel 2: headerNotesWrap (orange)
JPanel headerNotesWrap = new JPanel();
headerNotesWrap.setBackground(Color.orange);
groupWrapPanel.add(headerNotesWrap);
this.add(groupWrapPanel);
this.setVisible(true);
}
}
But then when I add seperate layout manager to one of the inner panels, the layout of the outer panel changes, and the 2 inner panels no longer get an equal share of the height of the outer panel. I can do this by adding a single line of code:
headerPanel.setLayout(new BorderLayout());
Can someone please explain why the layout of the outer panel changes when I specify a layout manager for the inner panel, and how I can prevent this.
Thank you.
EDIT
This is a related question and is in response to a comment someone made.
"A BoxLayout will determine the preferred size of each component. If there is extra space available it will then allocate the space equally up to the maximum size of each component. That would explain why each panel is 50/50 in the first case."
If that's the case, how come if I change the 2 inner components from panels to labels, they no longer stretch to fill the available space inside out the outer panel? like so:
public class MainFrame extends JFrame {
public MainFrame()
{
// we're going to create what shall be known as a "Group Box",
// which groups things together
this.setSize(500, 500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new GridLayout(1,1));
// outer panel: groupWrapPanel with BoxLayout
JPanel groupWrapPanel = new JPanel();
groupWrapPanel.setBackground(Color.blue);
groupWrapPanel.setLayout(new BoxLayout(groupWrapPanel, BoxLayout.Y_AXIS));
// inner label 1
JLabel label1 = new JLabel("Label 1");
label1.setBackground(Color.yellow);
label1.setOpaque(true);
groupWrapPanel.add(label1);
// inner label 2
JLabel label2 = new JLabel("Label 2");
label2.setBackground(Color.orange);
label2.setOpaque(true);
groupWrapPanel.add(label2);
this.add(groupWrapPanel);
this.setVisible(true);
}
}
Thanks again
I added the following to your code:
setVisible(true);
System.out.println(headerPanel.getPreferredSize());
System.out.println(headerPanel.getMaximumSize());
System.out.println(headerNotesWrap.getPreferredSize());
System.out.println(headerNotesWrap.getMaximumSize());
and got the following output when using the BorderLayout:
java.awt.Dimension[width=0,height=0]
java.awt.Dimension[width=2147483647,height=2147483647]
java.awt.Dimension[width=10,height=10]
java.awt.Dimension[width=32767,height=32767]
You can see that the BorderLayout maximum size is much larger than that of the FlowLayout.
So when the extra space is allocated proportionally the BorderLayout panel gets a lot more.
A few possible solutions:
Override the getMaximumSize() method of your panels that use a BorderLayout to return an appropriate value.
Use a GridBagLayout. You can also stack panels in a single column.
Try using the Relative Layout which can function similar to a BoxLayout and just stack panels.

JButton keep position in the center

So I'm making sample GUI using outer and inner class. I made a two inner classes. First the parent class which is the "first panel" second I made a child class which is the "second panel" where I add the JButton using GridBagLayout. My problem is it wont move in the location I want. I assigned my gridx = 2 and gridy = 1. But it won't move. Any help will appreciate thanks!
public class Login extends JFrame{
mainPanel mainpanel = new mainPanel(); // I create a class object for mainPanel so I can set as ContentPane.
//Constructor
public Login(){
setSize(500,400);
setTitle("Login Sample");
setVisible(true);
setLocationRelativeTo(null);
getContentPane().add(mainpanel);
//Window Listener
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}//window Closing
});
}
class mainPanel extends JPanel { //InnerClass
firstPanel firstpanel = new firstPanel();
//Constructor
public mainPanel(){
setPreferredSize(new Dimension (500,400));
setLayout(new BorderLayout());
setBorder(BorderFactory.createLineBorder(Color.green, 3));
add(firstpanel);
}
class firstPanel extends JPanel{
//Create Button
JButton loginButton = new JButton("Login");
//Constraints
GridBagConstraints loginConstraints = new GridBagConstraints();
public firstPanel(){
setLayout(new GridBagLayout());
loginConstraints.gridx = 1;
loginConstraints.gridy = 2;
add(loginButton,loginConstraints);
}
}
JButton keep position in the center
The reason your JButton keeps centering itself to the center of the Frame has nothing to with inner class. Every container (e.g. JPanel, JFrame) has a default layout.
The default layout of JPanel is FlowLayout. Under this layout, all components added will be arranged in a linear fashion in a row for as much as possible the panel width can fit. Anything more than the panel's width will be pushed to the next row. The default alignment of flow layout used by the JPanel is FlowLayout.CENTER, that is why when you only add one button, it always center itself.
Since it has a layout governing the positioning of your components, attempts to change the components' positions may become futile.
My problem is it wont move in the location I want. I assigned my gridx = 2 and gridy = 1. But it won't move
If you want your components to move to a specific location specified by you, you can set the layout to null (absolute positioning). However by doing so, you will have to set the location of every components which is added by you manually. If not, the components will not even show up in the frame.
To set a panel's layout to null, you may do this:
JPanel pnlMain = new JPanel();
pnlMain.setLayout(null);
To set the location of the components, we can use setBounds():
JButton btn = new JButton();
btn.setBounds(x, y, width, height); //set location and dimension
However, setting containers' layout to null can give you many unforeseen problems. With the layout being removed and all positioning being hard coded, you are left with little or no control when your program are used in different systems and environment. Various usage by users can also cause unforeseen problems as well (e.g. When user resize your window).
First i want to say that if you just have a component and want it centered, its easy to use BorderLayout and add it(the component) "Center" to the parent. The GridbagLayout is not working like this since you dont have components in gridx = 0 and gridy = 0. The grid is calculated by the components size inside. When you want to do it with the GridBagLayout you have to configure more e.g.
anchor:
Used when the component is smaller than its display area to determine where (within the area) to place the component. Valid values (defined as GridBagConstraints constants) are CENTER (the default), PAGE_START, PAGE_END, LINE_START, LINE_END, FIRST_LINE_START, FIRST_LINE_END, LAST_LINE_END, and LAST_LINE_START.
But i think its to much effort for i guess you want to do:
https://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html

Multiple JPanels in one JFrame not showing top panel

So I'm writing a program in which I wish to have a single JFrame containing a JPanel header in a separate colour and directly underneath have a grid of buttons in a separate JPanel. So far my program works perfectly except for the fact that the header String isn't showing up in the NORTH panel. Instead I'm getting a box containing the set background colour with a small grey box in the centre. I'm wondering if I didn't set the size of the panel correctly?
I have heard this can be accomplished using JLabel, but when I tried to do this, it would not show the background colour that I had set.
So, could anyone please show me how to achieve the following either with the JPanel (preferably because I would like to know how it works and what I'm missing) or with JLabel: filling that little grey box in the middle of the header with a String.
Here is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Example {
public static void main(String[] args) {
// Initialize a panel for the header, and mainGrid which will contain buttons
JPanel panel = new JPanel();
JPanel header = new JPanel();
JPanel mainGrid = new JPanel();
// Initialize the header
DisplayPanel message = new DisplayPanel();
header.setBackground(Color.ORANGE);
header.add(message);
// Initialize the mainGrid panel
mainGrid.setLayout(new GridLayout(2,2,2,2));
mainGrid.add(new JButton("1"));
mainGrid.add(new JButton("2"));
mainGrid.add(new JButton("3"));
mainGrid.add(new JButton("4"));
// Add the two subpanels to the main panel
panel.setLayout(new BorderLayout());
panel.add(header, BorderLayout.NORTH); // The issue is this panel isn't displaying the String created in DisplayPanel
panel.add(mainGrid, BorderLayout.CENTER);
// Add main panel to JFrame
JFrame display = new JFrame("Test");
display.setContentPane(panel);
display.setSize(200,100);
display.setLocation(500,200);
display.setVisible(true);
display.setResizable(false);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private static class DisplayPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("header" , 20, 20); // The string I want to be displayed
}
}
}
I would very much appreciate anyone's help or input as I have only been studying Java for a few months and this is my first post. Thank you in advance.
Also, any general tips on writing that you may have would be greatly appreciated.
I'm wondering if your problem is that you're nesting your message JPanel inside of the header JPanel, and the container header JPanel uses the JPanel default FlowLayout. Thus the component it holds won't expand on its own and will remain trivially small.
Consider either giving the header JPanel a BorderLayout so that message expands inside of it, or
use a JLabel to show your text, not a JPanel's paintComponent method. The JLabel should size itself to be big enough to show its text. If you do this and want it to show a background color, all you have to do is call setOpaque(true) on your JLabel, and you're set.
Actually, if you nest the JLabel, then there's no need to make it opaque. Just do this:
JPanel header = new JPanel();
JPanel mainGrid = new JPanel();
JLabel message = new JLabel("Header", SwingConstants.CENTER);
header.setBackground(Color.ORANGE);
header.setLayout(new BorderLayout());
header.add(message);
I would highly recommend using a GUI builder WYSIWYG IDE, like NetBeans, where you can easily drag and drop components to where they need to be. If you're doing any sort of complex GUI layout, it can be madness (and in my opinion, nonsensical) trying to write and maintain the code.
The layout your trying to implement would be trivial in NetBeans.

JPanel Positioning using the Border Layout not working

I am trying to setup my JPanel's position to the right using i.add(jp, BorderLayout.EAST); but it is not working. Any ideas why? Thanks for the help in advance.
/* INSTANCE DECLARATIONS */
private JTextField tf;//text field instance variable
private JLabel jl2;//label instance variable
/*****************
* WINDOW METHOD *
* ***************/
public void window() {
LoadImageApp i = new LoadImageApp();//calling image class
JFrame gameFrame = new JFrame();//declaration
JPanel jp = new JPanel();
JLabel jl = new JLabel("Enter a Letter:");//prompt with label
tf = new JTextField(1);//length of text field by character
jl2 = new JLabel("Letters Used: ");
jp.add(jl);//add label to panel
jp.add(tf);//add text field to panel
jp.add(jl2);//add letters used
gameFrame.add(i); //adds background image to window
i.add(jp, BorderLayout.EAST); // adds panel containing label to background image panel
gameFrame.setTitle("Hangman");//title of frame window
gameFrame.setSize(850, 600);//sets size of frame
gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//exit when 'x' button pressed
gameFrame.setIconImage(new ImageIcon("Hangman-Game-grey.png").getImage());//set the frame icon to an image loaded from a file
gameFrame.setLocationRelativeTo(null);//window centered
gameFrame.setResizable(false);//user can not resize window
gameFrame.setVisible(true);//display frame
}//end window method
What layout manager does i, your LoadImageApp instance, use? I'm betting it's not BorderLayout. I'm betting that the LoadImageApp class extends JPanel and if so and if you never explicitly set its layout, then it uses a FlowLayout by default, and as you're finding out, FlowLayout doesn't respect the BorderLayout.EAST int constant.
The solution is likely quite simple: make it use a BorderLayout:
setLayout(new BorderLayout());
Edit
You state in comment:
When I set the border layout of i to EAST, my background image shifts to the right also, is there a way to get around that?
No, you're missing the point. You need to set the layout of LoadImageApp to BorderLayout. You're not supposed to add i BorderLayout.EAST. This was never recommended to you.
i.e.,
public class LoadImageApp extends JPanel {
// in the constructor
public LoadImageApp() {
setLayout(new BorderLayout());
}
// .... etc....
}
THe LoadImageApp instance (which I would name loadImageApp, not i), should be added BorderLayout.CENTER, which you were doing before. Please read the layout manager tutorials which you can find here.

JTabbedPane in JPanel?

I have a simple problem when I want to add tabs in my jpanel. The alignment of the tabs get horizontal instead of vertical, wich looks like crap =/.
It looks like this:
If I discard the panel instead and add the tabbedPane directly to the frame, everything works fine.
If you uncomment the three lines of code and remove the getContentPane().add(jtp); you can reproduce my probleme.
working Code:
public class TabbedPane extends JFrame
{
public TabbedPane()
{
setTitle("Tabbed Pane");
setSize(300, 300); // set size so the user can "see" it
JTabbedPane jtp = new JTabbedPane();
// JPanel panel = new JPanel();//uncomment all three lines
// panel.add(jtp);
// getContentPane().add(panel);
getContentPane().add(jtp);//remove me
JPanel jp1 = new JPanel();// This will create the first tab
JPanel jp2 = new JPanel();// This will create the second tab
JLabel label1 = new JLabel();
label1.setText("This is Tab 1");
jp1.add(label1);
jtp.addTab("Tab1", jp1);
jtp.addTab("Tab2", jp2);
JButton test = new JButton("Press");
jp2.add(test);
setVisible(true); // otherwise you won't "see" it
}
public static void main(String[] args)
{
TabbedPane tab = new TabbedPane();
}
}
Thanks a lot!
If I discard the panel instead and add the tabbedPane directly to the frame, everything works fine.
The default layout of JPanel is FlowLayout, which "lets each component assume its natural (preferred) size." The default layout of JFrame is BorderLayout, the CENTER of which ignores preferred size. In either case, invoking setSize() precludes the layout from functioning initially; re-size the frame to see the effect. Instead, use pack(), which "Causes this Window to be sized to fit the preferred size and layouts of its subcomponents."
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true); // otherwise you won't "see" it
There are many things I would change in that code, starting with the recommendations of #trashgod. OTOH this is the minimal change needed in order to stretch the tabbed pane to the width/height of the parent container.
// give the panel a layout that will stretch components to available space
JPanel panel = new JPanel(new GridLayout());//uncomment all three lines
panel.add(jtp);
getContentPane().add(panel);
//getContentPane().add(jtp);//remove me
For more details see this answer.
Well firstly you can try this:
JPanel panel = new JPanel();//uncomment all three lines
panel.setLayout(new GridLayout());
JPanel jp1 = new JPanel();// This will create the first tab
JPanel jp2 = new JPanel();// This will create the second tab
JLabel label1 = new JLabel();
label1.setText("This is Tab 1");
jp1.add(label1);
jtp.addTab("Tab1", jp1);
jtp.addTab("Tab2", jp2);
JButton test = new JButton("Press");
jp2.add(test);
getContentPane().add(jtp);
and in the main:
TabbedPane tab = new TabbedPane();
tab.pack();
tab.setVisible(true);
May I suggest using MigLayout to set layouts, it will make your life easier. Hope it helps.
Try GridbagLayout. Once you have mastered it, you can design UI of any sort with this layout.
I agree with prasanth regarding the use of GridBagLayout
I have gone through this problem once and I solved it by adding the JTabbedPaneto the panel via GridBagLayout, make sure you add the JTabbedPane using the ipadx and ipady according to your requirements in your GridBagConstraints object
e.g.
JPanel myPanel=new JPanel();
myPanel.setLayout(new GridBagLayout());
JTabbedPane jTP=new JTabbedPane();
jTP.add("Tab1",new JPanel());//substitute your component instead of "new JPanel"
GridBagConstraints myConstraints=new GridBagConstraints();
myConstraints.ipadx=400;//streches the component being added along x axis - 200 px on both sides
myConstraints.ipady=600;//streches the component being added along y axis - 200 px on both sides
myPanel.add(jTP,myConstraints);
You can adjust both these properties according to what is perfect for your need

Categories