I'm a coding newb and want to learn some more java. I'm currently taking an introductory programming course in high school and am just trying to play around outside of class. This program I'm creating is supposed to print out a few instructions and questions in the console, to which I want to retrieve user input using a scanner and variable. The goal of the program is for the user to be able to create a 'drawing' based on pure instinct, then this drawing is displayed after the fact.
Here's my problem. I'm asking the user and storing the information in variables that are native to the main method, but I need to use this information in the paintComponent method.
I tried adding static in front of the variable such as:
static int emptyRectW1 = kboard.nextInt(); but this just shows the error "Illegal modifier for parametic emptyRectW1; only final is permitted."
I knew it was a long shot trying that out, but that's the best I've got.
I'm using Java Eclipse as my IDE.
Thanks for any help, looks like the only way to learn is to mess up and have somebody else point out my mistake! :)
Here's the code:
import java.util.Scanner;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BlindDrawing extends JPanel {
public static void main (String[] args) {
Scanner kboard = new Scanner(System.in);
System.out.println("Welcome to the Blind Drawing Game!");
System.out.println("In this game, you will be asked questions about how to construct an image using rectangles and ovals. You will be asked the shape's dimensions and position. The origin (0,0) is the top left corner.");
System.out.println("First you're making an empty rectangle, how wide do you want it to be?");
int emptyRectW1 = kboard.nextInt();
System.out.println("What about the height?");
int emptyRectH1 = kboard.nextInt();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0,0,emptyRectW1, emptyRectH1);
}
}
Update: In the comments an example was requested, so here's a simple one. This is just a simple demonstration of the ideas I talk about; it does not build on the above code. The reason is that, as others have noted, there are additional things you'd want to correct about the structure of that code. Rather than try to address them in detail, or give an example that encourages them, I'll just focus on the points I was making in my original answer:
public class SampleObject {
private int aValue;
protected void getVAlue() {
Scanner kboard = new Scanner(System.in);
System.out.println("Enter a value:");
aValue = kboard.nextInt();
}
protected void printValue() {
System.out.println("The value is " + aValue);
}
public void processValue() {
System.out.println("Welcome");
getValue();
printValue();
}
public static void main(String[] args) {
SampleObject sampleObject = new SampleObject();
sampleObject.processValue();
}
}
Some styles would have the main method in a separate "application class"; some frameworks have such a thing, wich might have responsibilities like handling outside messages requesting the app shut down, or whatver.
And generally as your applications get beyond simple exercises, you'll want to have more than just one class/object - each with distinct responsibilities that make up your application's functionality.
But for now, this should show how instance data woriks, and how to bootstrap a collection of objects rather than doing lots of processing in a static main method.
Good luck!
As a general answer to the question: variables defined inside a method are not available to other methods, and this is by design of the language. (Some advanced features twist this rule a little, but not in the way you want; and those things are a bit down the road from where you are anyway.)
To share state among methods, you add data members (sometimes called fields) to the class itself. Then values can be assigned in one method and read in another, or whatever, throughout the class.
However, as soon as you try to use that advice you're going to run into another problem, because main() is (and must be) static and your other method isn't (and probably shouldn't be). So you're going to do one of two things to fix that - the easy thing, or the right thing.
The easy thing would be to add static data members - making the data belong to the class rather than an instance of the object. The non-static methods could still see those. But this is leading you in the wrong direction.
The right thing is to do nothing more than bootstrap your application in the main method. What this means is, create object instances that can collaborate to carry out your program's function, and then set those objects in motion. Then all the actual work - like prompting for user input, etc. - should happen in (generally non-static) methods of those objects.
It's a very surface explanation, but really this isn't the place for an in-depth programming lesson. If your curiosity is getting ahead of the coursework, there certainly are good tutorials for OO programming and Java online (or at your local book store... though I may be dating myself with that suggestion).
Good luck.
The simple answer: pass the information obtained in the main method into the BlindDrawing object via either a method or a constructor's parameters.
But having said that you really don't want to mix a linear console type application with an event driven GUI app. Choose one or the other and stick with it. Here you can get the information you need via JOptionPanes if you need to get them before launching the main GUI application, and then again pass them into the main GUI application as described above -- via constructor parameters.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.*;
public class BlindDrawing extends JPanel {
private Rectangle rectangle;
public BlindDrawing(Rectangle rectangle) {
setPreferredSize(new Dimension(1000, 800));
this.rectangle = rectangle;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (rectangle != null) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.draw(rectangle);
}
}
private static void createAndShowGui(Rectangle rect) {
BlindDrawing mainPanel = new BlindDrawing(rect);
JFrame frame = new JFrame("BlindDrawing");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
String message = "Enter 4 numbers for X, Y, Width, and Height, separated by a space";
String title = "Get Rectangle Coordinates";
int messageType = JOptionPane.PLAIN_MESSAGE;
String input = JOptionPane.showInputDialog(null, message, title, messageType);
String[] tokens = input.split("\\s+");
if (tokens.length == 4) {
int x = Integer.parseInt(tokens[0]);
int y = Integer.parseInt(tokens[1]);
int width = Integer.parseInt(tokens[2]);
int height = Integer.parseInt(tokens[3]);
Rectangle rect = new Rectangle(x, y, width, height);
SwingUtilities.invokeLater(() -> createAndShowGui(rect));
}
}
}
EDIT
You asked in comments:
What I don't understand are the ones towards the bottom that have tokens. I don't really understand what these tokens do, if you could clarify, that would be great!
The question for me is: how can we most easily allow the user to enter for ints to use in a Swing application, but to sub-divide this even further we can ask for solutions that are most easy for the coder and solutions that are most easy for the user. In general you will want to prefer going after the latter.
The easiest for the coder is to create a simple console application and have the user enter the numbers using String prompts and a Scanner object that has been initialized to the standard input or System.in. As I've mentioned, while this is easy for the coder, it does not work well for the user since console applications and GUI applications don't play nice together as one is structured in a linear fashion while the other is much more free-flowing and event driven. If you want to get data later on while the program runs, and you again have the user enter information through the console, you risk either freezing the Swing application, rendering it useless, or updating the Swing application inappropriately in a background thread.
My solution above is a compromise where we prompt the user for a single String by using a JOptionPane.showInputDialog(...). This will give the user a prompt, and allow him to enter a single String into a text field. Here I ask the user to enter four numbrers separated, each separated by a space, and I think that you understand this part, but one problem with it is, once you get that String, which I call input, how do you extract the four numbers out of it.
One way is to split the String into an array of Strings (which I call tokens) using String's split(...) method. A simple way to do this is like so:
String[] tokens = input.split(" ");
This will split the input String into an array of sub-strings by splitting on a single space. It doesn't work so well if the user accidentally uses more than one space between his numbers, or if he uses different "white-space" to separate the numbers. I instead used:
String[] tokens = input.split("\\s+");
This uses something called regular expressions or "regex" for short to split the String. \\s represents any white-space character, and the + means that we'll split on one or more white-space characters. So if the user puts 2 or 3 spaces between his numbers, this still will work.
Another possible way to split this String is to put it into a Scanner and then "scan" for ints. Here we don't Scan with the standard input, with System.in, but rather we scan the entered String, here input. For example:
// get our line of input same as we did before
String input = JOptionPane.showInputDialog(null, message, title, messageType);
// create a Scanner object that scans through the line
Scanner inputScanner = new Scanner(input);
// extract the four numbers from the line
int x = inputScanner.nextInt();
int y = inputScanner.nextInt();
int width = inputScanner.nextInt();
int height = inputScanner.nextInt();
// close the Scanner so we don't waste resources
inputScanner.close();
There are still problems with this since all these solutions fail if the user enters 2 or 3 numbers and not 4, or if the user enters non-numeric input, and there are other ways of checking for this and correcting, such as using a JSpinner or JComboBox that limits the user's selections to allowed numbers, or by using try/catch blocks to catch invalid input and then prompt the user for more correct input.
You can initialize them as instance variables so they can be used by various other methods, like so:
public class BlindDrawing extends JPanel {
private int emptyRectW1;
private int emptyRectH1;
public static void main (String[] args) {
new BlindDrawing().run();
}
private void run() {
Scanner kboard = new Scanner(System.in);
System.out.println("Welcome to the Blind Drawing Game!");
System.out.println("In this game, you will be asked questions about how to construct an image using rectangles and ovals. You will be asked the shape's dimensions and position. The origin (0,0) is the top left corner.");
System.out.println("First you're making an empty rectangle, how wide do you want it to be?");
emptyRectW1 = kboard.nextInt();
System.out.println("What about the height?");
emptyRectH1 = kboard.nextInt();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, emptyRectW1, emptyRectH1);
}
}
Actually, a variable declared inside a method is a local variable.
Please extend the scope of the the two variables just before your main method. See code below.
static int emptyRectW1, emptyRectH1;
public static void main (String[] args) {
Then manipulate the latter code to avoid duplicate variable declaration as shown below.
emptyRectW1 = kboard.nextInt();
System.out.println("What about the height?");
emptyRectH1 = kboard.nextInt();
I hope this helps.
I am currently making a TicTacToe program for an assignment in college. I have my board laid out with 3x3 JTextFields, each one has an action listener attached. What I need to do is create another class which will check for errors (eg a user will put a number or a letter that is NOT x or o) they should get a dialog box stating the error and the JTextField they tried to enter will return to blank. How would I go about implementing the error checking, through try - catch - finally method?
Another question, I have a GameGUI class, I also want to have a GameLogic class. How do I check from GameLogic if the game has been won? In my GameLogic I will have something like
if j1, j2 and j3 are all x or o then display dialog box "x player wins".
I will try to answer the question regarding a general board game. Your object oriented thinking of splitting into different classes is correct. What I do generally is that I have the GameLogic containing my logic and validations for the game as well as determining whether the game is over or not and so on.
The GameGUI class would then have an instance variable of the type GameLogic that's initialized on creating an object of type GameGUI. In my way of thinking, I would have the GameLogic representing the board state with 2D Array of chars. The GameGUI would be just there to relay input from the user to the GameLogic which determines if the game is over. The GameLogic should throw an Exception of the type that you want to clarify and then the GameGUI should try to update the board with the input text from the user in the JText fields, catch the error from the GameLogic (if any) and then repaint the GUI that's displayed to the user based on the input it got. I will give a sample below to clarify my point although I won't provide the actual implementation for the TicTacToe game, you can easily do it on your own.
public class GameLogic {
....
char[][]board;
public GameLogic() {
//initialize the board representation for game
}
public boolean gameOver() {
//determine if the game is over by checking the board 2D array
// 3 xs or os in a row, column, or diagonal should determine the game is over or if there are no more moves
}
public void move(char character, int x, int y) {
//update a certain position with a character should throw an Exception if the character is invalid or if the the character is valid but it's not the character that the user owns player1 plays with x for example but puts o.
//should also have the logic for the turns
}
...
}
public class GameGUI {
.....
GameLogic engine;
public GameGUI() {
engine = new GameLogic();
}
public void actionPerformed(ActionEvent e) {
// here you would get the co-ordinates of the clicked JTextButton
// then call the method move on the engine instance
try {
engine.move(character, x, y);
} catch(Exception e) {
//display the validation for the error that happened
}
//repaint the representation from the engine to be displayed on the GUI Frame that you are using
}
...
}
One more thing is that I would have declared the JTextFields as 2D Array of JTextFields and not as individual instance variables to mirror the representation in the GameLogic class. You can also avoid the validations all together if you use JButton class instead of JTextField and that the user gets the character he is playing with on the clicked button if it is his turn and the button is not already used before.
I am making a button using MouseOverArea. After some trial and error, I realized I can override the methods in InputListener to do particular actions when an input event is notified.
For example, do things when mouse left button is pressed while cursor is over the component.
#Override
public void mousePressed(int button, int mx, int my) {
if (isMouseOver() && button == Input.MOUSE_LEFT_BUTTON) {
// Some magic happens
}
}
However, I will not able to do things like changing current game state because no Game object around. I know there are many ways to solve this problem, but I would like to know what is the Slick way to do this.
Are these methods suitable for such behavior ?
One way to modify game states is to use boolean states; Which are boolean variables that hold the state of the game or player. For example:
boolean isMovingUp, isMovingLeft, isMovingRight, isMovingDown;
You can then set these to true/false depending on what mouse or keyboard event takes place and your game class then read these variables, like so:
if (isMovingUp) {
// do something
isMovingUp = !isMovingUp;
}
Hope that helps!
I'm using andengine for android for the first time. I'm creating a simple list of text that simply needs to be able to call the same method but send a different variable accroding to its position on the list. The list does not need to scroll and is short. I decided to use simple text and created a for loop to make them for me from a string array.
The loop works and creates the text properly but when touching they all perform the last touch assignment instead of the corresponding one.
Does the onAreaTouched code need to be referred to or is it saved some where once the touch area is registered.
here it is:
for(x =1; x<base.locale.length;x++){
textLoc[x-1]=new Text(10,(110+(x*30)),base.getmFont(),
base.locale[x],HorizontalAlign.CENTER){
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
base.moveListen(Integer.toString(x));
loadNewScene();
return true;
}
};
scene.getLastChild().attachChild(textLoc[x]);
scene.registerTouchArea(textLoc[x]);
}
Does that code compile? As in this line:
base.moveListen(Integer.toString(x));
you are refering to the non-final loop-variable x.
Using a JEditorPane, is there any way to tell if the caret is currently on the last line? I cannot find anything in the API or more importantly JTextComponent of which JEditorPane is derived. I need to find this out when the user uses the down arrow key to move down the text. My current idea is this:
private boolean isEndOfText() {
int tmpCurrent = editor.getCaretPosition();
editor.getActionMap().get(DefaultEditorKit.endLineAction).actionPerformed(null);
int tmpEnd = editor.getCaretPosition();
try { editor.setCaretPosition(tmpEnd + 1); } catch (Exception e) { editor.setCaretPosition(tmpCurrent); return true; }
editor.setCaretPosition(tmpCurrent);
return false;
}
This code would run whenever the down key is pressed and would return whether or not it is in fact the end of the text by detecting if an error occurs if the caret is being put after the last possible position which would be the end of the line (if it is in fact the last line) otherwise it means the end of text has not been reached.
You should be able to use the Text Utilities. One method returns the total lines and another method return the line at the caret.
I've never played with a JEditorPane that much since I don't like its HTML support. You might also be able to use editor.getDocument().getLength() to determine if the caret is at the end of the document. This will work with a JTextArea or a JTextPane that only displays text, not HTML. Not sure how it works in a JEditorPane.
There's probably a better way, but you could try this:
return editor.getText().indexOf("\n", editor.getCaretPosition()) == -1;