My Menu in Java can't be Called Twice? [closed] - java

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I'm new to java and programming in general, and I am writing a program that has a menu in it. (It is a JFrame in java) What it does is when you hit a JButton, it shows an applet on the screen. When the applet is done, it goes to a screen where you can choose to run the applet again or go back to the main menu when you hit a button. The problem is that when you hit the button to go back to the menu, it doesn't. All it does is make neither button clickable.
This is the method I use to draw the menu:
public static void drawMenu()
{
f.add(BOption1);
f.add(BOption2);
}
The two jbuttons are already declared and such in the constructor, and they work fine the first time I run the menu. Then, when you hit one of the buttons, it removes both buttons from the screen with f.remove(...). Does anyone know why it won't work when I call this method a second time?
Edit:
Sorry, I meant to say canvas, not applet.
Edit Edit:
I found the solution to my problem, but thanks anyway.

Here is the code for your main class, Frame:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Frame extends JFrame {
static OnePlayer onePlayer;
static TwoPlayer twoPlayer;
static Frame f;
static JButton BOnePlayer = new JButton("Single Player");
static JButton BTwoPlayer = new JButton("Multiplayer");
static JButton BInstructions = new JButton("Instructions");
static JButton toMenu;
static JButton replay;
public Frame(String name) {
super(name);
this.setTitle(name);
this.setVisible(true);
this.setSize(640, 673);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setLocationRelativeTo(null);
this.setLayout(null);
this.setBackground(Color.GRAY);
BOnePlayer.setBounds(120, 150, 400, 100);
BTwoPlayer.setBounds(120, 250, 400, 100);
BInstructions.setBounds(120, 350, 400, 100);
BOnePlayer.setFont(new Font("Comic Sans MS", Font.ITALIC, 20));
BTwoPlayer.setFont(new Font("Comic Sans MS", Font.ITALIC, 20));
BInstructions.setFont(new Font("Comic Sans MS", Font.ITALIC, 20));
BOnePlayer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Container onePane = f.getContentPane();
onePane.setLayout(new GridLayout(1, 1));
onePlayer = new OnePlayer();
onePane.add(onePlayer);
onePlayer.init();
f.remove(BOnePlayer);
f.remove(BTwoPlayer);
f.remove(BInstructions);
}
});
BTwoPlayer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Container twoPane = f.getContentPane();
twoPane.setLayout(new GridLayout(1, 1));
twoPlayer = new TwoPlayer();
twoPane.add(twoPlayer);
twoPlayer.init();
f.remove(BOnePlayer);
f.remove(BTwoPlayer);
f.remove(BInstructions);
}
});
BInstructions.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
}
public static void main(String[] args) {
f = new Frame("Snake");
drawMenu();
}
public static void OnePlayerDone(int score) {
}
public static void TwoPlayerDone(int winner, int p1score, int p2score) {
f.remove(twoPlayer);
replay = new JButton("Play Again");
toMenu = new JButton("Return to Menu");
replay.setBounds(120, 100, 400, 100);
toMenu.setBounds(120, 500, 400, 100);
replay.setFont(new Font("Comic Sans MS", Font.ITALIC, 20));
toMenu.setFont(new Font("Comic Snas MS", Font.ITALIC, 20));
f.add(replay);
f.add(toMenu);
replay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Container twoPane = f.getContentPane();
twoPane.setLayout(new GridLayout(1, 1));
twoPlayer = new TwoPlayer();
twoPane.add(twoPlayer);
twoPlayer.init();
}
});
toMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
drawMenu();
}
});
}
public static void drawMenu() {
f.add(BOnePlayer);
f.add(BTwoPlayer);
f.add(BInstructions);
}
}
Suggestions:
First off, rename your class to something other than Frame. This is the name of a closely related core Java class, the AWT equivalent of JFrame, and your giving it the same name can confuse many. Perhaps call it SnakeFrame.
All of your static variables should instead be instance variables.
You shouldn't even have a SnakeFrame variable (your variable f). Instead you should use the current SnakeFrame instance, the this if you will.
Don't mix AWT with Swing components unnecessarily and without need. For instance you should use no Canvas-derived objects but rather JPanel-derived objects.
Your code should follow Java naming conventions so that others (us for instance) can understand it. Variable and method names should all begin with a lower case.
You will want to read up on and use the layout managers to help you place your GUI components on your GUI rather than use null layout and setBounds(...).
Most important, to swap views as you're trying to do, read up on and use a CardLayout as this was built for just this purpose.

