Issue
I am building a Calculator. I have created a few classes so far. There is the IntegerButton which should display it's value on the Monitor when pressed.
package calculator.buttons;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
public class IntegerButton extends Button{
int value;
public IntegerButton(int value) {
this.value = value;
this.setText(Integer.toString(value));
this.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
// Handle the event as an integer
// send event to monitor?
}
});
}
}
However, I do not understand how to do this.
I am unable to reference the Monitor when I define handle(ActionEvent event) within the constructor of each button. In addition, I am completely lost with the concept of EventHandlers. Should my Monitor listen to events? Should my Button have its setOnAction called within the start(Stage primaryStage) method? I am at a total loss.
Here is my application's start method: package calculator;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import javafx.stage.Stage;
/**
*
* @author souten
*/
public class Calculator extends Application {
public static final double MIN_HEIGHT = 525;
public static final double MIN_WIDTH = 350;
public static final double DEFAULT_GAP = 6;
@Override
public void start(Stage primaryStage) {
// Window settings
primaryStage.setTitle("Calculator");
primaryStage.setMinHeight(MIN_HEIGHT);
primaryStage.setMinWidth(MIN_WIDTH);
// container is the base content node
// - it contains 1 column and 3 rows
GridPane container = new GridPane();
container.setAlignment(Pos.CENTER);
ColumnConstraints column1 = new ColumnConstraints();
column1.setPercentWidth(100);
container.getColumnConstraints().add(column1);
RowConstraints[] rows = new RowConstraints[3];
for (int i = 0; i < rows.length; i++)
rows[i] = new RowConstraints();
rows[0].setPercentHeight(40);
rows[1].setPercentHeight(10);
rows[2].setPercentHeight(50);
container.getRowConstraints().addAll(rows);
container.setHgap(0);
container.setVgap(DEFAULT_GAP);
// row 0: the monitor, outputs the calculations in hex, dec, oct, and bin
Monitor m = new Monitor();
container.add(m, 0, 0);
// row 1: contains misc buttons i.e. bit-toggler, bit measurement, and memory buttons
// row 2: the bottom row, keypadContainer contains all the buttons that create the calculation/function
Keypad keypad = new Keypad();
container.add(keypad, 0, 2);
// Scene initialization
Scene scene = new Scene(container, MIN_WIDTH, MIN_HEIGHT);
primaryStage.setScene(scene);
scene.getStylesheets().add
(Calculator.class.getResource("Calculator.css").toExternalForm());
primaryStage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Keypad class:
package calculator;
import calculator.buttons.IntegerButton;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
public class Keypad extends GridPane{
String[][] labels = {
{"Lsh", "Rsh", "Or", "Xor", "Not", "And"},
{"↑", "Mod", "CE", "C", "⌫", "÷"},
{"A", "B", "7", "8", "9", "×"},
{"C", "D", "4", "5", "6", "−"},
{"E", "F", "1", "2", "3", "+"},
{"(", ")", "±", "0", ".", "="}
};
Button[][] buttons = new Button[6][6];
public Keypad(){
// initialize buttons
buttons[5][3] = new IntegerButton(0);
buttons[4][2] = new IntegerButton(1);
buttons[4][3] = new IntegerButton(2);
buttons[4][4] = new IntegerButton(3);
buttons[3][2] = new IntegerButton(4);
buttons[3][3] = new IntegerButton(5);
buttons[3][4] = new IntegerButton(6);
buttons[2][2] = new IntegerButton(7);
buttons[2][3] = new IntegerButton(8);
buttons[2][4] = new IntegerButton(9);
for (int i = 0; i < 6; i++){
for (int j = 0; j < 6; j++) {
if(buttons[i][j] != null)
this.add(buttons[i][j], j, i);
}
}
}
}
and my Monitor Class:
package calculator;
import javafx.scene.text.Text;
public class Monitor extends Text {
public Monitor() {
this.setText("Hello World!");
// this.addListener?
}
}
Basically I have a fundamental misunderstanding of how to connect these nodes via events. How do?
Solution
Here's a very basic example that illustrates how a Button event would work in the context your trying to use it.
public class SimpleButtonApp extends Application {
@Override
public void start(Stage stage) throws Exception {
GridPane container = new GridPane();
Label displayLabel = new Label();
String[][] labels = {
{"Lsh", "Rsh", "Or", "Xor", "Not", "And"},
{"↑", "Mod", "CE", "C", "⌫", "÷"},
{"A", "B", "7", "8", "9", "×"},
{"C", "D", "4", "5", "6", "−"},
{"E", "F", "1", "2", "3", "+"},
{"(", ")", "±", "0", ".", "="}};
for(int i = 0; i < labels.length; i++) {
for(int j = 0; j < labels[i].length; j++) {
String label = labels[i][j];
Button button = new Button(label);
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
displayLabel.setText(displayLabel.getText() + label);
}
});
container.add(button, i, j);
}
}
container.getChildren().addAll(button, displayLabel);
Scene scene = new Scene(container, 300, 100);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Some design hints for making a calculator:
1) A basic JavaFX Label should work for displaying the numbers
2) You don't need an IntegerButton class. A button is just a button.
3) Your event handlers should be defined in a place where you have access to both the Buttons and the Label.
Answered By - Steve
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)