I just start my journey with JavaFX and I'll try to make a simple calc.
I have that code to make all my buttons:
Button one = new Button("1");
Button two = new Button("2");
Button three = new Button("3");
Button four = new Button("4");
Button five = new Button("5");
Button six = new Button("6");
Button seven = new Button("7");
Button eight = new Button("8");
Button nine = new Button("9");
Button zero = new Button("0");
Button dot = new Button(".");
Button pow = new Button("^2");
TextField equation = new TextField();
Button equal = new Button("=");
Button multiple = new Button("*");
Button divide = new Button("/");
Button takefrom = new Button("-");
Button add = new Button("+");
In the start method ill add them all to the boxes and then to the root. My main class implements EvendHandler. Now i want apply .onAction(this), to each button.
There is a way to extract only buttons from root node?
I tried getChildren() and then for each but I can't get it to work.
Is there a good habit to make a arraylist for my buttons only and then make a loop that can do it?
Or there is another way?
All code can be found at:
http://pastebin.com/RBzbn8bT
You can use an instanceof test for this, or (with a bit of trickery) do a lookup. But neither of these are particularly nice solutions: a more elegant solution is just to define one or more methods for creating the buttons, and put all the code you need for each button there. That way you can easily define a different handler for each button.
This basic idea is something like:
public class Calculator extends Application {
private GridPane root ;
#Override
public void start(Stage primaryStage) {
root = new GridPane()
// zero button:
root.add(1, 4, createNumericalButton(0));
// buttons for 1-9:
for (int i = 1 ; i <= 9 ; i++) {
Button button = createNumericalButton(i);
int row = 2 - (i-1)/3 ; // {7,8,9} -> 0; {4,5,6} -> 1; {1,2,3}->2
int col = (i-1) % 3 ;
root.add(col, row, button);
}
// other layout...
}
private Button createNumericalButton(final int n) {
Button button = new Button(Integer.toString(n));
button.setMinSize(32, 32);
button.setOnAction(event -> {
// replace with real handler...
System.out.println("Pressed "+n);
}
return button ;
}
}
You can similarly define a createOperationButton(...) method for creating the buttons for +, -, *, and / etc. If you want to get a bit more sophisticated, that method could take a DoubleBinaryOperator as a parameter, for specifying the behavior of each button. So you'd end up doing something like:
root.add(4, 3, createOperationButton("+", (x, y) -> x + y));
root.add(4, 2, createOperationButton("-", (x, y) -> x - y));
root.add(4, 1, createOperationButton("*", (x, y) -> x * y));
root.add(4, 0, createOperationButton("/", (x, y) -> x / y));
In order to extract only buttons, you can use the instanceof keyword.
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op2.html
In your case, you could iterate through all the children of your root and check if they belong to the Button class.
For example:
for(int i=0; i<root.getChildren().size(); i++)
if(root.getChildren().get(i) instanceof Button) {
your code here
}
Related
I am working a JFrame calculator, I am not to familiar with so I was following a tutorial, and I've double checked it a couple times.
It's not working, its not throwing any errors or anything, it will compile and run. Just nothing pops up.
I am using Eclipse, and it is giving two warnings,
one about my constructor not being used in my main
that my class says this: The serializable class Gui does not declare a static final serialVersionUID field of type long.
I'm not sure why those would come up, but my code seems to be like the tutorial.
Thank you in advanced.
Ps. excuse the all commons, I just making sure I can looking back at it without having to refer back to the tutorial.
// This will make the visuals of the calc
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Gui extends JFrame implements ActionListener {
JPanel[] row = new JPanel[5];
JButton[] button = new JButton[19];
String[] buttonString = {"7", "8", "9", "+", // This is a string for the buttons that we will later apply to
"4", "5", "6", "-", // the the buttons with a loop, instead of 19 lines for each one
"1", "2", "3", "*",
".", "/", "C", "√",
"-/+", "=", "0"};
int[] dimW = {300, 45, 100, 90}; // An Array for the different widths of the display and buttons
int[] dimH = {35, 40}; // An array for the different heights of the display and buttons
Dimension displayDimension = new Dimension(dimW[0], dimH[0]); // The dims for the display using the first ints of the arrays
Dimension regularDimension = new Dimension(dimW[1], dimH[1]); // The
Dimension rColumnDimension = new Dimension(dimW[2], dimH[1]);
Dimension zeroButDimension = new Dimension(dimW[3], dimH[1]);
Boolean[] function = new Boolean[4]; // A boolean array to tell, which operator we are using
double[] temp = {0, 0}; // A temp array for the calc, might not use when using my stack calc
JTextArea display = new JTextArea(1, 20); // This is the display where the text will be displayed
Font font = new Font("Ariel", Font.BOLD, 14);
Gui() {
super("Gui");
setDesign();
setSize(380, 250); // Set the frame size
setResizable(false); // Makes so it can't be resized, can mess up layout if it true
setDefaultCloseOperation(EXIT_ON_CLOSE); // What happens when it closes
GridLayout grid = new GridLayout(5, 5); // Since we need a grid of 5 by 5 for the buttons this makes the grid
setLayout(grid);
for (int i = 0; i < 4; i++) // Sets values for the function array, might use might not with my clac
{
function[i] = false;
}
FlowLayout f1 = new FlowLayout(FlowLayout.CENTER); // This will only be use to layout row 1
FlowLayout f2 = new FlowLayout(FlowLayout.CENTER, 1, 1); // The ints are used to give a 1 pt gap vert and horiztal
for (int i = 0; i < 5; i++) // Intinalizing the Jpanel row's so we can use them
{
row[i] = new JPanel();
}
row[0].setLayout(f1); // Since we need the first row to have the special layout of f1 we just assign it
for (int i = 1; i < 5; i++) // Since we already set the first row "Row[0]" to f1, we have to start with row 2 or row[1] for i
{
row[i].setLayout(f2);
}
// After this all the rows have the correct layout, we can set up the buttons
// And set the same thing to each button with a loop
for (int i = 0; i < 19; i++) {
button[i] = new JButton(); // Creates a new button for each button in the array
button[i].setText(buttonString[1]); // Sets text on the button with the text from the list, in ButtonString
button[i].setFont(font); // Makes it nice looking with the fancy font we used in the font line
button[i].addActionListener(this); // This is what makes the button actually work
}
// Buttons done we can move to the display set up
display.setFont(font); // Set the fancy font to the display too
display.setEditable(false); // Makes it so no input from the keyboard, will have to change this on final product
display.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); // Makes it pop in right to left
// With the fonts and everything intinlized we can start to set the sizes for the compents
display.setPreferredSize(displayDimension); // Sets the size of the display
// We can use a loop for the regular buttons, i think all but zero
for (int i = 0; i < 14; i++) {
button[i].setPreferredSize(regularDimension); // Sets the size of the regular buttons
}
for (int i = 14; i < 18; i++) {
button[i].setPreferredSize(rColumnDimension); // Sets the size of the right column of buttons, the operrantors
}
button[18].setPreferredSize(zeroButDimension); // Sets the size of the zero button since its bigger
// Now that we got evrything sized up time to add everything to the panel
row[0].add(display); // Adds the display to row 1
add(row[0]); // Adds row 1 to the panel
for (int i = 0; i < 4; i++) {
row[1].add(button[i]); // all the number buttons to the row
}
row[1].add(button[14]); // adds the operator button to the row
add(row[1]); // adds the row
for (int i = 4; i < 8; i++) {
row[2].add(button[i]); // all the number buttons to the row
}
row[2].add(button[15]); // adds the operator button to the row
add(row[2]); // adds the row
for (int i = 8; i < 12; i++) {
row[3].add(button[i]); // all the number buttons to the row
}
row[3].add(button[16]); // adds the operator button to the row
add(row[3]); // adds the row
row[4].add(button[18]);
for (int i = 12; i < 14; i++) {
row[4].add(button[i]); // all the number buttons to the row
}
row[4].add(button[17]); // adds the operator button to the row
add(row[4]); // adds the row
setVisible(true); // Makes so you can see it
}
// Not sure what this is
public final void setDesign() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
}
}
// Will be use to make actionlistener work
public void actionPerformed(ActionEvent ae) {
}
public void main(String[] arguments) {
Gui c = new Gui();
}
}
You should really have this in your main method
public static void main(String[] args){
Gui c = new Gui();
c.setVisible(true);
}
I want it so every time a button is pressed in my 4x4 grid, that it increments moves by 1 . This is creating a 4x4 layout of buttons. Each time any of those buttons are pressed, I want moves to increment. Basically I'm creating the memory game, where you flip cards over to match each other. I just have to keep count of the total amount of moves a player does to solve the puzzle.
private int moves = 0;
private GridPane makeGridPane(){
ConcentrationModel c = new ConcentrationModel();
GridPane grid = new GridPane();
ColumnConstraints col1 = new ColumnConstraints();
col1.setPercentWidth( 50 );
grid.getColumnConstraints().addAll(col1, col1, col1, col1);
RowConstraints row1 = new RowConstraints();
row1.setPercentHeight( 50 );
grid.getRowConstraints().addAll(row1, row1, row1, row1);
for(int row = 0; row < 4; row ++){
for(int col = 0; col < 4; col++){
Button btn = new Button();
ImageView image = new ImageView(c.getCards().get(0).getImage());
image.setFitWidth(WIDTH/4);
image.setFitHeight(HEIGHT/4);
btn.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
btn.setGraphic(image);
grid.add(btn, col, row);
}
}
return grid;
}
You can create a single event handler and reuse it for all the buttons. Since you probably want the buttons to do other things too, I would recommend adding this as an event handler, instead of using the convenience method setOnAction(...):
EventHandler<ActionEvent> incrementMovesHandler = e -> moves++ ;
for(int row = 0; row < 4; row ++){
for(int col = 0; col < 4; col++){
Button btn = new Button();
btn.addEventHandler(ActionEvent.ACTION, incrementMovesHandler);
// ...
}
}
This is actually pretty simple. All you have to do is add this bit of code just before your grid.add(...):
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
moves++;
}
});
Or, equivalently, the Java 8 version:
btn.setOnAction((ActionEvent e) -> {moves++;});
(I can't currently test this, but it should work. If not, lemme know and I'll try to fix it.)
If you're concerned about memory, Christian points out below that this creates a new instance of EventHandler for every button. While this may not be too terrible, it's probably a bad habit to get into. The best way to handle (no pun intended) this is by making an object before your for loop:
EventHandler<ActionEvent> eh = new EventHandler<>() {
#Override public void handle(ActionEvent event) {
moves++;
}
};
Then, for each of your buttons, instead of the top-most code, you'd simply write:
btn.setOnAction(eh);
That way, a single EventHandler is being created and used to handle all the events. You'll want to use this one if you need to create more than just a few buttons, both because it's faster (doesn't need to allocate memory for each object) and more memory-efficient (...it, uh, doesn't need to allocate the memory for each object). In this case, I think it's pretty trivial, but it's good to know nonetheless.
You need to implement the ActionListener interface in your class.
Then in the actionPerformed function, just increment the moves variable.
You just have to call btn.addActionListener(this); for each of the button that
you created.
public class Sample extends JFrame implements ActionListener {
public Sample ()
{
}
private GridPane makeGridPane()
{
ConcentrationModel c = new ConcentrationModel();
GridPane grid = new GridPane();
ColumnConstraints col1 = new ColumnConstraints();
col1.setPercentWidth( 50 );
grid.getColumnConstraints().addAll(col1, col1, col1, col1);
RowConstraints row1 = new RowConstraints();
row1.setPercentHeight( 50 );
grid.getRowConstraints().addAll(row1, row1, row1, row1);
for(int row = 0; row < 4; row ++){
for(int col = 0; col < 4; col++){
Button btn = new Button();
ImageView image = new ImageView(c.getCards().get(0).getImage());
image.setFitWidth(WIDTH/4);
image.setFitHeight(HEIGHT/4);
btn.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
btn.setGraphic(image);
btn.addActionListener(this);
grid.add(btn, col, row);
}
}
return grid;
}
public void actionPerformed(ActionEvent e)
{
moves++;
}
}
I want to make a grid with a specific amount of buttons.
I know how many buttons there are need to be because I get the number of rows and columns.
I could do a loop, but I don't know how you can place buttons next to eachother and underneath.
Secondly, the buttons need a Text and an Id, text is no problem, but how do you give them an id?
And at last, and probably most difficult, it can occur that there are a lot of rows, so that a scrollbar should be available.
At the end it should look something like this:
#Override
public void start(Stage stage) {
GridPane grid = new GridPane();
grid.setPadding(new Insets(BUTTON_PADDING));
grid.setHgap(BUTTON_PADDING);
grid.setVgap(BUTTON_PADDING);
for (int r = 0; r < NUM_BUTTON_LINES; r++) {
for (int c = 0; c < BUTTONS_PER_LINE; c++) {
int number = NUM_BUTTON_LINES * r + c;
Button button = new Button(String.valueOf(number));
grid.add(button, c, r);
}
}
ScrollPane scrollPane = new ScrollPane(grid);
stage.setScene(new Scene(scrollPane));
stage.show();
}
The best solution would be:
itemNumber starts from 0 to N:
Grid.getChildren().get(itemNumber).setId("bt"+itemNumber);
Grid.getChildren().get(itemNumber).getId();
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
So I created a little snake game.
In my constructor I call the "CreateSnake" function, which creates a Snake with JButtons.
private void createSnake()
{
snakeButtonx[0] = 100; //Sets the starter position of the snake
snakeButtony[0] = 150;
JButton tempButton; //temporary Button for adding button to the Snake
// Initially the snake has length of 5
for (int i = 0; i < sizeSnake; i++)
{
snakeButton[i] = new JButton("" + i);
snakeButton[i].setEnabled(false); // Disable the buttons so you cant click it
tempButton = snakeButton[i];
Surface.addSnake(tempButton, i);
snakeButton[i].setBounds(snakeButtonx[i], snakeButtony[i], 10, 10);
snakeButtonx[i + 1] = snakeButtonx[i] - 10;
snakeButtony[i + 1] = snakeButtony[i];
}
}
Then I have a move function, which is called every 100 milliseconds via a thread
#SuppressWarnings("deprecation")
private void move()
{
snakeButtonx[0] += directionx; //Set the position of the head of the snake
snakeButtony[0] += directiony;
for (int i = 0; i < sizeSnake; i++)
{
snakeButtonPos[i] = snakeButton[i].getLocation(); //Fills the snakeButtonPos integer with the positions of every Button
}
snakeButton[0].setBounds(snakeButtonx[0], snakeButtony[0], 10, 10);
for (int i = 1; i < sizeSnake; i++)
{
snakeButton[i].setLocation(snakeButtonPos[i - 1]);
}
show();
}
So. Till here, it works fine. But whenever I want to add a sixth JButton to my JButton array, I get a nullpointer exception in my move methode.
private void Grow()
{
JButton tempButton = new JButton();
int newIndex = sizeSnake + 1;
// Add the new Button to the Button Array
snakeButton[newIndex] = new JButton();
snakeButton[newIndex].setEnabled(false);
tempButton = snakeButton[newIndex];
Surface.addSnake(tempButton, newIndex);
// Position is irrelevant, cause the position will be fixed at the next call of move()
snakeButton[newIndex].setBounds(200, 300, 10, 10);
sizeSnake = sizeSnake + 1;
}
The sixth JButton is in the Jbutton array while Im in my Grow() function. But by the next call of move(), there isnt a JButton with the index 6 anymore.
Why do I get a NullPointerException? Where is the mistake?
EDIT: The error occurs on this line after the sixth loop in my move() function: snakeButtonPos[i] = snakeButton[i].getLocation();
And the exact exception:
Exception in thread "Thread-2" java.lang.NullPointerException
at Snake.move(Snake.java:92)
at Snake.run(Snake.java:217)
at java.lang.Thread.run(Unknown Source)
EDIT2: I call move and Grow here in my Thread
#Override
public void run() {
while (true)
{
CheckPosition(); //CheckPosition includes Grow() if the snake intersects with an object
move();
try
{
Thread.sleep(100);
}
catch (InterruptedException ie)
{
System.out.println(ie);
}
}
}
In Grow(), try changing int newIndex = sizeSnake + 1; to int newIndex = sizeSnake;. Since your for loops all go until i < sizeSnake, that means the last JButton is actually the one at snakeButton[sizeSnake - 1], not the one at snakeButton[sizeSnake].
Since some code is missing, a shot in the dark:
private void Grow()
{
JButton tempButton = new JButton();
int newIndex = sizeSnake + 1;
// Add the new Button to the Button Array
snakeButton[newIndex] = new JButton();
snakeButton[newIndex].setEnabled(false);
...
}
Say sizeSnake is 5, then newIndex is set to 6, so your snakeButton array looks like this afterwards:
[button, button, button, button, button, null, button, null, ...]
Because index 6 is the seventh element. The newIndex is unnecessary.
The move() method should be
private void Grow()
{
JButton tempButton = new JButton();
// Add the new Button to the Button Array
snakeButton[sizeSnake] = new JButton();
snakeButton[sizeSnake].setEnabled(false);
tempButton = snakeButton[sizeSnake];
Surface.addSnake(tempButton, sizeSnake);
// Position is irrelevant, cause the position will be fixed at the next call of move()
snakeButton[sizeSnake].setBounds(200, 300, 10, 10);
sizeSnake = sizeSnake + 1;
}
I'm in the process of creating a frogger type game and have gotten pretty far in getting the program to do what I want it to do. However, I'm starting to think that to finish the game I will have to use way to much code and there must be a simpler way achieve the same results. I'm not looking for an answer, just need some more information.
Question 1: What can I use for the images that represent the moving Icons or cars? I'm currently using JButtons. The problem is that is difficult to get the buttons to move uniformly and I want to use 24 different moving Icons and from what I've learned so far I will have to add a new JButton for each icon.
Question 2: The way that I've gotten the Jbutton icons to move is to use a timer delay and then a counter to increment the x values. This works for the most part, but is there a better, perhaps simpler, way to move icons across the screen?
Any tips, tutorials etc are greatly appreciated.
Here is one of the classes that I've created to get movement of the icons:
public class EnemyJPanel extends JButton {
JButton enem = new JButton();
JButton enem12 = new JButton();
JButton enem13 = new JButton();
JButton enem1 = new JButton("1");
JButton enem2 = new JButton("2");
JButton enem3 = new JButton("3");
JButton enem4 = new JButton("4");
JButton score = new JButton("Score");
JButton enem5 = new JButton("5");
JButton enem6 = new JButton("6");
JButton enem7 = new JButton("7");
JButton enem8 = new JButton("8");
JButton yard = new JButton("50 Yard Line");
int i = 16;
int u = 576;
int d = 16;
int n = 576;
int k = 16;
int l = 16;
int dummyval = 16;
public EnemyJPanel(){
super();
setLayout(null);
enem1.setBounds(16,300,40,55);
enem2.setBounds(16,245,40,55);
enem3.setBounds(16,190,40,55);
enem4.setBounds(16,135,40,55);
score.setBounds(16,80,601,55);
yard.setBounds(16,355,601,55);
enem5.setBounds(16,410,40,55);
enem6.setBounds(16,465,40,55);
enem7.setBounds(16,520,40,55);
enem8.setBounds(16,575,40,55);
enem12.setBounds(16,300,40,55);
enem13.setBounds(16,300,40,55);
add(enem1);
add(enem2);
add(enem3);
add(enem4);
add(score);
}
public void addEnemy(){
enem1.setBounds(16,300,40,55);
enem2.setBounds(16,245,40,55);
enem3.setBounds(16,190,40,55);
enem4.setBounds(16,135,40,55);
score.setBounds(16,80,601,55);
add(enem1);
add(enem2);
add(enem3);
add(enem4);
add(score);
}
public void enemyMovement(){
i++;u--;d++;n--; // increments lateral movement from a timer in
dummyval++; // the dummy value is needed to keep the icons looping
dummyval = dummyval + 2;
enem1.setBounds(i,300,40,55);
i = i + 2;
if (dummyval > 176){
k++; k = k + 2;
enem12.setBounds(k,300,40,55);
}
if (k > 176){
l++;
l = l + 2;
enem13.setBounds(l,300,40,55);
}
enem2.setBounds(u,245,40,55);
enem3.setBounds(d,190,40,55);
enem4.setBounds(n,135,40,55);
enem5.setBounds(i,410,40,55);
enem6.setBounds(u,465,40,55);
enem7.setBounds(d,520,40,55);
enem8.setBounds(n,575,40,55);
if(i > 576){ // resets button
i = 16;
}
if(k > 576){
k = 16;
}
if(u < 16){
u = 576;
}
u = u - 2; // increase lateral speed
if(d == 576) {
d = 16;
}
if(n < 16){
n = 576;
}
n = n - 5; //increases lateral speed
}
}
The problem is created because you try to manage all the "stuff" separately. It looks like you may be missing some basic information on classes
First, I would create a custom class, something like
class ButtonObject extends JButton
{
public ButtonObject(String text, int x, int y, int width, int height)
{
super(text);
this.setBounds(x, y, width, height);
}
}
You also may want to take a look at arrays and create an array of your new ButtonObject.
The for loop will help you get through all the objects in your array.
ButtonObject[] enemies = new ButtonObject[10];
for (int i = 0; i < 10; i++)
{
String text = String.valueOf(i);
int y = 300 - (i * 55);
enemies[i] = new ButtonObject(text, 16, y, 40, 55);
}
There is probably a better way to do it than buttons but you may want to stick with them for now for simplicity.