Creating TicTacToe in javafx - javafx

I am writing a TicTacToe program that displays a tic-tac-toe board that has the following qualities:
A cell may be X, O, or empty.
What to display at each cell is randomly decided upon startup of program.
Input the X's and O's as text instead of images.
In my program, I have the X's and O's as .gif files. I was wondering how the code would look when placing the X's and O's as text instead of images? Thanks in advance!
here is my code:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.text.Text;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class TicTacToe extends Application {
#Override
public void start(Stage primaryStage) {
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int random = (int)(Math.random() * 3);
if (random != 2) {
String text = (random > 0) ? "/image/x.gif" : "/image/o.gif";
pane.add(new ImageView(new Image(image)), j, i);
}
}
}
Scene scene = new Scene(pane, 150, 150);
primaryStage.setTitle("Tic Tac Toe");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
// Create a scene and place it in the stage
Scene scene = new Scene(pane);
primaryStage.setTitle("TicTacToe"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
public static void main(String[] args) {
launch(args);
}
}

Replace "/image/x.gif" with "X" and "/image/o.gif" with "O" and instead of using an ImageView, use a Label and set the text of the label to the text variable then add it to your Pane

Related

Why the program gets the error in JavaFX? [duplicate]

This question already has an answer here:
How do I determine the correct path for FXML files, CSS files, Images, and other resources needed by my JavaFX Application?
(1 answer)
Closed 2 years ago.
I have spent the last 3 days trying to find an answer, watching videos and forum posts but no luck. Please take a look in those 4 pics. It seems that it only does it when the problem has image files.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.scene.image.ImageView;
import javafx.scene.image.Image;
public class Exercise14_02 extends Application {
#Override
public void start(Stage primaryStage) {
Image imageX = new Image("image/x.gif");
Image imageO = new Image("image/o.gif");
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setHgap(5);
pane.setVgap(5);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int status = (int)(Math.random() * 3);
if (status == 0) {
pane.add(new ImageView(imageX), j, i);
} else if (status == 1) {
pane.add(new ImageView(imageO), j, i);
}
}
}
// Create a scene and place it in the stage
Scene scene = new Scene(pane);
primaryStage.setTitle("Exercise14_02"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
public static void main(String[] args) {
launch(args);
}
}
try moving your images to 'resources' folder, create one if needed.
Image imagex = new Image(getClass().getResourceAsStream("/resources/your_image.jpg"));
or
check if you have included your resources folder in project.

JavaFX Alert with multiple colors