This is not an answer and will be deleted, but I needed to post a more complex comment:
I am writing a program that has a menu in it. (It is a JFrame in java) What it does is when you hit a JButton, it shows an applet on the screen.
Can you explain why you're doing this? It is most unusual and difficult for a JFrame to display an applet as an applet. Are you doing this by launching the applet using some stand-alone applet viewer? Perhaps you're doing something else, such as displaying a dialog or another JFrame, but using the wrong terms to describe it?
When the applet is done, it goes to a screen where you can choose to run the applet again or go back to the main menu when you hit a button.
How do you achieve this? What code do you use?
The problem is that when you hit the button to go back to the menu, it doesn't. All it does is make neither button clickable. This is the method I use to draw the menu:
public static void drawMenu()
{
f.add(BOption1);
f.add(BOption2);
}
Does anyone know why it won't work when I call this method a second time?
Somehow your code is changing the state of your program and thereby makes your JButtons unresponsive. How it's doing this -- you haven't told us enough for us to say.
I'm not sure that we have enough information to answer your question yet. Please show more code and give us more detailed and precise description of what is going on. Best would be if you could post an sscce.

Related

JLabel text not appearing

I am new to Java. I am trying to make text appear on a JLabel after a virtual button is clicked. However, I can't seem to find a solution to this. When I use the if statement it won't work. How can I make the text appear after the button was pressed?
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JPanel;
import java.awt.Graphics;
public class autos extends JLabel implements ActionListener
{
private static final long serialVersionUID = 1L;
int now=0;
public autos(){
JLabel l=new JLabel("");
JFrame f=new JFrame("the title");
JPanel p=new JPanel();
JButton b=new JButton("click");
f.setBounds(400,500,400,500);
f.setVisible(true);
p.add(b);
f.add(p);
b.addActionListener(this);
p.setVisible(true);
p.add(l);
f.add(l);
if(now==1)
{
l.setText("hello");
l.setOpaque(true);
}
p.setBounds(200,200,200,200);
l.setBounds(100,100,100,100);
l.setOpaque(true);
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawRect(200,300,89,90);
g.drawString("buv",80,80);
repaint();
}
public static void main(String[] args)
{
new autos();
}
#Override
public void actionPerformed(ActionEvent e) {
now=1;
System.out.println("worked");
System.out.println(now);
}
}
You are setting up your label in your constructor code, which executes before the event handler which sets the now variable to 1.
What you can do is to move this code:
l.setText("hello");
l.setOpaque(true);
To here:
#Override
public void actionPerformed(ActionEvent e) {
now=1;
System.out.println("worked");
System.out.println(now);
l.setText("hello");
l.setOpaque(true);
}
This is a minimally working example of updating the text on button click. See the comments in code for the variety of changes.
import java.awt.event.*;
import javax.swing.*;
/* There is no need to extend label here. */
// public class autos extends JLabel implements ActionListener
public class autos implements ActionListener {
private static final long serialVersionUID = 1L;
int now = 0;
// this is now a class attribute, accessible to any method of this class.
JLabel l;
public autos() {
// this no longer declares a local variable, but instead
// creates an instance of the class attribute.
l = new JLabel("");
JFrame f = new JFrame("the title");
JPanel p = new JPanel();
JButton b = new JButton("click");
f.setBounds(400, 500, 400, 500); // this needs fixing!
f.setVisible(true);
p.add(b);
f.add(p);
b.addActionListener(this);
p.setVisible(true);
p.add(l);
f.add(l);
p.setBounds(200, 200, 200, 200); // this needs fixing!
l.setBounds(100, 100, 100, 100); // this needs fixing!
l.setOpaque(true);
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
}
/* I cannot tell what this was trying to achieve, but whatever it was,
this was the wrong way to go about it. Never call repaint() from within
the paintComponent method as this creates an infinite loop! */
/*
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(200, 300, 89, 90);
g.drawString("buv", 80, 80);
repaint();
}
*/
public static void main(String[] args) {
// Swing GUIs should be created and updated on the EDT
new autos();
}
#Override
public void actionPerformed(ActionEvent e) {
/* This logic is questionable, but it denpends on what you are trying
to achieve here, something I'm not clear on. */
now = 1;
if (now == 1) {
l.setText("hello");
l.setOpaque(true);
}
System.out.println("worked");
System.out.println(now);
}
}
Edit
You added two comments at the setBounds part saying this needs fixing!. There I tried to resize the JPanel and JLabel but it's obvious it doesn't work.
How should I proceed here?
Here are some 'copy/paste comments' I regularly use:
Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or combinations of them along with layout padding and borders for white space.
See Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? (Yes.)
Provide ASCII art or a simple drawing of the intended layout of the GUI at minimum size, and if resizable, with more width and height.
Now, to expand on those comments for this use-case:
That is advice I offer for people trying to make a null layout, but it also applies here.
This is relevant because there is one component (the custom painted one, if it exists) that needs to #Override the getPreferredSize(..) method to return a size as a suggestion to the layout managers or for packing the top level container.
The 3rd comment is because it is hard to advise how to code this GUI without knowing the end effect that is required.
Of course, I should point out: Each SO thread is expected to be a single, specific question. I really should have told you to start a new question on the other matters, but let it slide for this edit.

