Reputation: 19
I am currently working on this assignment and I can not seem to get this program to run even though I don't have any errors really popping up ? I am trying to add a time stamp to the pane as well but every time I add the "ts" name for the time stamp to the Pane or Hbox's get children code it goes red.. I am not sure what exactly I'm doing wrong if anyone can point me in the right direction id greatly appreciate it...
package PCK1;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import java.sql.Timestamp;
import java.util.Date;
import java.text.SimpleDateFormat;
public class MainClass
{
public static void start(Stage stage)
{
// Time Stamp
Date date = new Date();
Timestamp ts=new Timestamp(date.getTime());
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(formatter.format(ts));
//Create a Circle
Circle c1 = new Circle(75,100,20);
//Create a Pane
Pane p = new Pane();
p.setMinSize(100, 150);
p.setBackground(new Background(new BackgroundFill( Color.rgb(190, 220, 190), null, null)
));
p.getChildren().addAll(c1);
//Create a Button
Button btnUp = new Button("Up");
btnUp.setOnAction((ActionEvent e) -> {double y = c1.getCenterY();
y -= 20.0;
c1.setCenterY(y);
});
Button btnDown = new Button("Down");
btnDown.setOnAction((ActionEvent e) -> {double y = c1.getCenterY();
y += 20.0;
c1.setCenterY(y);
});
//Create a HBox
HBox hb = new HBox();
hb.getChildren().addAll(btnUp, btnDown, p, ts);
hb.setBackground(new Background(new BackgroundFill(Color.rgb(150,200,150),null,null)));
hb.setMinSize(100, 50);
hb.setPadding(new Insets(10,10,10,10));
Scene scene = new Scene(hb);
stage.setScene(scene);
stage.setTitle("JavaFx");
stage.setWidth(250);
stage.setHeight(250);
stage.show();
}
}
Upvotes: 1
Views: 910
Reputation: 159416
Specifically, for the timestamp question, see the following example code:
private Label createTimestampLabel() {
LocalDateTime now = LocalDateTime.now();
String formattedTimestamp = now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
return new Label(formattedTimestamp);
}
It uses the java.time APIs explained in the Oracle Date Time tutorial to get the current time from LocalDateTime and format it as a String using a standard format.
It sets the formatted timestamp string as the text of a Label node.
Now that the returned element is a Node, it can be placed in the scene graph without generating the compile error you saw in your original example.
Using the java.time
APIs is preferred over the java.sql.Timestamp
and java.util.Date
code in your question. You are not working with SQL, so you should not be using java.sql.Timestamp
. The java.time
classes also have many improvements over obsolete date and time functions used in other Java packages like java.util
.
There were a lot of things about the provided example application that were either wrong or annoyed me.
So I re-wrote it to match a bit more closely how I would normally write such an application.
There are maybe a hundred different small decisions made in the choices for how to implement the re-write and explaining them all here would be too verbose.
Hopefully, you can compare the re-write to your original code, note some of the differences, and learn some things from it.
GraphicControlApp.java
package org.example.javafx.demo.graphiccontrol;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class GraphicControlApp extends Application {
public void start(Stage stage) {
GraphicController graphicController = new GraphicController();
Scene scene = new Scene(graphicController.getUI());
stage.setScene(scene);
stage.setTitle("JavaFX Interactive Graphic Control Demonstration");
stage.show();
}
}
GraphicController.java
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* UI creator and controller for application logic.
*
* Normally, most UI elements would be defined externally in FXML,
* however, for a simple application, we define the UI via private functions in this class.
*/
public class GraphicController {
// amount to move the circle across the surface on interaction.
private static final double MOVEMENT_DELTA = 20.0;
// default spacing between UI elements.
private static final double SPACING = 10;
// normally the styles would be configured in an external css stylesheet,
// but we place the background definitions here for a simple application.
private static final Color SURFACE_COLOR = Color.rgb(190, 220, 190);
private static final Background surfaceBackground = createBackground(SURFACE_COLOR);
private static final Color APP_BACKGROUND_COLOR = Color.rgb(150, 200, 150);
private static final Background appBackground = createBackground(APP_BACKGROUND_COLOR);
private Button up;
private Button down;
/**
* @return the complete layout for the application with event handlers attached for logic control.
*/
public Pane getUI() {
Circle circle = new Circle(75, 100, 20);
Pane surface = createSurface(circle);
HBox controls = createControls(circle);
Label timestampLabel = createTimestampLabel();
Pane layout = createLayout(surface, controls, timestampLabel);
attachKeyboardHandlers(layout);
return layout;
}
/**
* Create a label formatted with the current time in ISO standard format (e.g. '2011-12-03T10:15:30')
*
* @return label with the current timestamp.
*/
private Label createTimestampLabel() {
LocalDateTime now = LocalDateTime.now();
String formattedTimestamp = now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
return new Label(formattedTimestamp);
}
/**
* Create a surface on which a circle can move.
*
* @param circle the circle which can move on the surface.
* @return the created surface.
*/
private Pane createSurface(Circle circle) {
Pane surface = new Pane();
surface.setMinSize(100, 150);
surface.setBackground(surfaceBackground);
surface.getChildren().addAll(circle);
// we must define a clip on the surface to ensure that elements
// in the surface do not render outside the surface.
Rectangle clip = new Rectangle();
clip.widthProperty().bind(surface.widthProperty());
clip.heightProperty().bind(surface.heightProperty());
surface.setClip(clip);
return surface;
}
private VBox createLayout(Pane surface, HBox controls, Label timestampLabel) {
VBox layout = new VBox(SPACING, controls, surface, timestampLabel);
layout.setBackground(appBackground);
layout.setPadding(new Insets(SPACING));
VBox.setVgrow(surface, Priority.ALWAYS);
return layout;
}
/**
* Create controls which can control the movement of a circle.
*
* @param circle the circle which can be controlled
* @return the created controls with handlers attached for circle movement control.
*/
private HBox createControls(Circle circle) {
up = new Button("Up");
up.setOnAction(e -> moveVertically(circle, -MOVEMENT_DELTA));
down = new Button("Down");
down.setOnAction(e -> moveVertically(circle, MOVEMENT_DELTA));
return new HBox(SPACING, up, down);
}
private void moveVertically(Circle circle, double delta) {
double y = circle.getCenterY();
// we only restrict movement in the up direction,
// but allow unlimited movement in the down direction
// (even if that movement would mean that the circle would extend totally
// outside the current visible boundary of the surface).
if ((y + delta) < 0) {
return;
}
circle.setCenterY(y + delta);
}
/**
* Adds standard keyboard handling logic to the UI.
*
* Handlers are attached to the relevant scene whenever
* the scene containing the UI changes.
*
* @param layout the UI which will respond to keyboard input.
*/
private void attachKeyboardHandlers(Pane layout) {
EventHandler<KeyEvent> keyEventHandler = event -> {
switch (event.getCode()) {
case UP -> { up.requestFocus(); up.fire(); }
case DOWN -> { down.requestFocus(); down.fire(); }
}
};
layout.sceneProperty().addListener((observable, oldScene, newScene) -> {
if (oldScene != null) {
oldScene.removeEventFilter(
KeyEvent.KEY_PRESSED,
keyEventHandler
);
}
if (newScene != null) {
newScene.addEventFilter(
KeyEvent.KEY_PRESSED,
keyEventHandler
);
}
});
}
private static Background createBackground(Color surfaceColor) {
return new Background(new BackgroundFill(surfaceColor, null, null));
}
}
Upvotes: 2