Make JButton stretch to fit JPanel - java

I'm trying to get my buttons to fill the width of my panel, this is my code that
makes a buttons and a panel and then just adds the button to the panel.
buttonPane = makeButtonPanel();
button = makeButton("Hello");
button2 = makeButton("World");
buttonPane.add(button);
buttonPane.add(button2);
private JButton makeButton(String msg){
JButton button = new JButton(msg);
button.setAlignmentX(Component.CENTER_ALIGNMENT);
return button;
}
private JPanel makeButtonPanel(){
JPanel btnPanel = new JPanel();
btnPanel.setLayout(new BoxLayout(btnPanel, BoxLayout.Y_AXIS));
btnPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
return btnPanel;
}
This is the output I am getting...

How the button fits it's container depends on the layout of the container. If you want it to stretch you could make the button panel have a BorderLayout and add the button to the north position, or use any of the other layout types whose components attempt to try to occupy as much room as they can (BorderLayout with north is just one example).
For multiple buttons stretched widthwise out as much as they can go, place a container in the North position instead of a single button, where that container contains multiple JButtons. That container should probably be a JPanel with a GridLayout, 1 column, as many rows as you have buttons.

Related

How do i use border layouts?

I'm currently working on Layouts in Java. I'm trying to combine different layouts. So i have created a login Screen using Spring Layout, GridLayout and Border Layout.
The MainFrame (JFrame) uses GridLayout. The GridLayout consists of 2 Panel (North Panel and Main Panel). The Main Panel consists of the Jlabel, JTextfield and JButton of which I have no problem of. My problem is in the North Panel which uses Border Layout. It contains a JLabel (lblWelcome). I have been trying to bring the label to the center of the panel using Border Layout but it still aligns to the left. This is the below code:
JLabel lblWelcome = new JLabel("Welcome To The Login Screen");
JPanel northPanel = new JPanel(new BorderLayout());
northPanel.setBackground(Color.green);
northPanel.add(lblWelcome, BorderLayout.CENTER);
Login Screen :
Your JLabel is actually correctly centered, but its text isn't.
Simply change its creation to :
JLabel lblWelcome = new JLabel("Welcome To The Login Screen", SwingConstants.CENTER);

Toggling between JPanels (hide/show)

I have two JPanels that sit on top of one another. The 'top' panel holds many widgets (JButtons, JTextFields, etc.). One of the buttons will initiate an action to display a number of images.
These images are displayed on the other JPanel. So, when this button is clicked, I want to hide the control panel and display the images panel. Sounds pretty simple.
Here is the code (I've omitted a lot of stuff that I don't think is relevant). In the constructor, if I switch which panel is visible when the app launches, it looks fine either way. When I click the button, I should go from my dark gray control panel to my blue images panel. Except that what happens is my dark gray control panel becomes an empty white panel. Any ideas?
public GUI() {
JFrame frame = new JFrame();
...
JPanel imagesPanel = new ImagesPanel();
imagesPanel.setBackground(Color.BLUE);
imagesPanel.setVisible(false);
frame.getContentPane().add(imagesPanel, BorderLayout.CENTER);
// make a JPanel to hold all of the buttons and text fields
JPanel imagesPanel = new ImagesPanel();
controlPanel.setBackground(Color.DARK_GRAY);
controlPanel.setVisible(true);
frame.getContentPane().add(controlPanel, BorderLayout.CENTER);
...
JButton btnDisplayImages = new JButton("Display Images");
btnDisplayImages.setPreferredSize(standardButtonSize);
btnDisplayImages.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
imagesPanel.setVisible(true);
controlPanel.setVisible(false);
frame.repaint();
frame.setVisible(true);
}
});
// button added to control panel
...
}
Use CardLayout. (docs.oracle.com/javase/tutorial/uiswing/layout/card.html)
final String IMAGES_PANEL = "Images Panel";
final String CONTROL_PANEL = "Control Panel";
CardLayout cardLayout;
JPanel cards;
//Where the components controlled by the CardLayout are initialized:
//Create the "cards".
JPanel card1 = new JPanel();
...
JPanel card2 = new JPanel();
...
//Create the panel that contains the "cards".
cardLayout = new CardLayout();
cards = new JPanel(cardLayout);
cards.add(card1, IMAGES_PANEL);
cards.add(card2, CONTROL_PANEL);
...
//Show images panel
cardLayout.show(cards,IMAGES_PANEL);
...
//Show control panel
cardLayout.show(cards, CONTROL_PANEL);