Java Swing GUI - How to open multiple dialog boxes, one after another?

I am building an application which helps a user navigate a website by giving step by step instructions.
The instructions are given in the form of dialog boxes. I am using Java Swing to create the GUI dialog boxes.
Here is the structure of my code :
MainClass
{
//some selenium code to access the website 'Google.com'.....
InstructionDialog frame1 = new InstructionDialog("Enter 'Hello' in search field");
frame1.setVisible(true);
InstructionDialog frame2 = new InstructionDialog("Click 'Search' button");
frame2.setVisible(true);
InstructionDialog frame3 = new InstructionDialog("'Hello' is displayed in the results");
frame3.setVisible(true);
}
class InstructionDialog extends JFrame {
public String message;
public static javax.swing.JButton btnOk;
public InstructionDialog(String message)
{
//some code for the content pane //
msgArea = new JTextArea();
msgArea.setBounds(12, 13, 397, 68);
contentPane.add(msgArea);
msgArea.setEditable(false);
simpleStepMessage.msgArea.setText(message);
btnOk = new JButton("OK");
btnOk.setBounds(323, 139, 97, 25);
contentPane.add(btnOk);
btnOk.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
OkBtnActionPerformed(evt);
}
});
public void OkBtnActionPerformed(java.awt.event.ActionEvent evt)
{
this.dispose();
}
}
}
The problem when I run this is that all the 3 instances of the InstructionDialog run simultaneously. So I have all the 3 dialog boxes pop up at the same time.
But I want them to run one after another - the second dialog box should not appear until the OK button of the first is pressed, the third dialog box should not appear until the OK button of the second one is pressed.
How can I achieve this ?
Any help will be appreciated. Thanks.
The CardLayout is something I used for similar problems.
It is like a card deck and you can display one after another.
A time ago I had a similar issue. I developed the small library UiBooster. With UiBooster you can create blocking dialogs to ask the user for different inputs.
String opinion = new UiBooster().showTextInputDialog("What do you think?");

Honestly confused on how to apply Swing Timers to my program, can someone take a look?

