CardLayout - How to Delete current card (Java Swing) - java

How would one delete the current card that the user is on. I know how to go through a card layout using the next and previous function, but how would one remove the current frame that the user is on? For example, if I have a program where I am currently on the 3rd panel out of 5 total panels, how would I delete the current one which is the 3rd panel. Once you remove it, the next or previous one replaces it. I do not think removecurrentlayout can be used cause I am not removing a component. For example, in the code, how would I go about delete Card 3 if I am on that.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CardLayoutProg {
public static void main(String[] args) {
JFrame frame = new JFrame("CardLayout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
JPanel buttonPanel = new JPanel();
JButton nextButton = new JButton("Next");
buttonPanel.add(nextButton);
contentPane.add(buttonPanel, BorderLayout.SOUTH);
final JPanel cardPanel = new JPanel();
final CardLayout cardLayout = new CardLayout();
cardPanel.setLayout(cardLayout);
for (int i = 1; i <= 5; i++) {
JButton card = new JButton("Card " + i);
card.setPreferredSize(new Dimension(200, 200));
String cardName = "card" + 123123;
cardPanel.add(card, cardName);
}
contentPane.add(cardPanel, BorderLayout.CENTER);
nextButton.addActionListener(e -> cardLayout.next(cardPanel));
frame.pack();
frame.setVisible(true);
}
}

If you look at the docs for Container, you will see that it has a remove() method. Since JPanel extends Container, it also has this method. You should familiarize yourself with these API docs to find this kind of information.

Unfortunately the CardLayout does not tell you which card (JPanel) is currently being displayed.
Check out Card Layout Focus for a class that extends the CardLayout to provide this functionality.
You would use the getCurrentCard() method to access the panel currently being displayed.
Then once you get the card currently being displayed you can remove it from the parent panel using by the remove(...) method of the Container class.
You would just use the class as follows:
//final CardLayout cardLayout = new CardLayout();
final RXCardLayout cardLayout = new RXCardLayout();
The logic for your "Remove" button would be:
cardPanel.remove(cardLayout.getCurrentCard());

When you say index(3rd panel of 5 panels), you mean the name (String) of the component when it was inserted, right? I don't know any elegant way to do this, but you can try to get all the components in this container (parentComponent) and try to find the one that has the same name as your index. For example:
Component[] components = parentComponent.getComponents();
for(int i = 0; i < components.length; i++) {
if(components[i].getName().equals(index)) {
cardLayout.removeLayoutComponent(components[i]);
}
}

Related

Keeping components horizontally aligned using a flow layout manager

For reasons I won't discuss in detail, I am limited to using a flow layout manager. The obvious problem with this and my necessity to keep components on the same line, is that it pushes components further down the frame is they surpass the panel edges.
Are there methods I can use to align components to make sure that labels and their corresponding text fields appear on the same line?
If I have understood correctly, the main problem is that the label and the input are separated (the label on the right side, and the input in the next line on the left).
One solution for that problem is the group the label and the input field into a sub panel, and add this sub panel to the main panel which uses the FlowLayout.
The code below illustrates this technique:
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
/**
*
* #author acampos
*/
public class Main02 {
public static void main(String[] args) {
JFrame jFrame = new JFrame();
JPanel mainPanel = new JPanel();
JPanel dynamicPanel;
JLabel dynamicLabel;
JTextField dynamicInput;
for (int i = 0; i < 5; i++) {
// Creates the panel that will contain the Label AND the Input
dynamicPanel = new JPanel();
// Creates the dynamic label
dynamicLabel = new JLabel("Label " + i + ": ");
// Creates the dynamic text field
dynamicInput = new JTextField(10);
// Adds the label and the text field to the dynamic panel
dynamicPanel.add(dynamicLabel);
dynamicPanel.add(dynamicInput);
dynamicPanel.setSize(100, 100 );
// Adds the dynamic panel to the main panel <-- HERE IS THE KEY
mainPanel.add(dynamicPanel);
}
// Set the FlowLayout to the MAIN PANEL, so the dynamic panels
// will 'flow' but the label and the text field will be kept together
mainPanel.setLayout(new FlowLayout(3));
// Adds the main panel (which contains the dynamic panels) to the main frame
jFrame.add( mainPanel );
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setVisible(true);
jFrame.setSize(600, 150);
jFrame.setResizable(true);
}
}
When you run this code (yes, you can run it) and change the jFrame's size you see that the label and the input don't split anymore.
Note: For the next questions, I strongly suggest you that you share your code with the community. That's a good practice that is more detailed on https://stackoverflow.com/help/how-to-ask

how would i change my code to cardLayout

package garage;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
*
* #author Jela
*/
public class VehicleParts extends JPanel {
public VehicleParts() {
JPanel card0 = new JPanel();
//card0.setPreferredSize(new Dimension(800, 600));
JPanel card1 = new JPanel(new BorderLayout());
JPanel card2 = new JPanel(new BorderLayout());
JPanel card3 = new JPanel(new BorderLayout());
JLabel zero = new JLabel("0");
JLabel one = new JLabel("1");
JLabel two = new JLabel("2");
JLabel three = new JLabel("3");
card0.add(zero);
card1.add(one);
card2.add(two);
card3.add(three);
card1.setVisible(false);
card2.setVisible(false);
card3.setVisible(false);
card0.setVisible(false);
JButton buttonZero = new JButton("Repair");
JButton buttonOne = new JButton("Parts");
JButton buttonTwo = new JButton("Stock");
JButton buttonThree = new JButton("Supplier");
//JButton buttonback = new JButton("Parts");
buttonZero.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
card0.setVisible(true);
card1.setVisible(false);// shows card1 when button is clicked
card2.setVisible(false);
card3.setVisible(false);
}
});
buttonOne.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
card1.setVisible(true);// shows card1 when button is clicked
card2.setVisible(false);
card3.setVisible(false);
card0.setVisible(false);
}
});
add(buttonZero);
add(buttonOne);
add(buttonTwo);
add(buttonThree);
add(card0);
add(card1);
add(card2);
add(card3);
}
}
Im not sure how i would change this code into CardLayout. If anyone can give me tips of how i could change it, please tell me. This is not my main class. Ive tried cardlayout, however whenever i use it, i cannot see my buttons anymore.
To make sure the buttons are visible using all the cards, you simply divide the panel into two panels - one panel that will contain the buttons, and the other that will contain the cards.
So - your main panel (VehicleParts) will have a BorderLayout.
You add two panels to it. One is the cards panel. It will have a CardLayout. Make the cards panel reference variable final, so that you can access it from the buttons' event listeners (which are anonymous classes). Although the cards panel itself has a card layout, you add it to your main panel using BorderLayout.CENTER.
The other panel is the buttons panel. It can have a GridLayout, for example. Add it to the main panel using, perhaps, BorderLayout.SOUTH to put it at the bottom.
Add your cards to the cards panel. Don't forget to give them names.
Then create the buttons, and in each button's listener, change cards using the CardLayout.show() method. Add each button to the buttons panel.

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();
}