Need "non-rectangular Card Layout Panel" or "Transparent component"

I've got a new requirement to change my display.
Currently I have a row of 3 radio buttons sitting above a Panel with a card layout. The buttons CONTROL which card of the Card Layout Panel is displayed. But this, it seems, wastes valuable screen real estate.
The row of buttons can easily be transformed to a column of buttons using a GridLayout(4,1) on the panel that owns them and their title label. This panel could then theoretically be placed in the upper left corner of the each of the cards displayed in the card layout panel, and the top row of each card could be moved up to the right of the button panel, allowing more space for what has to come below.
But what shall be the containment model for this? In this variant, the button panel must appear on each card. Who owns it? Logically it needs to be owned by the parent panel on which all this sits, but it won't display on the cards, which will cover it over - unless I could
add the button panel to each card at the moment of its display, which would probably be messy and maybe cause flicker.
make the top left corner of each card be transparent, allowing it to show the upper left button panel owned by its parent. But how would I do that?
Other solutions?
Maybe
Have two card layout panels controlled by the radio buttons. The upper right one that contains all but the the button panel and the lower component that sits below both.
It sounds like you could use a JLayeredPane as the parent component of both, the panel containing the radio buttons and the card panel.
JLayeredPane allows its child components to overlap, each child belonging to a layer.
To specify the layer, you can pass an Integer constant into the JLayeredPane's add(Component, Object) method as the constraint argument. The integer constants are defined in the JLayeredPane class itself. You can use JLayeredPane.DEFAULT_LAYER for the card panel and JLayeredPane.PALETTE_LAYER for the radio button panel.
Having set the layer, you'll still have to position the two panels correctly in x,y space. I would recommend just overriding the JLayeredPane's doLayout() method with something like this (haven't tested):
public void doLayout()
{
cardPanel.setBounds( new Rectangle( getSize() ));
radioButtonPanel.setBounds( new Rectangle( radtioButtonPanel.getPreferredSize() ));
}
You may be able to use OverlayLayout to display the control panel in the top-left of your card panel.
I would forget the transparency idea. Just put the options as a list to the left of (or right of, or over/under) the card panel. I would definitely NOT put the panel of controls on the CardPanel itself. It should be outside.
The list of selections could be radios, buttons, or in this example, a JList of items that can grow w/o messing up the layout. For example:
/*
* CardLayoutDemo.java
*/
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
#SuppressWarnings("unchecked")
public class CardLayoutDemo implements Runnable
{
final static String CARD1 = "Gray Panel";
final static String CARD2 = "Blue Panel";
final static String CARD3 = "Green Panel";
JPanel cards;
CardLayout cl;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new CardLayoutDemo());
}
public void run()
{
final JList jList = new JList(new String[]{CARD1, CARD2, CARD3});
jList.setPrototypeCellValue("XXXXXXXXXXXX");
jList.setVisibleRowCount(5);
jList.setSelectedIndex(0);
jList.addListSelectionListener(new ListSelectionListener()
{
#Override
public void valueChanged(ListSelectionEvent e)
{
String name = jList.getSelectedValue().toString();
cl.show(cards, name);
}
});
JScrollPane scroll = new JScrollPane(jList);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
Dimension dim = new Dimension(300, 300);
JPanel card1 = new JPanel();
card1.setBackground(Color.GRAY);
card1.setPreferredSize(dim);
JPanel card2 = new JPanel();
card2.setBackground(Color.BLUE);
card2.setPreferredSize(dim);
JPanel card3 = new JPanel();
card3.setBackground(Color.GREEN);
card3.setPreferredSize(dim);
cl = new CardLayout();
cards = new JPanel(cl);
cards.add(card1, CARD1);
cards.add(card2, CARD2);
cards.add(card3, CARD3);
JFrame f = new JFrame("CardLayout Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(scroll, BorderLayout.WEST);
f.add(cards, BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
If you wanted a label for the selections, just make a "selection panel" that contains the JLabel and the JScrollPane (or use your grid of buttons panel), and put it in Borderlayout.WEST (instead of the adding the JScrollPane directly).
Also, look into JTabbedPane as an alternative.

Change Background and size of panels in card layout

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.

How to make JLabel consume space when not visible?

I have a program which creates 2 Panels and then places a label and two buttons in them. The label is set to invisible setVisible(false) and then the two buttons are added and the frame is packed. When i click the first button, the label is shown, setVisible(true), and the seccond one hides it again, setVisible(false). When i click each button, they move to fill the space of the label as it hides, and move again to get out of the way of the label as it is shown. I want to stop this from happening and have the buttons stay in the same place even when the label is hidden.
Here is the code:
public class MainFrame extends JFrame{
public JLabel statusLabel;
public JButton show;
public JButton hide;
public MainFrame(){
super("MagicLabel");
JPanel topPanel = new JPanel(); //Create Top Panel
statusLabel = new JLabel(""); //Init label
statusLabel.setVisible(false); //Hide label at startup
topPanel.setSize(400, 150); //Set the size of the panel, Doesn't work
topPanel.add(statusLabel); //Add label to panel
JPanel middlePanel = new JPanel(); //Create Middle Panel
show= new JButton("Show"); //Create show button
hide= new JButton("Hide"); //Create hide button
middlePanel.setSize(400, 50); //Set the size of the panel, Doesn't work
middlePanel.add(show); //Add show button
middlePanel.add(hide); //Add hide button
this.add(topPanel, "North"); //Add Top Panel to North
this.add(middlePanel, "Center"); //Add Middle Panel to Center
addActionListeners(); //void:adds action listeners to buttons
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(100, 100, 512, 400);
this.setPreferredSize(new Dimension(400,200)); //Set size of frame, Does work
this.pack();
this.setVisible(true);
}
public void animateInstall(boolean var0){ //Void to show and hide label from action listeners
statusLabel.setVisible(var0);
sendWorkingMessage("Boo!");
}
public void sendWorkingMessage(String message){ //Void to set text of label
this.statusLabel.setForeground(new Color(225, 225, 0));
this.statusLabel.setText(message);
}
void addActionListeners(){
show.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
animateInstall(true);
}
});
hide.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
animateInstall(false);
}
});
}
this.setPreferredSize(new Dimension(400,200));
this.setMinimumSize(new Dimension(400,200));
So pack() cannot interfere.
Use CardLayout. Add the JLabel and empty JPanel. Instead of seting it visible/invisible swap the cards showing the JLabel or the JPanel when necesary.
Extending JFrame is not advisable, better extend JPanel put all your components inside and then add it to a JFrame
You need to learn how to use SwingUtilities.invokeLater(): See example how your should look like
You need to learn about Layout: Tutorial
Very dumb and easy approach in your code would be:
this.statusLabel.setForeground(bgColor); //background color
this.statusLabel.setText(" "); //some number of characters
By default for you frame you are using BorderLayout. You can try to have like:
this.add(topPanel, BorderLayout.NORTH); //Add Top Panel to North
this.add(middlePanel, BorderLayout.SOUTH); //Add Middle Panel to South
rather than at center.
Or you can create an intermediate container panel for these 2 panels, or consider other layout managers like BoxLayout, etc

Categories