Changing layout/frame in response to a button press - java

I'm trying to make a little game on Java using the Swing components (Boggle-type game).
The way I have it set up right now, it basically opens up to the game right away - but I want to have a start up window with two buttons - "Tutorial" and "Play". I already have the functionality (my Tutorial button just opens a new Window with all the things on it) I'm just not sure how to create a second JFrame and then switch to it when I press Play (or rather, create a JFrame, then switch to the one I've already created when the JButton is pressed). I guess I could cause a new JFrame to open on the same location and the old one to become non-visible - but I was hoping for a simpler solution.
I also want to do this on completion of the game, switching again automatically to a little stat page - so any info will be appreciated.
This is what I have so far in case you guys want to see my code (I haven't yet hooked up the Enter key send the userWord to be validated and scored in my other classes, or filled in the tileGrid with Tile Objects, or the timer.... but that will all come later!)
public class Game implements Runnable {
public void run(){
final JFrame frame = new JFrame("Boggle");
frame.setLocation(500,200);
// Input - holds typing box
final JLetterField typingArea = new JLetterField(1);
typingArea.setFocusTraversalKeysEnabled(false);
typingArea.setEditable(true);
typingArea.setFocusable(true);
typingArea.requestFocusInWindow(); //also this request isn't being granted..
//if anyone could explain why i would love you
// I want the focus on the TextField on startup
frame.add(typingArea, BorderLayout.SOUTH);
typingArea.addKeyListener(new KeyAdapter() {
public void keyPressed (KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) { // enter key is pressed
String userWord = typingArea.getText().toLowerCase();
typingArea.setText("");
}
}
});
final JLabel status = new JLabel("Running...");
// Main playing area
GridLayout tileGrid = new GridLayout(4,4);
final JPanel grid = new JPanel(tileGrid);
frame.add(grid, BorderLayout.CENTER);
// Reset button
final JPanel control_panel = new JPanel();
frame.add(control_panel, BorderLayout.NORTH);
final ImageIcon img = new ImageIcon("Instructions.png", "My Instructions...");
final JButton info = new JButton("Help");
info.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final JFrame infoFrame = new JFrame("Tutorial");
infoFrame.setLocation(500,50);
JLabel tutorialImg = new JLabel(img);
int w = img.getIconWidth();
int h = img.getIconHeight();
infoFrame.setSize(w, h);
infoFrame.add(tutorialImg);
infoFrame.setVisible(true);
}
});
control_panel.add(info);
// Put the frame on the screen
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Game());
}
}

use CardLayout instead of second JFrame, your concept is heading to OutOfMemory
use JFrame.pack(after switch betweens Cards in CardLayout) if you want to change JFrames bounds on runtime,

Related

How to refresh / reload / completely close and reopen jframe

I've read the similar questions regarding this problem, tried few methods but none is working.
I have 2 JFrame forms. I want to input information in the first form and submit it to the database. When I click a button, the second form will open and load the information
When I re-input new information in the first form and click the the button again, I want the second form to reload the new information inputted from the database.
This is my code so far.
time t = new time();
private void OrderButtonActionPerformed(java.awt.event.ActionEvent evt) {
if(t.isVisible()){
t.dispose();
t.revalidate();
t.repaint();
t.setVisible(true);
t.setLocationRelativeTo(null);
}
else{
t.setVisible(true);
t.setLocationRelativeTo(null);
}
You don't need to play with JFrames for that. See below example :
JLabel toe = new JLabel("I'm primary text");
JFrame cow = new JFrame("Primary Window");
JPanel cowpanel = new JPanel();
cowpanel.add(toe);
cow.setContentPane(cowpanel);
cow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
cow.pack();
cow.setVisible(true);
JButton tow = new JButton("Change");
tow.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
toe.setText("Hi!, I'm secondary text!");
}
});
JFrame dog = new JFrame("Secondary Window");
JPanel dogPanel = new JPanel();
dog.setContentPane(dogPanel);
dogPanel.add(tow);
dog.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
dog.pack();
dog.setVisible(true);
Clicking the 'Change' button from Frame 2 will change the JLabel's text in Frame 1.

Java: Adding events to dynamically created components