I was reading about Swing Timers and the example really looks nothing like I was trying to do so I found it logically confusing to apply it to my program. I'm starting to think I don't even need a timer for this.
Here is what I am trying to do:
I am making a JFrame program that has the user enter a credit card number into a JTextField. Before they do this there is a JLabel that says "Please enter your number into the text field", then once they enter this into the field and hit enter, depending on whether my code determines that the card number is valid or not valid, the JLabel will change to "Invalid" or "Thank you, processing."
However, I have unsuccessfully found a way to make it change text based, it just seems to stay with whatever text I initially give it.
So could someone please look at my code and change it to do what I am asking? That would be excellent. You guys have been helpful in the past.
public class CreditGraphics {
public String cardNum;
public JFrame frame;
public JPanel panel;
public JLabel label;
public JTextField text;
public Timer timer;
public CreditGraphics() {
frame = new JFrame("HI");
panel = new JPanel();
label = new JLabel();
text = new JTextField(16);
panel.add(label);
panel.add(text);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(new Dimension(500, 500));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
label.setText("Hi");
label.setText("Hello");
text.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardNum = text.getText();
timer = new Timer(2000,this);
timer.setInitialDelay(1000);
timer.start();
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CreditGraphics();
}
});
}
public void checkCard(){
}
}
You have some major problems with your Timer's ActionListener as it is adding the anonymous inner ActionListener object, the this in the Timer's constructor, to itself. So it will call the very same actionPerformed inside the Timer that is called by the JButton that starts the Timer -- quite confusing. If your program were to need a Timer, you would do well to make sure to give it its own ActionListener, and not the same ActionListener that you add to your JButton as you're doing now.
Most importantly, do you even need a Swing Timer? I don't think so since you don't appear to be wanting an action repeatedly happening every xxx milliseconds, or an action that occurs once after xxx milliseconds, and since all you want to do is change the text. I suggest that instead you simply change your JLabel's text in the anonymous inner ActionListener class, and just leave it at that. If your requirements are different, then you will want to clarify and expand on your question.
So in semi-pseudocode, something like:
public void actionPerformed(ActionEvent e) {
String userText = text.getText();
if (testIfTextValid(userText)) { // some method to test if input OK
label.setText(INPUT_VALID); // String constant for JLabel to display
// here pass the userText to other parts of your code that needs to use it
} else {
label.setText(INPUT_INVALID);
}
}

Using actionListener with Button

I am programming a menu to be used with a formerly all text based game. I am trying to use addActionListener to print a line of text when a button is clicked, so I can figure out how to implement my main code in the future. The issue I am having is with the addActionListener method on my JButton. I am performing all of this with a JFrame. From what others say, I have used this as the argument but am getting a "non-static variable this cannot be referenced from a static context" error. Here is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Menu
{
public static void Menu()
{
JButton button = new JButton("Click to enter");
button.setBounds(125, 140, 150, 20);
JFrame frame = new JFrame("Casino");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(button);
button.addActionListener(this);
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension(400, 300));
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
#Override
String s = "Welcome!";
System.out.println(s);
}
}
Currently your program is nothing more than a single static method with everything trying to be shoehorned into this method. This would be fine if you were creating the most basic console program, such as one that asks the user for 2 numbers, then adds the numbers and returns the answer, but you are no longer trying to do this. Instead you're trying to create a Swing GUI program, one whose state you wish to change if the user interacts with it in an event-driven way, in other words you want it to change state if the user presses a button or selects a menu item.
Your problem is that you're trying to mesh this simple static world with the "instance" world, but in static land, there is no this.
Since your needs and requirements are becoming more complex, your program structure will need to change to reflect this. Is this an absolute requirement that you do this? No -- something called Turing Equivalence tells that it is possible to write most complex program imaginable inside of a single static main method, but due to the increased complexity, the program would become very difficult to understand and almost impossible to debug.
What I recommend specifically is that you create one or more well behaved object-orient classes, classes with non-static variables and non-static methods, and use these to build your GUI and its model (the non-GUI nucleus that GUI programs should have). Again the main method should be short, very short, and should only involve itself in creating the above classes, and setting the GUI visible, and that's about it.
What you want to do is to study the basic concepts of Java, and in particular that on how to create Java classes. The Java tutorials can help you with this.
There are a number of issues with this class.
It does not implement ActionListener so it can't be used as parameter to JButton
The static modifier on the Menu method means you can even use this anyway
public static void Main is not a constructor, so beware
#Override should appear before the method declaration, not in it.
Something like...
public class Menu implements ActionListener
{
public Menu()
{
JButton button = new JButton("Click to enter");
button.setBounds(125, 140, 150, 20);
JFrame frame = new JFrame("Casino");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(button);
button.addActionListener(this);
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension(400, 300));
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e)
{
String s = "Welcome!";
System.out.println(s);
}
}
Might be a better approach, but I'd be worried about creating a JFrame within the class, but that's just me...

