so my problem is that i'm making a really simple number guessing game in java swing, i added a JButton and a JTextField, i want to click the button to get the value written in my text field and then pass it to a do while loop that's gonna make the operation, then i'm going to display it in a JLabel, But i don't know how. I have no JFrame cause i'm gonna send this class to the class that has the JFrame, so i'm adding everything to a JPanel.
hope I was clear, would appreciate some help.
code:
import java.util.Random;
import java.util.Scanner;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class GameDat extends JPanel {
JPanel panel = new JPanel();
FlowLayout layout = new FlowLayout();
Random random = new Random();
JButton enter;
JTextField display;
JLabel result;
int MIN = 1;
int MAX = 50;
int compare = random.nextInt(MAX - MIN + 1) + MIN;
int player;
int guessIt = 0;
public void iniGame(){
enter = new JButton("Pick a number:");
panel.setSize(300,300);
panel.setLayout(layout);
panel.add(enter);
panel.add(display);
panel.add(result);
enter.addActionListener(new CustomActionListenerEnter());
do {
//here should go the value captured from the JTextField instead of a scanner
player = input nextInt();
guessIt++;
if (player > compare)
//this text should go to the jlabel instead of printing it
System.out.println("Number is less than " + player);
else if (player < compare)
//this text should go to the jlabel instead of printing it
System.out.println("Number is greater than " + player);
else
//this text should go to the jlabel instead of printing it
System.out.println(compare + " was my number, it took you " + guessIt + " guesses.");
} while (player != compare);
}
class CustomActionListenerEnter implements ActionListener{
public void actionPerformed(ActionEvent e){
//I wanna pass this value to my do while.
display.getText();
}
}
}
My main recommendation: get rid of the while loop. This loop works with a linear console type program, but this is not how event-driven GUI's work, and that loop will tie up the Swing event thread, rendering your GUI frozen and useless. So, again, get rid of that loop, and instead change the state of a variable in this class based on user's response, and base behavior on that state. So in your ActionListener, get the text from the JTextField, convert it to an int by parsing it, check if it's a decent guess, and notify the user of the results of their guess.
Other issues:
You understand that your class above creates two JPanels, one the JPanel which is the instance of the class itself, and which you add nothing to, and the other one that is referenced by the panel variable that you do add components to. If you're only going to use the panel variable JPanel, then the class should probably not extend JPanel.
What's with the,... //here should go the value captured from the JTextField instead of a scanner and player = input nextInt();? Get rid of this non-compiling code and not helpful code and use the JTextField. It looks like you're trying to shoe-horn console code into a GUI, and this won't work.
Do not use System.out.println(...) or similar code for user interaction, but only for temporary debugging if that. All user interaction should be through the GUI itself, and final production code should not have printlns.
Well it turned out like this at the end, and it works fine. Thanks.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
player = Integer.parseInt(jTextField3.getText());
guessIt++;
if (player > compare)
jTextField1.setText("Number is less than " + player);
else if (player < compare)
jTextField1.setText("Number is greater than " + player);
else
jTextField1.setText(compare + " was my number, it took you " +
guessIt + " guesses.");
}
Related
I am trying to learn some basic java by following a book, one of the exercises requires that I display a set of bar graphics based on user input.
I have to query the user to input the no. of bars to be shown and the length of each.
I use the following:
1`st is the Bar class I defined to draw rectangles corresponding to the numbers inputed
import java.awt.Graphics;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Bar extends JPanel
{
private int noOfBars; // number of bars to display
int i = 0;
// constructor with choice input
public Bar (int noOfBars)
{
this.noOfBars = noOfBars;
}
// draw desired shapes starting from default position (0, 5) and incrementing for each new bar
public void paintComponent(Graphics g)
{
super.paintComponent(g);
do
{
String input = JOptionPane.showInputDialog("Enter number: ");
int length = Integer.parseInt(input);
for (int j = 1; j <= length; j++)
g.drawRect(0, 5 + i * 20 ,j * 15 , 15);
i++;
} while (i < noOfBars);
}
}
2`nd is the main class:
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class ShapesExercise
{
public static void main(String[] args)
{
int noOfBars = 0;
// obtain user choice
String input = JOptionPane.showInputDialog("Enter total bars to display:");
noOfBars = Integer.parseInt(input);
if (noOfBars == 0)
{
JOptionPane.showMessageDialog(null,"Invalid number.");
input = JOptionPane.showInputDialog("Enter total bars to display::");
noOfBars = Integer.parseInt(input);
}
JFrame application = new JFrame();
application.setSize(300, 40 + 25 * noOfBars);
Bar panel = new Bar(noOfBars);
application.add(panel);
application.setVisible(true);
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
My issue is as follows:
The first message_dialog (the one created in the main class) works correctly, popping up only once and querying for input.
But the message_dialogs generated by the Bar class keep popping up even after reaching the end of the "do while" loop (this was initially a "for" loop but I changed it to "do while" in an attempt to troubleshoot the code).
I have no idea why this happens. While researching online I could not find something related.
Thank you in advance.
paintComponent is called by Swing’s painting architecture, which in turn is largely dependent on the native system. paintComponent can be called several times per second, depending on the circumstances; it may be called once, or several times, when a window is moved or brought to the front. It may be called for each movement of the mouse over it.
You have no control over when paintComponent is called. You must only draw in that method. You MUST NOT call JOptionPane in it. You must not change any state, and you must not change the component or any other components in that method.
If you want to call JOptionPane, do it elsewhere, and then call repaint() to request that the Swing system eventually call your paintComponent method.
You can learn more at https://docs.oracle.com/javase/tutorial/uiswing/painting/.
I have a question I have a program where I want to test the users ability to remember a random list of colors. Based off if the users input is right or wrong it will ask for the next color.
So I got it all work up to where the user inputs the first color. Before it has the user input on the first color. The program is already assuming the user input is wrong, even tho it hasn't asked for any input.
I know from previously knowledge I could like flush the buffer, can you do that with JOptionPane?
Or is this another issue I'm not seeing?
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JOptionPane;
public class Testing
{
//Intialization of the whole program for everything to pass information
public JFrame main;
public JLabel lbInsturctions;
public JLabel welcomeMessage;
public JLabel homeScreen;
public JLabel homeScreenColors;
public JTextField txtInput;
public int num = 1;
public String colorList = "";
public String[] color = {"red","green","blue","brown","yellow", "gold", "orange", "silver"};
public String[] solution = new String[5];
//sets up the window and random colors
public Testing ()
{
Random r = new Random();
for (int i = 0; i<solution.length; i++)
{
solution[i] = color[r.nextInt(7)];
colorList = Arrays.toString(solution);
}
JOptionPane.showMessageDialog(null, "Lets test your memory. Memorize these colors: " + colorList);
main = new JFrame ();
main.setSize (500,300);
main.setTitle ("Ultimate Colors");
main.setDefaultCloseOperation(main.EXIT_ON_CLOSE);
main.setLayout(new FlowLayout());
intializeGame();
main.setVisible(true);
}
public void intializeGame ()
{
//All Intiazations
lbInsturctions = new JLabel();
homeScreen = new JLabel();
txtInput= new JTextField(null, 15);
//Need to delete or make new window if user pushes ok then
lbInsturctions.setText("Enter color number " + num + ":");
main.add(lbInsturctions);
main.add(txtInput);
txtInput.addActionListener(new colorTester());
}
public class colorTester implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
//Need to delete or make new window if user pushes ok then
lbInsturctions.setText("Enter color number " + num + ":");
//grabs the users input to see if it is corect
String guess= "";
guess = txtInput.getText();
System.out.println(guess);
//Checks to see if the users input is the same as the initalizaton
if (color[num+1].equalsIgnoreCase(guess) || num > 6)
{
System.out.println("You got it!");
++num;
lbInsturctions.setText("Enter color number " + num + ":");
txtInput.setText("");
}
//if the User input is wrong
else
{
System.out.println("It's a good thing your not graded!");
txtInput.setVisible(false);
lbInsturctions.setText("It's a good thing this is not graded!");
}
if (num == 5)
{
lbInsturctions.setText("You memory is perfect good job!");
txtInput.setVisible(false);
}
}
}
}//end of program
This has nothing to do with flushing buffers.
You're getting user input here: guess = txtInput.getText(); which is in the intializeGame method. Meaning you're getting the text from the txtInput JTextField on its creation, before the user has had a chance to enter anything into the field. I think that you're used to programming linear console programs, where you get the user's input immediately, but that's not how event-driven GUI's work. Instead you must get and react to the user's input on event, here perhaps the ActionListener of some button. Perhaps your code needs a "submit" JButton or something similar, and in its ActionListener, extract the input from the JTextField and respond to it. Do this and your code has a better chance of working.
Other issues:
you don't ever appear to have added your txtInput JTextField into the GUI.
same for the homeScreen JLabel
Edit your new code posted at the bottom of your question has the same problem.
So I am working with JComboBox in my new program, but for some reason every time something is selected it repaints. I do not want it to repaint the entire program when something is selected, just the boxes specified. See the code below.
The first section here is from the class that contains the panel.
First here are the declarations for the JComboBox's and the Labels they edit once selected:
private JComboBox crewview = new JComboBox(SpaceGame.stuffselector);
private JComboBox resourceview = new JComboBox(SpaceGame.stuffselector1);
private JLabel crewmember, crewmember1, crewmember2;
private JLabel resourcev, resourcev1, resourcev2;
where stuff selector is an array of number digits 1 to 10
My paint method containts these, as it does not work unless I have these here:
resourceview.setLocation(400,80);
resourcev.setLocation(455,85);
resourcev1.setLocation(455,95);
resourcev2.setLocation(455,105);
crewview.setLocation(400, 20);
crewmember.setLocation(455,25);
crewmember1.setLocation(455,35);
crewmember2.setLocation(455,45);
And here are my action listeners:
private class crewviewListener implements ActionListener{
public void actionPerformed(ActionEvent e){
lifeForm temp = SpaceGame.playership.getCrewat(crewview.getSelectedIndex());
crewmember.setText("Name: " + temp.getName()); //set the text to the crew member
crewmember1.setText("Race: " + temp.getRace());
crewmember2.setText("Worth: " + temp.getWorth());
}
}
private class resourceviewListener implements ActionListener{
public void actionPerformed(ActionEvent e1){
Resource temp1 = SpaceGame.playership.getResourceat(resourceview.getSelectedIndex());
resourcev.setText("Name: " + temp1.getName()); //set the text to the crew member
resourcev1.setText("Worth: " + temp1.getWorth());
resourcev2.setText("Amount: " + temp1.getAmount());
}
}
So as you may tell be reading the code, I am trying to get it to only update the JLables when stuff in the box is selected, and not repaint everything.
JLabels are non-opaque by default. This means that whenever you change the text in the label, the background of the label must also be repainted. Therefore the panel that contains the label will also be repainted.
Swing will usually determine a clipped area of the panel to be repainted. That is the rectangular area that contains the 3 labels will be repainted, not the entire panel.
Post a SSCCE that demonstrates the problem if you need more help.
I am fairly new to java so bear with me please, basically, below I have a tabbed pane for each of the four rooms in the rooms Arraylist, and I am creating buttons in each tab depending how many lights each room has, How can I associate the buttons in each tab with a specified the rooms?. So like when I click the light button in the Room 1 tab, the event listener knows that the button belongs to the room1?
Any help is appreciated, thanks.
import java.util.ArrayList;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class MasterGUI extends JFrame implements ActionListener{
public MasterGUI(){
}
public void DisplayFrame(){
ArrayList<Rooms> rooms;
rooms = Building.getRoomList();
JFrame master = new JFrame("Solar Master Control Panel");
master.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container content = master.getContentPane();
content.setBackground(Color.lightGray);
JTabbedPane tabbedPane = new JTabbedPane();
JPanel tmpPanel;
for(int x = 0; x < rooms.size(); x++){
tmpPanel = new JPanel();
String roomName = rooms.get(x).getName();
int id = rooms.get(x).getId();
tabbedPane.addTab(roomName + " Room " + id, tmpPanel);
}
for(int x = 0; x < rooms.size(); x++){
for(int i = 0; i < rooms.get(x).roomLights.size(); i++){
int num = i + 1;
((JPanel) tabbedPane.getComponentAt(x)).add(new JButton("Light" + num));
}
}
master.add(tabbedPane, BorderLayout.CENTER);
master.setSize(800, 600);
content.add(tabbedPane);
master.setVisible(true);
}
public void actionPerformed(ActionEvent e){
}
First of, you need to add the ActionListener to the button so it will be called when the button is clicked.
...
JButton button = new JButton("Light" + num);
button.addActionListener(this);
((JPanel) tabbedPane.getComponentAt(x)).add(button);
...
As far as differentiating between which button was clicked, there are two main ways to address this. The first is to use getSource() on the ActionEvent to get a reference to the object that triggered the event. You can use this to decide how you want to proceed further. The other option is to have MasterGUI not implement ActionListener. Instead, make a unique ActionListener for each button that immediately know what action needs to occur when it was called. The first option makes it easier to register listeners, but requires more work in the handler to determine the source. I prefer the second method.
ActionEvent in actionPerformed() will tell you the source of the button pressed. So you can do one of two things, you can name the button (which is not the same as the button text) something indicative of the room, or you can provide a command string that the button invokes, which is also available from the ActionEvent.
Check out the JButton JavaDoc, it has links to dealing with Actions and specifically button Actions supported.
It will focus your question a little better as well, since you'll have a better idea of how you're looking to achieve your goal.
I am creating a hangman game. I made a button A - Z using the GUI Toolbars in Netbeans as follows:.
My problem is, how can I add an actionlistener to all of it. Is it possible to use a loop? If i click the button A, i will get the character 'a' and so on..
Yes it is possible to use a loop, but since your JButtons were created by using NetBeans code-generation, they won't be in an array or collection initially, and so this is something that you'll have to do: create an array of JButton and fill it with the buttons created by NetBeans. Then it's a trivial matter to create a for loop and in that loop add an ActionListener that uses the ActionEvent's actionCommand (as noted above) in its logic.
Having said this, I think that the better solution is to forgo use of the NetBean's GUI builder (Matisse) and instead to create your Swing code by hand. This will give you much greater control over your code and a much better understanding of it as well. For instance, if you do it this way, then in your for loop you can both create your buttons, add the listeners, and add the button to its container (JPanel).
e.g.,
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class Foo2 {
public static void main(String[] args) {
JPanel buttonContainer = new JPanel(new GridLayout(3, 9, 10, 10));
List<JButton> letterButtons = new ArrayList<JButton>(); // *** may not even be necessary
for (char buttonChar = 'A'; buttonChar <= 'Z'; buttonChar++) {
String buttonText = String.valueOf(buttonChar);
JButton letterButton = new JButton(buttonText);
letterButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
System.out.println("actionCommand is: " + actionCommand);
// TODO fill in with your code
}
});
buttonContainer.add(letterButton);
letterButtons.add(letterButton);
}
JOptionPane.showMessageDialog(null, buttonContainer);
}
}
Well, with some pseudo code, wouldn't this make sence for you?
for(button in bord) {
button.addActionListener(my_actionlistener);
}
Then in your actionlistener you can see which button was pressed
public void actionPerformed(ActionEvent e) {
// button pressed
if ("string".equals(e.getActionCommand()) {
// do something
}
// and so forth
}
You'll need to add the buttons to a list of some kind so you can iterate through them, Netbeans doesn't do this for you when you generate the buttons.
After that, just run a for each loop on the list containing all the buttons. To get the values of the characters just cast the relevant ascii value, which starts at 97 for a lower case a or 65 for an upper case A:
int charNum = 97;
for(Button b : board) {
char charVal = (char)charNum;
charNum++;
//add the action listener
}