I'm building a UI in Java. I want to create new components, like a JLabel, using a button. So every time I click a button it creates a new JLabel and places them in a specific JPanel.
Then, I want to be able to do some things with the labels based on how the user clicks on them.
With a left mouse press I want them to be able to drag the labels around the screen.
With a right mouse click I want to be open a new window where certain data can be entered, tied to the label (which might involve dynamically creating variables).
I've been toying around with some code I've Googled around for. I can get a button to create new labels in a panel, but when I try to get them to drag, I can only get one label at a time to appear, and after a second button press, moving the label isn't smooth, it jumps around.
I haven't even tried to implement any of the right mouse click things yet. If anyone can point me in the right direction, I'd appreciate it.
public class Testing {
JFrame frame;
//Launch the application.
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
Testing window = new Testing();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
//Create the application.
public Testing() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
JPanel area;
JButton btnCreate;
JLabel dragLabel;
frame = new JFrame();
frame.setBounds(100, 100, 511, 542);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
frame.setVisible(true);
area = new JPanel();
area.setBounds(10, 11, 477, 404);
frame.getContentPane().add(area);
area.setLayout(new BorderLayout());
btnCreate = new JButton("Create Label");
dragLabel = new JLabel("Drag Me");
btnCreate.setBounds(10, 425, 477, 67);
frame.getContentPane().add(btnCreate);
btnCreate.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
area.add(dragLabel);
area.revalidate();
DragListener drag = new DragListener();
dragLabel.addMouseListener(drag);
dragLabel.addMouseMotionListener(drag);
}
});
}
}
class DragListener extends MouseInputAdapter
{
Point location;
MouseEvent pressed;
public void mousePressed(MouseEvent me) {
pressed = me;
}
public void mouseDragged(MouseEvent me)
{
if(SwingUtilities.isLeftMouseButton(me)){
Component component = me.getComponent();
location = component.getLocation(location);
int x = location.x - pressed.getX() + me.getX();
int y = location.y - pressed.getY() + me.getY();
component.setLocation(x, y);
}
}
}
EDIT - I'm fairly certain the primary issue is in how the JLabel itself is being added to the panel. Every time the button is being pushed it's adding the same label over again, and this is gumming up the works.
Unfortunately, I'm not sure how to deal with that. I've done a bit more digging, and since dynamic variables aren't possible, I'm going to have to use an array or a map or some sort. With that, it appears I can declare arrays of components. Would something like that be necessary for my purposes?
Really odd stuff in your code. I don't want to go everything, and I'm not an expert by any stretch of the imagination, but I tried to remove redundant or contradictory stuff. I suspect a part of what you did was just copy pasting bits without really fitting them into the code.
Anyway, you needed to create the label inside the listener, so that it creates a new one everytime you click. Otherwise you only ever create one label and just reuse the same everytime.
I implemented a dialog on right click to enter the label name, don't know what you wanted to do but at least it detects right clicks.
Also in general it's easier to use layout managers instead of hardcoding everything. Here you had a borderlayout but were ignoring it.
class Main {
//Launch the application.
public static void main(String[] args) {
DrageableLabel window = new DrageableLabel();
}
}
public class DrageableLabel {
public DrageableLabel() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
JFrame frame = new JFrame();
Container area = frame.getContentPane();
area.setLayout(new BorderLayout());
JButton btnCreate = new JButton("Create Label");
btnCreate.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
/*
This is where you create your new window
for now I've added a dialog that takes a string parameter and creates a label with that string
I moved the method code to create a new drageable label outside the actionlistener to make it less confusing and reuseable
Either build w-e you want directly in here
or call a method that does it (which I prefer)
*/
String string = JOptionPane.showInputDialog(frame, "Enter your message", "Messages", JOptionPane.CANCEL_OPTION);
addDrageableLabel(string, area);
} else if (SwingUtilities.isLeftMouseButton(e)) {
addDrageableLabel("Drag me", area);
}
}
});
area.add(btnCreate, BorderLayout.SOUTH);
frame.setBounds(100, 100, 511, 542);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
// This is the method that creates and adds a drageable label
public void addDrageableLabel(String labelName, Container container) {
JLabel dragLabel = new JLabel(labelName);
container.add(dragLabel, BorderLayout.CENTER);
container.validate();
DragListener drag = new DragListener();
dragLabel.addMouseListener(drag);
dragLabel.addMouseMotionListener(drag);
}
}
class DragListener extends MouseInputAdapter {
Point location;
MouseEvent pressed;
#Override
public void mousePressed(MouseEvent me) {
pressed = me;
}
#Override
public void mouseDragged(MouseEvent me) {
Component component = me.getComponent();
location = component.getLocation(location);
int x = location.x - pressed.getX() + me.getX();
int y = location.y - pressed.getY() + me.getY();
component.setLocation(x, y);
}
}

Java Swing open form on button click

