Pack method called from actionPerformed functions only sometimes - java

Problem
Upon compiling and running my program multiple times, sometimes pack() works and the components of newGamePanel are compressed, and sometimes it doesn't work, and newGamePanel expands to fill the JFrame values set by setSize(). I have been unable to reliably reproduce either result-- it really seems to be random.
Note: As I cut down on the amount of GUI formatting to have a reasonable amount of code to review, the GUI is pretty trash. However, the problem is still easy to identify. When the JPanel that's supposed to be packed is shown by CardLayout, sometimes the JFrame is the "packed" size and sometimes it matches the setSize() values I set in the beginning. Now that I cut the GUI, the newGamePanel components don't move to fill their container, but that's just because I removed all their constraint values.
Suspicions and design
I am calling pack() from class TankEvent, which implements ActionListener. Game is a TankApplication object (TankApplication extends JFrame) passed to TankEvent in the TankEvent constructor, which is called by TankDisplay (TankDisplay extends JPanel).
JFrame instantiates JPanel, passes instance of self.
JPanel instantiates ActionListener, passes instance of self.
ActionListener modifies JFrame using pack().
The following is the code executed when a button is pressed.
CardLayout layOut = (CardLayout)(display.getLayout()); //display is an object of TankDisplay
layOut.show(display, "newGamePanel");
game.pack(); //game is an object of TankApplication
game.setResizable(false);
break;
I wonder if the issue is in my design. I'm making a huge assumption that pack() repaints the JFrame (are JFrames even repainted? Perhaps revalidates/updates?). But as long as I reset the size of JFrame when I'm done, I'm not sure why it would be an issue..
(Side question, I'm not sure why I need to cast display.getLayout() as a CardLayout. This is the suggested implementation from docs.oracle, but why does getLayout() return a LayoutManager and not the actual LayoutManager...?)
Shortened Relevant Code
Tank Display
package Tanks;
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.net.URL;
import javax.imageio.*;
public class TankDisplay extends JPanel{
JCheckBox unlimitedAmmoCB, unlimitedTimeCB;
JTextField playerOneTF, playerTwoTF;
JPanel menuPanel, newGamePanel;
public TankDisplay(TankApplication g){
TankEvent listener = new TankEvent(this, g); //passing an instance of self and previously received instance of TankApplication to TankEvent
setLayout(new CardLayout()); //Hihghest level of GUI after JFrame. CardLayout for overall display JPanel, need for switching functionality in TankEvent
menuPanel = new JPanel(new GridBagLayout()); //Second highest level of GUI. Will eventually display a picture instead of a black JPanel. Has button "New Game" and "Load Game"
JPanel mainMenuImageP = new JPanel();
GridBagConstraints conMainMenuImageP = new GridBagConstraints();
mainMenuImageP.setBackground(Color.BLACK);
conMainMenuImageP.fill = GridBagConstraints.BOTH;
conMainMenuImageP.gridy = 0;
conMainMenuImageP.gridx = 0;
menuPanel.add(mainMenuImageP, conMainMenuImageP); //adding menuPanel components
JButton newGameB = new JButton("New Game");
GridBagConstraints conNewGameB = new GridBagConstraints();
conNewGameB.fill = GridBagConstraints.NONE;
conNewGameB.gridy = 1;
conNewGameB.gridx = 0;
menuPanel.add(newGameB, conNewGameB); //adding menuPanel components
JButton loadGameB = new JButton("Load Game");
GridBagConstraints conLoadGameB = new GridBagConstraints();
conLoadGameB.fill = GridBagConstraints.NONE;
conLoadGameB.gridy = 1;
conLoadGameB.gridx = 1;
menuPanel.add(loadGameB, conLoadGameB); //adding menuPanel components
//action listners for mainPenu panel components
newGameB.addActionListener(listener);
add(menuPanel, "menuPanel"); //menuPanel is added to higher display JPanel
newGamePanel = new JPanel(new GridBagLayout()); //creating second higher level container. To achieve certain functionality,
//this panel contains four other panels, that each contain their own
JPanel playerOneSetUp = new JPanel(new GridBagLayout()); //components. newGamePanel uses GridBagLayout, and so do the panels
GridBagConstraints conPlayerOneSetUp = new GridBagConstraints();//that it's managing. GridBayLayout managaing GridBagLayout
conPlayerOneSetUp.fill = GridBagConstraints.BOTH;
conPlayerOneSetUp.gridy = 0;
conPlayerOneSetUp.gridx = 0;
JLabel playerOneL = new JLabel("Player One Name");
GridBagConstraints conPlayerOneL = new GridBagConstraints();
conPlayerOneL.fill = GridBagConstraints.HORIZONTAL;
conPlayerOneL.gridy = 0;
conPlayerOneL.gridx = 0;
playerOneSetUp.add(playerOneL, conPlayerOneL);
playerOneTF = new JTextField();
GridBagConstraints conPlayerOneTF = new GridBagConstraints();
conPlayerOneTF.fill = GridBagConstraints.HORIZONTAL;
conPlayerOneTF.gridy = 1;
conPlayerOneTF.gridx = 0;
playerOneSetUp.add(playerOneTF, conPlayerOneTF);
JButton playerOneJColorChooser = new JButton("Player One Color");
GridBagConstraints conPlayerOneJColorChooser = new GridBagConstraints();
conPlayerOneJColorChooser.fill = GridBagConstraints.HORIZONTAL;
conPlayerOneJColorChooser.gridy = 2;
conPlayerOneJColorChooser.gridx = 0;
playerOneSetUp.add(playerOneJColorChooser, conPlayerOneJColorChooser);
newGamePanel.add(playerOneSetUp, conPlayerOneSetUp); //adding newGamePanel components
JPanel playerTwoSetUp = new JPanel(new GridBagLayout());
GridBagConstraints conPlayerTwoSetUp = new GridBagConstraints();
conPlayerTwoSetUp.fill = GridBagConstraints.BOTH;
conPlayerTwoSetUp.gridy = 1;
conPlayerTwoSetUp.gridx = 0;
JLabel playerTwoL = new JLabel("Player Two Name");
GridBagConstraints conPlayerTwoL = new GridBagConstraints();
conPlayerTwoL.fill = GridBagConstraints.HORIZONTAL;
conPlayerTwoL.gridy = 0;
conPlayerTwoL.gridx = 0;
playerTwoSetUp.add(playerTwoL, conPlayerTwoL);
playerTwoTF = new JTextField();
GridBagConstraints conPlayerTwoTF = new GridBagConstraints();
conPlayerTwoTF.fill = GridBagConstraints.HORIZONTAL;
conPlayerTwoTF.gridy = 1;
conPlayerTwoTF.gridx = 0;
playerTwoSetUp.add(playerTwoTF, conPlayerTwoTF);
JButton playerTwoJColorChooser = new JButton("Player Two Color");
GridBagConstraints conPlayerTwoJColorChooser = new GridBagConstraints();
conPlayerTwoJColorChooser.fill = GridBagConstraints.HORIZONTAL;
conPlayerTwoJColorChooser.gridy = 2;
conPlayerTwoJColorChooser.gridx = 0;
playerTwoSetUp.add(playerTwoJColorChooser, conPlayerTwoJColorChooser);
newGamePanel.add(playerTwoSetUp, conPlayerTwoSetUp); //adding newGamePanel components
JPanel options = new JPanel(new GridBagLayout());
GridBagConstraints conOptions = new GridBagConstraints();
conOptions.fill = GridBagConstraints.BOTH;
conOptions.gridy = 0;
conOptions.gridx = 1;
JLabel optionsL = new JLabel("Game Options");
GridBagConstraints conOptionsL = new GridBagConstraints();
conOptionsL.fill = GridBagConstraints.HORIZONTAL;
conOptionsL.gridy = 0;
conOptionsL.gridx = 0;
options.add(optionsL, conOptionsL);
unlimitedAmmoCB = new JCheckBox("Unlimited Ammunition");
GridBagConstraints conUnlimitedAmmoCB = new GridBagConstraints();
conUnlimitedAmmoCB.fill = GridBagConstraints.HORIZONTAL;
conUnlimitedAmmoCB.gridy = 1;
conUnlimitedAmmoCB.gridx = 0;
options.add(unlimitedAmmoCB, conUnlimitedAmmoCB);
unlimitedTimeCB = new JCheckBox("Unlimited Time");
GridBagConstraints conUnlimitedTimeCB = new GridBagConstraints();
conUnlimitedTimeCB.fill = GridBagConstraints.HORIZONTAL;
conUnlimitedTimeCB.gridy = 2;
conUnlimitedTimeCB.gridx = 0;
options.add(unlimitedTimeCB, conUnlimitedTimeCB);
newGamePanel.add(options, conOptions); //adding newGamePanel components
JButton startGameB = new JButton("START");
GridBagConstraints conStartGameB = new GridBagConstraints();
conStartGameB.fill = GridBagConstraints.BOTH;
conStartGameB.gridy = 1;
conStartGameB.gridx = 1;
newGamePanel.add(startGameB, conStartGameB); //adding newGamePanel components
add(newGamePanel, "newGamePanel"); //newGamePanel is added to higher level display JPanel
}
}
Tank Application
package Tanks;
import javax.swing.*;
import java.awt.*;
public class TankApplication extends JFrame{
public static void main (String args[]){
TankApplication GUI = new TankApplication();
}
public TankApplication(){
super("Tanks");
add(new TankDisplay(this));
setSize(800, 600);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
}
Tank Event
package Tanks;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JColorChooser;
public class TankEvent implements ActionListener{
TankApplication game;
TankDisplay display;
public TankEvent(TankDisplay d, TankApplication g){ //I found this was necesarry because I didn't want to call the constructors of panels
display = d; //and frames. I'm not sure why that caused errors, but it does. And when I tried to
game = g; //create overloaded constructors for TankApplication and TankDisplay, their references
} //didn't have the information I needed. This is likely because I kept most of the components
//as local variables in the constructors, instead of creating variables in their respective classes, and using
public void actionPerformed(ActionEvent e){ //the constructors to modify them
CardLayout layOut = (CardLayout)(display.getLayout()); //<---Why do I need to do this?
switch(e.getActionCommand()){
case "New Game":
layOut.show(display, "newGamePanel");
game.pack(); //<<<---Root problem. Sometimes newGamePanel is packed, the JFrame is smaller, sometimes newGameaPanel is not packed. Seems random
game.setResizable(false); //for this JPanel only, I don't want to be able to resize the window. I will change this when the user flips
break; //to another JPanel
}
}
}
Robert seems to have asked a similar question, but didn't seem to get a satisfactory answer. Why do threads have anything to do with this?

You are not using CardLayout correctly.
When you use a CardLayout on a panel the preferred size of the panel is the size of the largest child panel added to the CardLayout.
Swapping from one panel to another will not alter the preferred size of panel and therefore the frame. So the pack() method will have no effect.
I suggest you don't worry about packing the frame. Just create the "menu panel" so that its components are centered. Then when you start the game all that changes is that you display the "game panel".

Related

java GUI layout suggestion

public class AFS {
public JPanel afs(final Fields input){
JPanel titlePanel = new JPanel();
//Title fields
JLabel afs = new JLabel("Statement", Label.LEFT);
Label mm = new Label("month ", Label.LEFT);
Label my = new Label("Year ", Label.LEFT);
//first line
titlePanel.add(afs);
titlePanel.add(mm);
titlePanel.add(input.MENTRY);
titlePanel.add(my);
titlePanel.add(input.YENTRY);
titlePanel.setPreferredSize(null);
//Left Panels
JPanel sb = new JPanel();
JPanel entry = new JPanel();
entry.setLayout(new BoxLayout(entry, BoxLayout.Y_AXIS));
entry.setAlignmentX(Component.LEFT_ALIGNMENT);
entry.add(new Label("Service "));
entry.add(input.s);
entry.add(new Label("Amount "));
entry.add(input.a);
entry.add(new Label("Counter "));
entry.add(input.o);
entry.add(new Label("Division "));
entry.add(input.d);
sb.add(entry);
JPanel holderPanel = new JPanel();
holderPanel.setLayout(new BoxLayout(holderPanel, BoxLayout.Y_AXIS));
holderPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
holderPanel.add(titlePanel);
holderPanel.add(sb);
JButton start = new JButton("Save Current");
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ScriptAction action = new ScriptAction();
action.saveAll(input,1);
}
});
holderPanel.add(start);
return holderPanel;
}
I have a short version of what looks like above code.
The current layout looks like this:
But I want the layout look like (paint edited).
I have tried swap using gridLayout for the entry and it will display 2 rows but gridlayout will still align everything in the center (include the title and the header). Furthermore the button span would be across the entire bottom section. I was wondering if there are any suggested way to do this?
You would need to use a combination of layout managers to achieve the desired output:
Before resize / After resize
In this case there are 3 main parts:
Top pane (Uses Box to align some text on the left and some on the right)
Middle pane (Uses GridBagLayout to position the components as in the image, maybe GridLayout with proper insets might work as well)
Bottom pane (Uses default JPanel's layout: FlowLayout)
The top pane uses 2 JPanels as well, the first one for the label Statement alone and other with FlowLayout aligned to the right for the other 4 components, as per this answer BoxLayout does not respect the preferred size of our JTextFields. So a workaround is to wrap them inside another JPanel and then wrap that JPanel along with the Statement label.
A similar problem arises with the middle pane, which needs to use 2 JPanels: One for the fields wrapped inside another bigger one which holds it and the JButton at the bottom (Save Current). We could achieve a similar output by adding the JButton with a gridx = 2 and gridy = 2 with the counter and division label and fields on gridx = 3 and gridx = 4 respectively (instead of 2 & 3) but we would then need to add gbc.insets to add insets to the top and bottom with high values as well... It's up to you which one to use :)
The code that produces the above outputs is the following:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class FormSample {
private JFrame frame;
private JPanel topRightPane;
private JPanel centerPane;
private JPanel centerWithButtonPane;
private JPanel buttonsPane;
private JTextField monthField;
private JTextField yearField;
private JTextField serviceField;
private JTextField amountField;
private JTextField counterField;
private JTextField divisionField;
private static final int LEFT_MARGIN = 50; //Increase / Decrease to add extra space between components
private static final int RIGHT_MARGIN = LEFT_MARGIN;
//Change insets accordingly to add extra space between components (top, left, bottom, right)
private static final Insets leftInsets = new Insets(0, LEFT_MARGIN, 0, 0);
private static final Insets rightInsets = new Insets(0, 0, 0, RIGHT_MARGIN);
private static final Insets defaultInsets = new Insets(0, 0, 0, 0);
private JButton saveCurrentButton;
private JButton saveAllButton;
private JButton resetButton;
public static void main(String[] args) {
SwingUtilities.invokeLater(new FormSample()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
monthField = new JTextField(10);
yearField = new JTextField(10);
serviceField = new JTextField(10);
amountField = new JTextField(10);
counterField = new JTextField(10);
divisionField = new JTextField(10);
saveCurrentButton = new JButton("Save Current");
saveAllButton = new JButton("Save all");
resetButton = new JButton("Reset");
buttonsPane = new JPanel();
topRightPane = new JPanel();
topRightPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
topRightPane.add(new JLabel("Month"));
topRightPane.add(monthField);
topRightPane.add(new JLabel("Year"));
topRightPane.add(yearField);
centerWithButtonPane = new JPanel();
centerWithButtonPane.setLayout(new BoxLayout(centerWithButtonPane, BoxLayout.PAGE_AXIS));
Box box = Box.createHorizontalBox();
box.add(new JLabel("Statement"));
box.add(Box.createHorizontalGlue());
box.add(topRightPane);
centerPane = new JPanel();
centerPane.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = defaultInsets;
centerPane.add(new JLabel("Service"), gbc);
gbc.gridx = 1;
gbc.insets = rightInsets;
centerPane.add(serviceField, gbc);
gbc.gridx = 2;
gbc.insets = leftInsets;
centerPane.add(new JLabel("Counter"), gbc);
gbc.gridx = 3;
gbc.insets = defaultInsets;
centerPane.add(counterField, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.insets = defaultInsets;
centerPane.add(new JLabel("Amount"), gbc);
gbc.gridx = 1;
gbc.insets = rightInsets;
centerPane.add(amountField, gbc);
gbc.gridx = 2;
gbc.insets = leftInsets;
centerPane.add(new JLabel("Division"), gbc);
gbc.gridx = 3;
gbc.insets = defaultInsets;
centerPane.add(divisionField, gbc);
saveCurrentButton.setAlignmentX(Component.CENTER_ALIGNMENT); //Force centered alignment for our JButton
centerWithButtonPane.add(centerPane);
centerWithButtonPane.add(saveCurrentButton);
buttonsPane.add(saveAllButton);
buttonsPane.add(resetButton);
frame.add(box, BorderLayout.NORTH);
frame.add(centerWithButtonPane, BorderLayout.CENTER);
frame.add(buttonsPane, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Also please follow the advices given by #SergiyMedvynskyy about not mixing AWT and Swing components (i.e. JTextField with TextField) and only use Swing components as AWT ones are buggy.

Setting Size is not overriding on Java

I am having issue where my JPanel is not setting up the size. I am not sure if is something to do with my JTab or JFrame. I am using GridBagLayout layout management. And for some reason are not able to set the size.
Here is a dummy code, following the same logic to my original source code:
FirstPanel.java
import javax.swing.*;
import java.awt.*;
public class FirstPanel extends JPanel {
private JLabel label1 = new JLabel("Label 1");
private JTextField textField1 = new JTextField();
private GridBagConstraints c = new GridBagConstraints();
public FirstPanel() {
//Size is not overriding
Dimension size = getPreferredSize();
size.width = 100;
setPreferredSize(size);
setBorder(BorderFactory.createTitleBorder("Border Title");
setLayout(new GridBagLayout());
addComponents();
}
private void addComponents() {
c.gridx = 0;
c.gridy = 0;
c.anchor = GridBagConstraints.NORTHWEST;
c.insets = new Insets(5, 0, 0, 0);
add(label1, c);
c.gridx = 1;
add(textField1, c);
c.weightx = 1;
c.weighty = 1;
add(new JLabel(""), c);
}
}
MainPanel.java
import javax.swing.*;
import java.awt.*;
public class MainPanel {
private JFrame frame = new JFrame("App");
private JPanel panel1 = new JPanel(new GridBagLayout());
private GridBagConstraints c = new GridBagConstraints();
private JTabbedPane tabPane = new JTabbedPane();
public MainPanel() {
addComponents();
frame.add(tabPane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 350);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
}
private void addComponents() {
tabPane.addTab("Tab 1", new FirstPanel());
}
}
Main.java
public class Main {
public static void main(String[] args) {
new MainPanel();
}
}
Or at least have two JPanels,
Exactly.
Frist you create a main panel using a BorderLayout that you add to the tabbed pane.
Then you have a second panel for your labels and text fields (using whatever layout manager you want). Then you add this panel to the BorderLayout.LINE_START.
Then you add your scrollpane containing the JTable to the BorderLayout.CENTER of the main panel.
Read the tutorial on Layout Manager. Nest panels with different layout managers as required.
want to have JTable taking 50% of the other side.
Picking a random number like 50% is not the way to design a GUI. What happens if the frame is made smaller/larger. What happens to the space? Design the layout with flexibility in mind, just like your browser window is designed. There are always fixed areas where the size is determined by the components added and there is a flexible area that grows/shrinks as desired.

Can I increase panel length every time a container is added?

I'm currently designing a GUI assignment planner. I have run across a few issues along the way. For one part of my program I have a panel to hold assignments that still need to be completed. What I would like to create is a panel that will add containers (holding the components to display an assignment) to a panel. However, the only way I can conceive of doing this is by lengthening the panel each time a container is added. Unfortunately, to the best of knowledge, this isn't possible since a panel is given a defined width and depth when it is created. Ideally, if possible, I'd like to increase the panel length every time a container is added. A scrollbar would scroll down the panel.
So is this possible? Am I approaching this the right way? I am very new to GUI so I am open to improvements and suggestions. If anyone would like me to post my code so far, I will. (Beware, it is in very rough shape at the moment)
Attached below is a rough draft of what I am trying to make:
TIA
This is the majority of my code so far. The problem is that once i add a certain amount of containers it starts to make them smaller. I just want to extend it every time a container is added. Most of the comments are for documentation or to remind to do something.
import javax.swing.*;
import java.awt.*;
//import java.util.ArrayList;
public class MyWindow
{
private final JFrame frame = new JFrame();
private final int WINDOW_WIDTH = 500, WINDOW_DEPTH = 500;
private JPanel panel;
private JPanel toDoList, completed;
//ArrayList<JFrame> frame = new ArrayList<>();
public MyWindow()
{
frame.setTitle("Assignment Planner");
this.contents();
}
private void contents()
{//use an arraylist to create containers ArrayList<JPanel> container = new ArrayList<>();
frame.setSize(WINDOW_WIDTH, WINDOW_DEPTH);
panel = new JPanel(new GridLayout(2, 1));
toDoList = new JPanel();
toDoList.setLayout(new /*GridLayout(0,1,5,5)*/BoxLayout(toDoList, BoxLayout.PAGE_AXIS));
toDoList.setPreferredSize(new Dimension(250, 250));
panel.add(toDoList);
completed = new JPanel();
//panelCompleted.setLayout(new GridLayout(0, 1)); //fix like one above
panel.add(completed);
JScrollPane scroll = new JScrollPane(toDoList);
panel.add(scroll); //scroll panes for both panels
JScrollPane scroll2 = new JScrollPane(completed);
panel.add(scroll2);
toDoList.add(assignment());
toDoList.add(Box.createRigidArea(new Dimension(0,1)));
toDoList.add(assignment());
toDoList.add(Box.createRigidArea(new Dimension(0,1)));
toDoList.add(assignment());
toDoList.add(Box.createRigidArea(new Dimension(0,1)));
beginningScrollPaneValue += 110;
toDoList.setPreferredSize(new Dimension(250, beginningScrollPaneValue));
toDoList.revalidate(); //scroll.revalidate();
toDoList.repaint(); //scroll.repaint();
frame.getContentPane().add(panel, BorderLayout.CENTER);//add the panel in the JFrame's content pane in the center
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
JPanel assignment()
{
JPanel container = new JPanel(new GridBagLayout());
container.setMaximumSize(new Dimension(500,100));
GridBagConstraints c = new GridBagConstraints();
c.weightx = 0.5;
JCheckBox cb = new JCheckBox();
c.fill = GridBagConstraints.NONE;
c.gridx = 1;
c.gridy = 0;
container.add(cb, c);
container.setBackground(Color.red);//does no fill area behind checkbox
return container;
}
}

Putting button on top of image in JPanel?

I have been working on a main menu screen. I use a card layout because I have a splash screen that shows up before the main menu screen. Once the user clicks the "Continue" button on the splash screen, they are brought to the main menu screen.
I can't add a screenshot because I don't have a high enough reputation but as of now the buttons are pushed off to the side, I assume because of the card layout.
Is there any way that I can place the button on top of the main menu screen image?
Here is my code for the window:
package edu.ycp.cs.Main;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class Window {
JPanel cards; // a panel that uses CardLayout
final static String SPLASHSCREEN = "SplashScreen";
final static String MAINMENU = "MainMenu";
public void addComponentToWindow(Container pane) {
// Put the JComboBox in a JPanel to get a nicer look.
JPanel gameWindow = new JPanel(); // use FlowLayout
// Create the "cards".
JPanel card1 = new JPanel();
JButton continueButton = new JButton("Continue");
continueButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
CardLayout cl = (CardLayout) (cards.getLayout());
cl.show(cards, MAINMENU);
}
});
card1.add(new SplashScreen());
card1.add(continueButton);
JPanel card2 = new JPanel();
JButton menuButton1 = new JButton("PLAY!");
JButton menuButton2 = new JButton("HIGH SCORES");
card2.add(new MainMenuScreen());
card2.add(menuButton1);
card2.add(menuButton2);
cards = new JPanel(new CardLayout());
cards.add(card1, SPLASHSCREEN);
cards.add(card2, MAINMENU);
pane.add(gameWindow, BorderLayout.PAGE_START);
pane.add(cards, BorderLayout.CENTER);
}
}
Any suggestions on how to get the button on top of the image?
JPanel card1 = new JPanel();
card1.add(new SplashScreen());
card1.add(continueButton);
A JPanel use a FlowLayout. So when you add two components to it they are just painted beside each other.
You want the component to be painted on top of each other so you need to do something like:
JPanel card1 = new JPanel();
SplashScreen splash = new SplashScreen();
splash.setLayout( new FlowLayout() );
card1. add(splash);
splash.add( continueButton );
Your JPanel that contains your 2 menuButton and MenuScreen doesn't have a layout. Use one like GridBagLayout and set the buttons on top. You could use another layout, that's up to you.
I used buttons only to show you a simple example for GridBagLayout and suggest you check Oracle's page on that layout if you wish to use it.
JPanel card2 = new JPanel();
card2.setLayout(new GridBagLayout());
JButton menuButton1 = new JButton("PLAY!");
JButton menuButton2 = new JButton("HIGH SCORES");
JButton menuButton3 = new JButton("UNDER THE 2 OTHERS");
GridBagConstraints gbc2 = new GridBagConstraints();
gbc2.gridx = 0;
gbc2.gridy = 1;
gbc2.weightx = 1;
gbc2.weighty = 1;
gbc2.gridwidth = 2;
gbc2.fill = GridBagConstraints.HORIZONTAL;
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
GridBagConstraints gbc3 = new GridBagConstraints();
gbc3.gridx = 1;
gbc3.gridy = 0;
gbc3.weightx = 1;
gbc3.weighty = 1;
gbc3.fill = GridBagConstraints.HORIZONTAL;
card2.add(menuButton1, gbc);
card2.add(menuButton2, gbc3);
card2.add(menuButton3, gbc2);
If your splash screen only has that one button, you could try making your entire splash image a button, as in this example: Java: using an image as a button
You could edit your existing splash screen image to add a Continue Button inside the image itself. Of course the user would be able to click anywhere (as it would be one huge image button).
Sounds cheesy, I know. But it might be a quick-and-dirty way to get close enough to what you want.

GridBagLayout within JScrollPane not resizing properly

I have a JPanel with a GridBagLayout inside of a JScrollPane. I also have an 'add' button within the JPanel which, when clicked, will be removed from the JPanel, adds a new instance of a separate component to the JPanel, then adds itself back to the JPanel. This sort of makes a growing list of components, followed by the 'add' button.
Adding new components works fine, the JPanel stretches to accommodate the new components, and the JScrollPane behaves as expected, allowing you to scroll through the entire length of the JPanel.
This is how the add works:
jPanel.remove(addButton);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = GridBagConstraints.RELATIVE;
jPanel.add(new MyComponent(), c);
jPanel.add(addButton, c);
jPanel.validate();
jPanel.repaint();`
Removal works by clicking a button inside the added components themselves. They remove themselves from the JPanel just fine. However, the JPanel keeps it's stretched-out size, re-centering the list of components.
This is how removal works:
Container parent = myComponent.getParent();
parent.remove(myComponent);
parent.validate();
parent.repaint();`
The question is, why does my GridBagLayout JPanel resize when adding components, but not when removing components?
You have to revalidate and repaint the JScrollPane, here is an example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SwingTest {
public static void main(String[] args) {
final JPanel panel = new JPanel(new GridBagLayout());
for (int i = 0; i < 25; i++) {
JTextField field = new JTextField("Field " + i, 20);
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridy = i;
panel.add(field, constraints);
}
final JScrollPane scrollPane = new JScrollPane(panel);
JButton removeButton = new JButton("Remove Field");
removeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (panel.getComponentCount() >= 1) {
panel.remove(panel.getComponentCount() - 1);
scrollPane.revalidate();
scrollPane.repaint();
}
}
});
JFrame frame = new JFrame("Swing Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(640, 480);
frame.setLocation(200, 200);
frame.getContentPane().add(scrollPane);
frame.getContentPane().add(removeButton, BorderLayout.SOUTH);
frame.setVisible(true);
}
}

Categories

Resources