JFrame crashes when trying to replace a panel with another panel - java

I have a JFrame which is initialized as follows:
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setPreferredSize(PREFERRED_SIZE);
setTitle("Game Set");
setLayout(new BorderLayout());
background = new JLabel(new ImageIcon("images/gameSetBackground.jpg"));
background.setPreferredSize(PREFERRED_SIZE);
add(background);
loginPane = new LoginPane();
background.setLayout(new GridBagLayout());
loginPane.setOpaque(false);
background.add(loginPane, constraints);
pack();
setVisible(true);
I did it this way because it let me set the background to the jpg I specify. Now I have the loginPane() class as follows:
public class LoginPane extends JPanel {
JLabel label = new JLabel("Login");
JLabel secondLabel = new JLabel("If you don't have a profile, click below to create one!");
JTextField userName;
JPasswordField password;
public LoginPane() {
setLayout(new GridBagLayout());
userName = new JTextField(20);
password = new JPasswordField(20);
constraints.insets = new Insets(2, 2, 2, 2);
constraints.gridx = 0;
constraints.gridy = 0;
add(label, constraints);
// etc add all of them the same way
constraints.gridy = 3;
add(secondLabel, constraints);
userName.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
password.requestFocus();
}
});
password.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (userName.getText().equals("Mike")) {
}
}
});
}
}
What I want to happen is that when I hit enter after a username and password has been entered, I will check if that is a valid username/password pair. After that I want to remove everything here and display a different JPanel. Inside the password.ActionListener, I tried the following:
loginPane.removeAll();
background.removeAll();
Those were two separate cases, but both cause the JFrame to crash, the TextFields become unresponsive and I have to exit out. What am I doing wrong?

"JFrame crashes when trying to replace a panel with another panel"
Simple/and correct solution would be to use a CardLayout to switch between panels. See more at How to use CardLayout and see a simple example here.
The CardLayout has methods like show() to to show a certain panel by name, next() to show the next panel, and previous() to show the previous panel. This is preferred way, over removing and adding panels.

Related

Button layout outside of a GridLayout