I am developing a card flip flop game in java Swing(using java swing for 1st time). I am using netbeans, I have a menu like new game.. I want that when the user clicks new game button then the game starts. But i dont know how to do this, like when user clicks button , then in event handling action function,is it like this?
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
JFrame myframe = new JFrame();
//and the game functionality here
}
You are doing the right thing if you want to have a new window open upon click a button. In your sample code, you need to make the new frame visible.
public class NewGame {
public static void main(String[] args) {
JFrame frame = new JFrame("Start up frame");
JButton newGameButton = new JButton("New Game");
frame.setLayout(new FlowLayout());
frame.add(newGameButton);
frame.setVisible(true);
newGameButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JFrame newGameWindow = new JFrame("A new game!");
newGameWindow.setVisible(true);
newGameWindow.add(new JLabel("Customize your game ui in the new window!"));
newGameWindow.pack();
}
});
frame.pack();
}
}

How to display one Jframe at a time? [duplicate]

I'm trying to make a little game that will first show the player a simple login screen where they can enter their name (I will need it later to store their game state info), let them pick a difficulty level etc, and will only show the main game screen once the player has clicked the play button. I'd also like to allow the player to navigate to a (hopefully for them rather large) trophy collection, likewise in what will appear to them to be a new screen.
So far I have a main game window with a grid layout and a game in it that works (Yay for me!). Now I want to add the above functionality.
How do I go about doing this? I don't think I want to go the multiple JFrame route as I only want one icon visible in the taskbar at a time (or would setting their visibility to false effect the icon too?) Do I instead make and destroy layouts or panels or something like that?
What are my options? How can I control what content is being displayed? Especially given my newbie skills?
A simple modal dialog such as a JDialog should work well here. The main GUI which will likely be a JFrame can be invisible when the dialog is called, and then set to visible (assuming that the log-on was successful) once the dialog completes. If the dialog is modal, you'll know exactly when the user has closed the dialog as the code will continue right after the line where you call setVisible(true) on the dialog. Note that the GUI held by a JDialog can be every bit as complex and rich as that held by a JFrame.
Another option is to use one GUI/JFrame but swap views (JPanels) in the main GUI via a CardLayout. This could work quite well and is easy to implement. Check out the CardLayout tutorial for more.
Oh, and welcome to stackoverflow.com!
Here is an example of a Login Dialog as #HovercraftFullOfEels suggested.
Username: stackoverflow Password: stackoverflow
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import javax.swing.*;
public class TestFrame extends JFrame {
private PassWordDialog passDialog;
public TestFrame() {
passDialog = new PassWordDialog(this, true);
passDialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new TestFrame();
frame.getContentPane().setBackground(Color.BLACK);
frame.setTitle("Logged In");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
});
}
}
class PassWordDialog extends JDialog {
private final JLabel jlblUsername = new JLabel("Username");
private final JLabel jlblPassword = new JLabel("Password");
private final JTextField jtfUsername = new JTextField(15);
private final JPasswordField jpfPassword = new JPasswordField();
private final JButton jbtOk = new JButton("Login");
private final JButton jbtCancel = new JButton("Cancel");
private final JLabel jlblStatus = new JLabel(" ");
public PassWordDialog() {
this(null, true);
}
public PassWordDialog(final JFrame parent, boolean modal) {
super(parent, modal);
JPanel p3 = new JPanel(new GridLayout(2, 1));
p3.add(jlblUsername);
p3.add(jlblPassword);
JPanel p4 = new JPanel(new GridLayout(2, 1));
p4.add(jtfUsername);
p4.add(jpfPassword);
JPanel p1 = new JPanel();
p1.add(p3);
p1.add(p4);
JPanel p2 = new JPanel();
p2.add(jbtOk);
p2.add(jbtCancel);
JPanel p5 = new JPanel(new BorderLayout());
p5.add(p2, BorderLayout.CENTER);
p5.add(jlblStatus, BorderLayout.NORTH);
jlblStatus.setForeground(Color.RED);
jlblStatus.setHorizontalAlignment(SwingConstants.CENTER);
setLayout(new BorderLayout());
add(p1, BorderLayout.CENTER);
add(p5, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
jbtOk.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (Arrays.equals("stackoverflow".toCharArray(), jpfPassword.getPassword())
&& "stackoverflow".equals(jtfUsername.getText())) {
parent.setVisible(true);
setVisible(false);
} else {
jlblStatus.setText("Invalid username or password");
}
}
});
jbtCancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
parent.dispose();
System.exit(0);
}
});
}
}
I suggest you insert the following code:
JFrame f = new JFrame();
JTextField text = new JTextField(15); //the 15 sets the size of the text field
JPanel p = new JPanel();
JButton b = new JButton("Login");
f.add(p); //so you can add more stuff to the JFrame
f.setSize(250,150);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Insert that when you want to add the stuff in. Next we will add all the stuff to the JPanel:
p.add(text);
p.add(b);
Now we add the ActionListeners to make the JButtons to work:
b.addActionListener(this);
public void actionPerforemed(ActionEvent e)
{
//Get the text of the JTextField
String TEXT = text.getText();
}
Don't forget to import the following if you haven't already:
import java.awt.event*;
import java.awt.*; //Just in case we need it
import java.x.swing.*;
I hope everything i said makes sense, because sometimes i don't (especially when I'm talking coding/Java) All the importing (if you didn't know) goes at the top of your code.
Instead of adding the game directly to JFrame, you can add your content to JPanel (let's call it GamePanel) and add this panel to the frame. Do the same thing for login screen: add all content to JPanel (LoginPanel) and add it to frame. When your game will start, you should do the following:
Add LoginPanel to frame
Get user input and load it's details
Add GamePanel and destroy LoginPanel (since it will be quite fast to re-create new one, so you don't need to keep it memory).

Thread errors when running Java game

I am getting some strange errors when running my Java game. I've been working on this game for weeks as a project for my computer science class and it is due on 6/4/2015, so I appreciate any help. Initially I wrote the game in a class called Game and ran it from a static method called run. Later, I decided to add a GUI menu in a class called Control. To run the game now, I call the main method in the Control class. This menu has a button with an action listener. When the button is clicked, the run method in the Game class is called. If I click and run the run method directly the game works fine. But if I click the button which calls the run method it draws a frame, but not the actual game.
Here is my code for the GUI:
public class Control extends JFrame implements ActionListener {
// JPanel
public JPanel pnlButton = new JPanel();
// Buttons
public JButton btnAddFlight = new JButton("Multiplayer");
public JButton single = new JButton("Singleplayer");
public Control() throws IOException,InterruptedException {
super("Bouncy Ball");
//Set button size
btnAddFlight.setBounds(150, 400, 220, 30);
single.setBounds(150,350,220,30);
// JPanel bounds
pnlButton.setBounds(0, 0, 500, 500);
pnlButton.setBackground(Color.WHITE);
// Adding the Bouncy Ball logo to JPanel
String path = "gg.jpg";
File file = new File(path);
BufferedImage image = ImageIO.read(file);
JLabel label = new JLabel(new ImageIcon(image));
label.setBounds(179,50,150,150);
//Action Listener setup
single.addActionListener(this);
//add buttons and title logo to JPanel
pnlButton.add(btnAddFlight);
pnlButton.add(label);
pnlButton.add(single);
//Set up and add the instructions to the JPanel
JLabel gg = new JLabel("Welcome to Bouncy Ball, a game where you have to manipulate");
gg.setFont(new Font("Serif", Font.PLAIN, 18));
gg.setBounds(0,10,500,500);
pnlButton.add(gg);
JLabel f = new JLabel("the window size with WASD to win! Click the buttons to start.");
f.setFont(new Font("Serif", Font.PLAIN, 18));
f.setBounds(0,28,500,500);
pnlButton.add(f);
pnlButton.setLayout(null);
//Add JPanel to JFrame
this.add(pnlButton);
// JFrame properties
setSize(500, 500);
setTitle("Bouncy Ball");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);;
}
#Override
public void actionPerformed(ActionEvent submitClicked) {
try{
isClicked = true;
Game.run();
}
catch(InterruptedException a){}
}
public static void main(String[] args) throws IOException,InterruptedException{
new Control();
}
}
and here is the run method in my game class:
public static void run() throws InterruptedException {
//Setting up JFrame
frame = new KeyFrame("Bouncy Ball");
frame.setSize(1000, 1000);
//Setting up Scanner and get user level input
Scanner scan = new Scanner (System.in);
System.out.println("Level one, two, three, or four?(must be an int, four is multiplayer)");
f = scan.nextInt();
//Display JFrame
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.toFront();
//Add Game JPanel
game = new Game();
frame.add(game);
//Setting up game basics
b = new Ball(game,0,0,30,30);
setUpLevel();
objList.add(0,b);
//Main Game Loop
while (true) {
//Request Focus
game.requestFocusInWindow();
//Update current Time
lastStartTime = System.currentTimeMillis();
//Move the ball and the player
p.move();
b.move();
//Refresh JPanel
game.repaint();
Thread.sleep(10);
//Check if the player wins or loses
checkWin();
checkLoss();
}
}
If I call the run method directly it works, but not if I click the button in the GUI. I have a feeling that it is a thread issue, because the main thread ends once run is called. I'm not a 100% percent sure as to the cause though. I'd appreciate any responses, I've been working on this game for weeks as a project for my computer science class and it is due on 6/4/2015.
Swing is single threaded - all painting, events, etc...occur on this thread (named the EDT). The Game.run method is called on the EDT, which in turn executing a long running task (eg while (true), Thread.sleep) - this prevents the EDT from doing anything else. To perform animation, consider using a Thread, or better yet a Swing Timer.

Categories