The panel or buttons aren't being displayed on the frame

import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Frame extends JFrame {
private JPanel buttonPanel;
private JButton[][] buttons;
private JPanel otherPanel;
public Frame() {
setSize(500, 600);
setLocation(100, 100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
setResizable(false);
setVisible(true);
buttonPanel = new JPanel();
buttonPanel.setLocation(0, 0);
buttonPanel.setSize(500, 500);
buttonPanel.setLayout(new GridLayout(8, 8));
buttons = new JButton[8][8];
for(int i = 0; i < 8; i++){
for(int j = 0; j < 8; j++){
buttons[i][j] = new JButton("" + i);
buttonPanel.add(buttons[i][j]);
}
}
add(buttonPanel);
}
}
the buttons are supposed to be put on the panel and then the panel is put on the frame. when its run however nothing is shown on the frame
thanks for the help
Look at where you're setting the JFrame visible. And then look at where you're adding your buttons. Kind of out of order, don't you think? It's like taking a picture of a chair, and then after doing that, asking someone to sit in the chair. If you want to take a portrait, have them sit in the chair first, and then take the picture. Call setVisible(true) after adding all components.
Get rid of your use of null layout as this makes for very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain. Instead you will want to study and learn the layout managers and then nest JPanels, each using its own layout manager to create pleasing and complex GUI's that look good on all OS's.
where is the main ?
also you have to make an object from JFrame and use it to add these methods, example JFrame f=new JFrame;
f.setSize(..,..);
and so on..

Last button in JFrame is set as background?

import javax.swing.JButton;
import javax.swing.JFrame;
public class Test extends JFrame {
private static final long serialVersionUID = 1L;
public Test() {
super("A test");
setSize(360,300);//Size of JFrame
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);//Sets if its visible.
JButton num1 = new JButton("1");//Set the JButton name
JButton num2 = new JButton("2");
JButton num3 = new JButton("3");
num1.setBounds(80,70,50,50);
num2.setBounds(130,70,50,50);
num3.setBounds(180,70,50,50);
add(num1);
add(num2);
add(num3);
}
public static void main (String[] args) {
new Test().setVisible(true);
}
}
Here the num3 button is set as the background, I want the buttons to be aligned. This might be a trivial mistake I'm not sure as I've just started working with JFrame. Thank you.
The Problem
Basically, there are three parts that are causing this problems...
JFrame uses a BorderLayout by default. This means that only the last component add to any one of the five available layout positions will be managed
You call setVisible(true) before adding anything to the frame
You call setBounds on the buttons.
Because the components are generally painted in z-order (in FIFO order generally) and because of the optimisation in the code, the last button is been controlled by the BorderLayout of the frame, but the other two maintain the bounds you set before
Really interesting problem
Solution(s)
Use an appropriate layout manager, maybe a FlowLayout or GridBagLayout
Call setVisible last where ever possible
Check out Laying Out Components Within a Container for details
This is because of Layout Manager. Please check the code below.
i use another JPanel to put all the buttons. i set the panel as it will have 1 row and 3 columns objects.
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test extends JFrame {
private static final long serialVersionUID = 1L;
JPanel buttonPanel;
public Test() {
super("A test");
setSize(360,300);//Size of JFrame
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);//Sets if its visible.
setLayout(null);
buttonPanel = new JPanel(new GridLayout(1, 3));
buttonPanel.setBounds(80, 70, 150, 50);
JButton num1 = new JButton("1");//Set the JButton name
JButton num2 = new JButton("2");
JButton num3 = new JButton("3");
buttonPanel.add(num1);
buttonPanel.add(num2);
buttonPanel.add(num3);
add(buttonPanel);
}
public static void main (String[] args) {
new Test().setVisible(true);
}
}
Well, never use raw placing and no Layout Manager.
This is your Bible
You can do that with some Layout tricks. For example this one:
First of all import the Layout classes.
import java.awt.GridLayout;
import java.awt.BorderLayout;
Make the frame a BorderLayout frame by copying this in the constructor of it.
setLayout(new BorderLayout());
Then make another JPanel and make it a GridLayout JPanel:
JPanel panel = new JPanel(new GridLayout(1,3));
panel.add(num1);
panel.add(num2);
panel.add(num3);
Arguments 1 and 3 mean "use exactly 1 row and 3 columns to place the widgets in this JPanel".
Finally add the last panel at the center of the frame:
add(panel,BorderLayout.CENTER);
This way you won't deal with dimensions or precise spots and still do what you want...
(to test it copy all the code in "Test" constructor)

Categories