I'm currently doing a quite simple GUI and was wondering how I could get the button in question out from the GridLayout and put it in its own say BorderLayout, if that's a bit vague I'll attach images to show you what I mean:
With that picture I would like the button to not be with the grid layout and for it to fill all the way across at the bottom of the program as it would in a border layout. My code is as follows:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
/**
* Write a description of class HW4GUI here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class HW4GUI extends JFrame implements ActionListener
{
private JButton jbtAction;
private JTextField jtfFName;
private JTextField jtfLName;
private JTextField jtfLibNo;
private int nextLibNo;
private JPanel textPanel;
/**
* The constructor for the GUI, also initalises nextLibNo number
*/
public HW4GUI()
{
super("Adding a borrower");
makeFrame();
showFrame();
nextLibNo = 1001;
}
/**
*
*/
private void makeFrame()
{
setLayout(new GridLayout(4,0));
setResizable(false);
textPanel = new JPanel();
//textPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
textPanel.setLayout(new BorderLayout());
jtfFName = new JTextField(15);
JLabel fNLbl = new JLabel("First Name: ");
add(fNLbl);
add(jtfFName);
// add(textPanel);
fNLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfFName.setEditable(true);
jtfLName = new JTextField(15);
JLabel lNLbl = new JLabel("Last Name: ");
add(lNLbl);
add(jtfLName);
//add(textPanel);
lNLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfLName.setEditable(true);
jtfLibNo = new JTextField(15);
JLabel lNOLbl = new JLabel("Library Number: ");
add(lNOLbl);
add(jtfLibNo);
// add(textPanel);
lNOLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfLibNo.setEditable(false);
jbtAction = new JButton("Add Borrower");
add(jbtAction, BorderLayout.SOUTH);
jbtAction.addActionListener(this);
}
/**
* displays the frame window where you can set the size of it and also other variables
*/
private void showFrame()
{
setSize(400,200);
setResizable(false);
setLocationRelativeTo( null);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e)
{
String fn = jtfFName.getText();
String ln = jtfLName.getText();
boolean valid = true;
if (e.getActionCommand().equals("Add Borrower"))
{
if (fn.equals("") && (ln.equals("")))
{
jtfLibNo.setText("No Names");
valid = false;
}
else if (fn.equals("") )
{
jtfLibNo.setText("No First Name");
valid = false;
}
else if (ln.equals(""))
{
jtfLibNo.setText("No Last Name");
valid = false;
}
else
if (valid == true)
{
String lib = Integer.toString(nextLibNo++);
jtfLibNo.setText(lib);
jbtAction.setText("Confirm");
}
}
if (e.getActionCommand().equals("Confirm"))
{
jtfLibNo.setText("");
jbtAction.setText("Add Borrower");
}
}
}
As you have said that you want the Button outside your GridLayout, you can do:
Declare a new Panel, like mainPanel or something like that.
JPanel mp = new JPanel();
Set its layout to 3x1 using GridLayout.
mp.setlayout(new GridLayout(3,1));
Add you labels and text-fields to that panel.
mp.add(fNLbl);// and the rest.
Add this panel to your frame.
add(mp, BorderLayout.CENTER);
Then add the Button at the end, using, BorderLayout.SOUTH.
add(jbtAction, BorderLayout.SOUTH);
But as far as my knowledge goes, then your button will occupy the width of the whole frame. So, instead, you can add the button to a panel, and then add that panel to it. Like:
add( new JPanel(){{ add(jbtAction);}}, BorderLayout.SOUTH); // this is double-brace initialization.
The following code works fine:
private void makeFrame()
{
JPanel mp = new JPanel();
mp.setLayout(new GridLayout(3,1));
setResizable(false);
textPanel = new JPanel();
//textPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
textPanel.setLayout(new BorderLayout());
jtfFName = new JTextField(15);
JLabel fNLbl = new JLabel("First Name: ");
mp.add(fNLbl);
mp.add(jtfFName);
// add(textPanel);
fNLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfFName.setEditable(true);
jtfLName = new JTextField(15);
JLabel lNLbl = new JLabel("Last Name: ");
mp.add(lNLbl);
mp.add(jtfLName);
//add(textPanel);
lNLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfLName.setEditable(true);
jtfLibNo = new JTextField(15);
JLabel lNOLbl = new JLabel("Library Number: ");
mp.add(lNOLbl);
mp.add(jtfLibNo);
// add(textPanel);
lNOLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfLibNo.setEditable(false);
jbtAction = new JButton("Add Borrower");
add(mp, BorderLayout.CENTER);
add( new JPanel(){{ add(jbtAction);}}, BorderLayout.SOUTH);
jbtAction.addActionListener(this);
}
With that picture I would like the button to not be with the grid layout and for it to fill all the way across at the bottom of the program as it would in a border layout
Then use a BorderLayout. The default layout manager for a JFrame is a BorderLayout. So you would do somethinglike:
Create a panel using a GridLayout. Add the first 5 components to this panel. Then add the panel to the "CENTER" of the frame.
Create your button. Add the button the the "PAGE_END" of the frame.
The idea of layout managers is that you can nest panels with different layouts to achieve your final layout.
I also agree, the main panel with multiple buttons should probably be a GridBagLayout as it will size each column to the width of the widest component in the column instead of making every column width identical, which will make the panel look better. Read the section from the Swing tutorial on How to Use GridBagLayout for more information and working examples.

Set keyboard focus