WindowBuilder for Swing made member data and it seemed unnecessary

WindowBuilder for Swing creates checkboxes as local variables and textboxes as member data. This inconsistency bothered me. Since it all gets linked up into the toplevel JFrame anyway, these widgets are sure to live as long as the JFrame has references down to them so there doesn't seem to be a need for the textboxes to be member data. It seems to me that the textboxes should be locals just like the checkboxes. Locals are better encapsulation. The local references can die at the end of the GUI object (a class that extends JFrame) constructor generated by WindowBuilder and the JFrame will still have references to all the widgets.
Making them local and putting "final" in front of these widget declarations so that they can be used inside the event handler's anonymous inner classes was what it took to make them work. I also had to rearrange the order a bit since the order of instantiation of textboxes doesn't matter if they are all declared as members. Order does matter for locals so I had to move the uses of the "new" operator (instantiation) "up" a bit towards the top of the local scope. They just had to be north of the event handlers that use them.
So far I've found no bugs as a consequence so I am asking why WindowBuilder did not do it this way to begin with. I am new to Swing and WindowBuilder so there is a high probability that there are excellent reasons for WindowBuilder to not do this even though it seems to be the right approach for my case.
The following is the WindowBuilder output after some trivial naming modifications but before the modifications described above. This is the output as it is with 2 textboxes, 2 checkboxes, 2 buttons in the north and 1 label in the center. This is being pasted here in case somebody can see something here that may explain the choice behind WindowBuilder's use of member data.
public class TestWB extends JFrame
{
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JTextField textBox1;
private JTextField textBox2;
public TestWB() // the constructor
{
... // see the constructor below
}
}
The constructor for the above class:
public TestWB()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 646, 451);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel northPanel = new JPanel();
contentPane.add(northPanel, BorderLayout.NORTH);
JButton button1 = new JButton("button1");
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
northPanel.add(button1);
JButton button2 = new JButton("button2");
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
northPanel.add(button2);
final JCheckBox checkBox1 = new JCheckBox("cb1");
checkBox1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
CbProcessor cbp = new CbProcessor();
cbp.dealWithCb(checkBox1.isSelected(), textBox1);
}
});
northPanel.add(checkBox1);
final JCheckBox checkBox2 = new JCheckBox("cb2");
checkBox2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
CbProcessor cbp = new CbProcessor();
cbp.dealWithCb(checkBox2.isSelected(), textBox2);
}
});
northPanel.add(checkBox2);
textBox1 = new JTextField();
textBox1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
textBox1.setText("tb1");
northPanel.add(textBox1);
textBox1.setColumns(5);
textBox2 = new JTextField();
textBox2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
textBox2.setText("tb2");
northPanel.add(textBox2);
textBox2.setColumns(5);
JPanel centerPanel = new JPanel();
contentPane.add(centerPanel, BorderLayout.CENTER);
JLabel label1 = new JLabel("label1");
centerPanel.add(label1);
}
This is a case where reading the WindowBuilder docs would have easily answered your question(s). WindowBuilder will generate code any way that you like. Widgets can all be local variables, all be fields, or any combination in between. You can control the scope of different widgets individually or on a type-by-type basis (by setting defaults). In fact, WindowBuilder has an incredibly rich set of code generation preferences and can replicate just about any code generation style you could desire. It will also happily reverse engineer just about any code you throw at it, so you can make just about any changes you want to the generated code (by hand or via the tool) and it will remain perfectly happy.
I don't know something about WindowBuilder, but I do know something about SWT and SimpleDesktopAplication FrameWorks but
1) both are based on AWT(part from SWT) and Swing
2) both are overrode standard AWT & Swing's methods
3) in some cases is too hard to returns back to standard AWT & Swing's methods from Framework's methods
I'd suggest to learn basic Swing at begining,

Categories