I have a program that at some point (may) displays two warnings - one about errors - those are in red, and one about warnings - those are in orange.
I wonder however if there is a way - using css - to have just one warning with some text red and some text orange.
Here is an example of what I want to achieve (the two can be separated into "sections"):
RED ERROR1
RED ERROR2
RED ERROR3
ORANGE WARNING1
ORANGE WARNING2
I've seen some answers pointing to RichTextFX like this one, however I don't see (or don't know) how that could apply to generic Alerts. Is that even possible, without writing some custom ExpandedAlert class?
The Alert class inherits from Dialog, which provides a pretty rich API and allows arbitrarily complex scene graphs to be set via the content property.
If you just want static text with different colors, the simplest approach is probably to add labels to a VBox; though you could also use more complex structures such as TextFlow or the third-party RichTextFX mentioned in the question if you need.
A simple example is:
import java.util.Random;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class App extends Application {
private final Random rng = new Random();
private void showErrorAlert(Stage stage) {
Alert alert = new Alert(Alert.AlertType.ERROR);
int numErrors = 2 + rng.nextInt(3);
int numWarnings = 2 + rng.nextInt(3);
VBox errorList = new VBox();
for (int i = 1 ; i <= numErrors ; i++) {
Label label = new Label("Error "+i);
label.setStyle("-fx-text-fill: red; ");
errorList.getChildren().add(label);
}
for (int i = 1 ; i <= numWarnings ; i++) {
Label label = new Label("Warning "+i);
label.setStyle("-fx-text-fill: orange; ");
errorList.getChildren().add(label);
}
alert.getDialogPane().setContent(errorList);
alert.initOwner(stage);
alert.show();
}
#Override
public void start(Stage stage) {
Button showErrors = new Button("Show Errors");
showErrors.setOnAction(e -> showErrorAlert(stage));
BorderPane root = new BorderPane(showErrors);
Scene scene = new Scene(root, 400, 400);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
which gives this result:

Can't get images to show up, trying to display 5 random cards from directory file

I'm not sure what I'm doing wrong. My pane opens, but it is blank. I have the file (card) as a directory (image) in the src folder. I have tried writing this so many different way but always get the same result. I just need to make the images actually show up. I don't know how to get the card images to show up. Any help is greatly appreciated.
package Assignment;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Collections;
public class Assignment extends Application {
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Initialize card deck
ArrayList<Integer> cards = getCards();
// Create a FlowPane
FlowPane pane = new FlowPane();
pane.setVgap(10);
pane.setHgap(10);
pane.setPadding(new Insets(15, 15, 15, 15));
for (int i = 0; i < 5; i++) {
pane.getChildren().add(new ImageView(new Image("file:image/card/" + cards.get(i) + ".png")));
}
// Create scene and place it in the stage
Scene scene = new Scene(pane,500, 300);
primaryStage.setTitle("Poker 1");
primaryStage.setScene(scene);
primaryStage.show();
}
private ArrayList<Integer> getCards() {
ArrayList<Integer> cards = new ArrayList<>();
for (int i = 0; i < 52; i++) {
cards.add(i + 1);
}
Collections.shuffle(cards);
return cards;
}
public static void main(String[] args) {
launch(args);
}
}
What directory are your cards images in?
Click 'edit configuration' on the run button drop down menu, then look at the "Working directory" entry. Ex. Mine was C:\Users\NAME\IdeaProjects\Test
Placing the cards in C:\Users\NAME\IdeaProjects\Test\image\cards[1-52].png made your code work for me as written.

Draw Arrows over Nodes

I want to draw arrows in a group over my grid view. The example works fine with 3x3 grid. But if I change this size to e.g. 4x4 these arrows are on the wrong place.
I colorized the source field (green) and the destination field (red) to make sure I target the right cells. The program clears the arrowGroup and draws two arrows every 3s.
import eu.lestard.grid.GridModel;
import eu.lestard.grid.GridView;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import static javafx.scene.paint.Color.RED;
public class App extends Application {
private GridView<States> gridView;
private StackPane stackPane;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane borderPane = new BorderPane();
stackPane = new StackPane();
borderPane.setCenter(stackPane);
Group arrowGroup = new Group();
GridModel<States> gridModel = new GridModel<>();
gridModel.setDefaultState(States.EMPTY);
gridModel.setNumberOfColumns(3);
gridModel.setNumberOfRows(3);
gridView = new GridView<>();
gridView.setGridModel(gridModel);
stackPane.getChildren().add(gridView);
stackPane.getChildren().add(arrowGroup);
final Scene scene = new Scene(borderPane, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
new Thread(() -> {
for (int i = 1; i <= 1000000; i++) {
Platform.runLater( () -> {
arrowGroup.getChildren().clear();
drawArrow(arrowGroup, new Point2D(0,0), new Point2D(2,1));
drawArrow(arrowGroup, new Point2D(1,1), new Point2D(0,2));
});
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
}).start();
}
// getRelativeBounds, getCenter based on https://stackoverflow.com/a/43119383/772883
private void drawArrow(Group group, Point2D from, Point2D to) {
final Line line = new Line();
System.out.println(String.format("Draw arrow from cell %s to %s", from, to));
System.out.println(String.format("group coord %s %s", group.getLayoutX(), group.getLayoutY()));
// Note: (X,Y) -> (Column, Row) => access via (Y,X)
final Pane cellPane = gridView.getCellPane(gridView.getGridModel().getCell(((int) from.getY()), (int) from.getX() ));
final Pane cellPane2 = gridView.getCellPane(gridView.getGridModel().getCell((int) to.getY() , (int) to.getX()));
cellPane.setBackground(new Background(new BackgroundFill(Color.DARKGREEN, CornerRadii.EMPTY, Insets.EMPTY)));
cellPane2.setBackground(new Background(new BackgroundFill(RED, CornerRadii.EMPTY, Insets.EMPTY)));
Bounds n1InCommonAncestor = getRelativeBounds(cellPane, gridView);
Bounds n2InCommonAncestor = getRelativeBounds(cellPane2, gridView);
Point2D n1Center = getCenter(n1InCommonAncestor);
Point2D n2Center = getCenter(n2InCommonAncestor);
System.out.println(String.format("Draw arrow from coord %s to %s", n1Center, n2Center));
System.out.println(n1Center);
System.out.println(n2Center);
line.setStartX(n1Center.getX());
line.setStartY(n1Center.getY());
line.setEndX(n2Center.getX());
line.setEndY(n2Center.getY());
group.getChildren().add(line);
}
private Bounds getRelativeBounds(Node node, Node relativeTo) {
Bounds nodeBoundsInScene = node.localToScene(node.getBoundsInLocal());
return relativeTo.sceneToLocal(nodeBoundsInScene);
}
private Point2D getCenter(Bounds b) {
return new Point2D(b.getMinX() + b.getWidth() / 2, b.getMinY() + b.getHeight() / 2);
}
public static enum States {
EMPTY,
X,
O
}
}
(If have replaced the arrows with lines to reduce the code.)
There is a gist withe the code and a gradle buildfile:
https://gist.github.com/anonymous/c54b12ee04b7e45f2e9f58e9de1d1df0
It would be great if somebody could explain why does only work with 3x3. Is there any better option than a group?

How do I use a button in JavaFX to change the size of a line

I want to change the size of a line using a button so later I can make the line look like it is rotating... Here is the code I have so far:
package JavaFXApplication14;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class JavaFXApplication14 extends Application
{
public static void main(String[] args)
{
launch(args);
}
int x = 200;
#Override public void start(Stage primaryStage) throws Exception
{
final GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(100);
grid.setVgap(100);
grid.setPadding(new Insets(10, 10, 10, 10));
Scene scene = new Scene(grid, 600, 400); //Color.BLACK ?
primaryStage.setScene(scene);
primaryStage.setTitle("4D");
primaryStage.show();
Line ln = new Line(100, 200, x, 200);
ln.setStroke(Color.BLUE);
ln.setStrokeWidth(5);
grid.add(ln, 0, 0);
Button btn = new Button("X-Y");
grid.setHalignment(btn, HPos.CENTER);
btn.setOnAction(e -> btn_Click());
grid.add(btn, 0, 1);
}
public void btn_Click()
{
x = x + 50;
}
}
Also, sometimes when I use the following line of code the color of the background does not change.
Scene scene = new Scene(grid, 600, 400, Color.BLACK);
What is the reason for that?
The button works very well you can test it, but here you only set a new value to x and nothing else, in other words you don't update the position x2 of your Line.You can dot that by making your variable ln accessible and updating its value EndX:
//before the method start
Line ln;
//Inside your btn_click() method add
ln.setEndX(x);
But it will only increase the size of your line (Horizontally) and not rotate it. with a little research explained here and following what I told you in the comment you can do this easily based on the axis of rotation (startX & startY) and the points to be rotated (endX & endY):
public class Launcher extends Application{
private Pane root = new Pane();
private Scene scene;
private Button btn = new Button("Test");
private Line line;
#Override
public void start(Stage stage) throws Exception {
line = new Line(200,200,200,100);
line.setStroke(Color.BLACK);
line.setStrokeWidth(5);
btn.setOnAction(e -> rotate());
root.getChildren().addAll(btn,line);
scene = new Scene(root,500,500);
stage.setScene(scene);
stage.show();
}
private void rotate(){
double x1 = line.getEndX() - line.getStartX();
double y1 = line.getEndY() - line.getStartY();
//The more you reduce the angle the longer the rotation
double x2 = x1 * Math.cos(0.1) - y1 * Math.sin(0.1);
double y2 = x1 * Math.sin(0.1) + y1 * Math.cos(0.1);
line.setEndX(x2+ line.getStartX());
line.setEndY(y2+ line.getStartY());
}
public static void main(String[] args) {
launch(args);
}
}
Note: In your example you use a GridPane, so you will be restricted to its functioning, Good luck !

Resources