I'm currently following a java tutorial on how to create a guessing game GUI App. At one point in the instructions however, it says to Set the keyboard focus to the field; I don't know what this means or how to do it. Any clarification would be greatly appreciated.
here's the exact instruction: Focus the user's attention on thePlayer field:
Set the keyboard focus to the field.
here's my code so far:
public class GOM extends JFrame implements ActionListener, KeyListener
{
Container content = this.getContentPane();
//top
JTextField theGuess = new JTextField(10);
JLabel bankroll = new JLabel("");
//bottom
JButton newplayer = new JButton("New Player");
JButton newnumber = new JButton("New Number");
JTextField thePlayer = new JTextField(20);
//center
JTextArea theoutput = new JTextArea("");
//invisible
String playerName;
int theNumber;
int numTries;
int numGames;
double amtRemaining;
Random randomizer()
{
Random rnd = new Random();
return rnd;
}
JScrollPane scrollArea = new JScrollPane(theoutput);
public GOM()
{
this.setVisible(true);
this.setSize(500,400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Guess O'Matic");
//top panel
JPanel p1 = new JPanel();
p1.add(theGuess);
p1.add(bankroll);
p1.add(new JLabel("Make Your Guess"));
content.add(p1, BorderLayout.NORTH);
//bottom panel
JPanel p2 = new JPanel();
p2.add(newplayer);
p2.add(newnumber);
p2.add(thePlayer);
content.add(p2, BorderLayout.SOUTH);
// finishing touches
content.add(new JLabel(" "), BorderLayout.WEST);
content.add(new JLabel(" "), BorderLayout.EAST);
content.add(scrollArea, BorderLayout.CENTER);
newplayer.addActionListener(this);
newnumber.addActionListener(this);
thePlayer.addKeyListener(this);
theGuess.addKeyListener(this);
newPlayer();
}
public void newPlayer()
{
theoutput.setText(playerName);
theoutput.setEnabled(false);
theGuess.setEnabled(false);
newnumber.setEnabled(false);
newplayer.setEnabled(false);
theGuess.setBackground(Color.WHITE);
thePlayer.setEnabled(true);
thePlayer.setText(playerName);
thePlayer.setBackground(Color.YELLOW);
}
#Override
public void actionPerformed(ActionEvent e)
{
}
#Override
public void keyTyped(KeyEvent e)
{
}
#Override
public void keyPressed(KeyEvent e)
{
}
#Override
public void keyReleased(KeyEvent e)
{
}
}
If you have a GUI with several JTextFields and possibly other text components, the keyboard focus can only be on one of those fields at a time. In other words, if you type, only one of the fields can display the caret and then will usually display the typed in text. When a Swing GUI is displayed then the GUI must decide which text component should have focus, and it uses its focus traversal policy to decide this. The default policy usually will put the focus into the first text field created. You can change this by calling requestFocusInWindow() on the text component that you want to hold the focus.

Text boxes squished in Swing layout

I have a frame that opens when you click file>new user, but the text fields are all squished together.
I'm trying to have them all stacked vertically so I use new GridLayout(3, 2) as my LayoutManager. However, the stuff for the new window is all the way at the bottom.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class App extends JFrame implements ActionListener
{
private final int WIDTH = 300;
private final int HEIGHT = 550;
private int control = 0;
String[] username = new String[10];
String[] pass = new String[10];
private String tempName;
private String tempPass;
Container con = getContentPane();
JPanel panel = new JPanel();
private JTextField name = new JTextField();
private JPasswordField password = new JPasswordField();
JMenuBar mainBar = new JMenuBar();
JMenu menu1 = new JMenu("File");
JMenu menu2 = new JMenu("Edit");
JMenuItem newUser = new JMenuItem("New User");
JButton but1 = new JButton("Log In");
JButton but2 = new JButton("test");
JLabel error = new JLabel("Login info not corret\n Or user not registered.");
JLabel success = new JLabel("Success!");
/////////////stuff for dialog///////////////////
JPanel panel2 = new JPanel();
JTextField newModalUser = new JTextField();
JPasswordField newModalPass = new JPasswordField();
JPasswordField newModalPassCon = new JPasswordField();
JButton register = new JButton("Register");
////////////////////////////////////////////////
public static void main(String[] args)
{
App frame = new App();
}
public App()
{
//just settin some stuff up
super("For The Bold");
setSize(WIDTH, HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
//setResizable(false);
setVisible(true);
//add menubar
setJMenuBar(mainBar);
mainBar.add(menu1);
menu1.add(newUser);
//background of main JFrame
setContentPane(new JLabel(new ImageIcon("//Users//ryanchampin//Desktop//GUI app//image.png")));
//test names in the arrays
username[0] = "ryan";
pass[0] = "test";
//main stuff in the middle
//panel.setBackground(Color.RED);
panel.setSize(300,300);
panel.add(name);
panel.add(password);
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS ));
panel.add(but1);
panel.add(but2);
add(panel,new GridBagConstraints());
setLayout(new GridBagLayout());
//assign action listener
but1.addActionListener(this);
newUser.addActionListener(this);
register.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
Object source = e.getSource();
tempName = name.getText();
tempPass = password.getText();
if(source == but1)
{
for(int x = 0; x < username.length; x++)
{
if(tempName.equalsIgnoreCase(username[x]) && tempPass.equals(pass[x]))
{
//display success JLabel
add(success);
System.out.println("success");
break;
}
else
{
success.setText(null);
add(error);
name.setText(null);
password.setText(null);
}
}
}
else
if(source == newUser)
{
panel.setVisible(false);
setLayout(new GridLayout(3,2));
add(panel2);
panel2.add(newModalUser);
panel2.add(newModalPass);
panel2.add(newModalPassCon);
panel2.add(register);
}
else if(source == register)
System.out.println("yay it worked");
}
}
Avoid using setSize(...) or setPreferredSize(...) if possible.
Instead let the components and their layout managers set their own sizes.
Use a CardLayout to swap views instead of what you're doing. If you do this, the CardLayout will size its container to fit all the "cards" that it has been given.
Don't forget to call pack() on the GUI after adding all components
Don't forget to call setVisible(true) after adding all components and after calling pack.
When creating new JTextFields and JPasswordFields, pass in an int for the number of columns into the constructors.
Edit
You ask:
whats pack() used for?
The pack() method tells the GUI to have all the layout managers of its constituent containers to lay out their components, and then to set the best size of the GUI after every component has been properly placed.
If you want spacing in a GridLayout, you can use the setHgap(int) and setVgap(int) methods to set the number of pixels of space that will appear between each element in the grid.
In your code, there are two ways you could do this: construct a GridLayout and call the two setter methods on it, then pass it into the setLayout(LayoutManager) method:
GridLayout layout = new GridLayout(3, 2);
layout.setHgap(5); // or whatever number of pixels you want
layout.setVgap(5); // same
setLayout(layout);
Alternatively, you could cast the LayoutManager you would get from calling getLayout() and call the two methods on it:
setLayout(new GridLayout(3, 2));
((GridLayout) getLayout()).setHgap(5);
((GridLayout) getLayout()).setVgap(5);
if you want them stacked vertically, wouldn't it be easier to keep using BoxLayout?

Ad selected panel throw JCombobox

I'm having problem with adding another JPanel to my frame when I'm using combobox.
I want to change the center panel according to the selection in combobox.
I made differehnt panel to all selections but it didn't add to my main panel.
I added the code.
thanks :)
import AllClasses.FlightCompany;
{
public class WorkerDialog extends JFrame {
private JPanel Worker;
private String[] LabelNames = { "Worker Type:", " Worker Name:" };
String [] str = { "Office", "Host",
"Pilot" };
JComboBox<String> ChooseBox = new JComboBox<>(str);
public JPanel MainPanel;
private JPanel [] p= new JPanel[3];
public WorkerDialog(FlightCompany f) {
super("Worker Dialog");
p[0] = new Office_Gui();
p[1] = new Host_Gui();
p[2] = new Pilot_Gui();
Worker = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5));
JLabel LabelName = new JLabel(LabelNames[0]);
JLabel LabelName2 = new JLabel(LabelNames[1]);
JTextField fieldBox = new JTextField();
LabelName.setSize(40, 25);
ChooseBox.setPreferredSize(new Dimension(180, 22));
Worker.add(LabelName);
Worker.add(ChooseBox);
Worker.add(LabelName2);
fieldBox.setPreferredSize(new Dimension(180, 22));
Worker.add(fieldBox);
JPanel AddPanel = new JPanel(new GridLayout(2, 1, 1, 1));
AddPanel.add(new JButton("Add"));
AddPanel.add(new JButton("TakeOff"));
MainPanel = new JPanel(new BorderLayout(3, 3));
AddPanel.setPreferredSize(new Dimension(0, 110));
ChooseBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
//String str = e.getActionCommand();
String jb = (String) ChooseBox.getSelectedItem();
if (jb.equals("Office")){
MainPanel.add(p[0],BorderLayout.CENTER);
System.out.println("Office");}
}
});
MainPanel.add(Worker, BorderLayout.NORTH);
MainPanel.add(AddPanel, BorderLayout.SOUTH);
add(MainPanel);
//pack();
setSize(560, 300);
setAlwaysOnTop(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
setVisible(true);
What you want to do is use a CardLayout for your mainPanel, that will allow you to easily switch between panels. Then add all your panels to the mainPanel, specifying a name for the panel. That name will go in the combo box. When you want to show a certain panel, just call cardLayout.show(mainPanel, "nameOfPanel")
To learn more about Cardlayout see How to Use CardLayout. You can also see a simple example here
An aside: Use Java naming convention. Variables begin with lower case letters, using camel casing. ie:
ChooseBox → chooseBox
MainPanel → mainPanel
etc.

Adding ScrollPane to JTextArea

I am working on a project for my college course. I was just wondering if anyone knew how to add a scrollBar to a JTextArea. At present I have the GUI laid out correctly, the only thing missing is the scroll bar.
This is what the GUI looks like. As you can see on the second TextArea I would like to add the Scrollbar.
This is my code where I create the pane. But nothing seems to happen... t2 is the JTextArea I want to add it to.
scroll = new JScrollPane(t2);
scroll.setBounds(10,60,780,500);
scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
Any help would be great, thanks!
The Scroll Bar comes when your text goes beyond the bounds of your view area. Don't use Absolute Positioning, for such a small talk at hand, always prefer Layout Managers, do read the first para of the first link, to know the advantage of using a Layout Manager.
What you simply need to do is use this thingy :
JTextArea msgArea = new JTextArea(10, 10);
msgArea.setWrapStyleWord(true);
msgArea.setLineWrap(true);
JScrollPane msgScroller = new JScrollPane();
msgScroller.setBorder(
BorderFactory.createTitledBorder("Messages"));
msgScroller.setViewportView(msgArea);
panelObject.add(msgScroller);
Here is a small program for your understanding :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JTextAreaScroller
{
private JTextArea msgArea;
private JScrollPane msgScroller;
private JTextArea logArea;
private JScrollPane logScroller;
private JButton sendButton;
private JButton terminateButton;
private Timer timer;
private int counter = 0;
private String[] messages = {
"Hello there\n",
"How you doing ?\n",
"This is a very long text that might won't fit in a single line :-)\n",
"Okay just to occupy more space, it's another line.\n",
"Don't read too much of the messages, instead work on the solution.\n",
"Byee byee :-)\n",
"Cheers\n"
};
private ActionListener timerAction = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
if (counter < messages.length)
msgArea.append(messages[counter++]);
else
counter = 0;
}
};
private void displayGUI()
{
JFrame frame = new JFrame("Chat Messenger Dummy");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout(5, 5));
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new GridLayout(0, 1, 5, 5));
logArea = new JTextArea(10, 10);
logArea.setWrapStyleWord(true);
logArea.setLineWrap(true);
logScroller = new JScrollPane();
logScroller.setBorder(
BorderFactory.createTitledBorder("Chat Log"));
logScroller.setViewportView(logArea);
msgArea = new JTextArea(10, 10);
msgArea.setWrapStyleWord(true);
msgArea.setLineWrap(true);
msgScroller = new JScrollPane();
msgScroller.setBorder(
BorderFactory.createTitledBorder("Messages"));
msgScroller.setViewportView(msgArea);
centerPanel.add(logScroller);
centerPanel.add(msgScroller);
JPanel bottomPanel = new JPanel();
terminateButton = new JButton("Terminate Session");
terminateButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
if (timer.isRunning())
timer.stop();
else
timer.start();
}
});
sendButton = new JButton("Send");
bottomPanel.add(terminateButton);
bottomPanel.add(sendButton);
contentPane.add(centerPanel, BorderLayout.CENTER);
contentPane.add(bottomPanel, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
timer = new Timer(1000, timerAction);
timer.start();
}
public static void main(String... args)
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
new JTextAreaScroller().displayGUI();
}
});
}
}
Here is the outcome of the same :
The scroll bar by default will only be shown when the content overfills the available viewable area
You can change this via the JScrollPane#setVerticalScrollBarPolicy method, passing it ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS

Categories