I am making an alarm clock kind of program and I need a way to make the clock face a specific font. I have tried multiple times in multiple ways. If that is not possible can you please provide another solution? Thank you in advance!
import java.util.Calendar;
import java.util.GregorianCalendar;
import javax.print.DocFlavor.URL;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Menu extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
//Frame stuff (works)
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
//Frame Size
Scene scene = new Scene(new DigitalClock(),1080, 720);
//Icon
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream(("/lib/logo.png"))));
primaryStage.setTitle("Clock: 140 Edition");
//Necessities
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String args[]) {
launch(args);
}
}
class Util {
public static String pad(int fieldWidth, char padChar, String s) {
StringBuilder sb = new StringBuilder();
for (int i = s.length(); i < fieldWidth; i++) {
sb.append(padChar);
}
sb.append(s);
return sb.toString();
}
}
class DigitalClock extends Label {
public DigitalClock() {
bindToTime();
}
// the digital clock updates once a second.
private void bindToTime() {
Timeline timeline = new Timeline(
new KeyFrame(Duration.seconds(0),
new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent actionEvent) {
Calendar time = Calendar.getInstance();
String hourString = Util.pad(2, ' ', time.get(Calendar.HOUR) == 0 ? "12" : time.get(Calendar.HOUR) + "");
String minuteString = Util.pad(2, '0', time.get(Calendar.MINUTE) + "");
String secondString = Util.pad(2, '0', time.get(Calendar.SECOND) + "");
String ampmString = time.get(Calendar.AM_PM) == Calendar.AM ? "AM" : "PM";
setText(hourString + ":" + minuteString + ":" + secondString + " " + ampmString);
}
}
),
new KeyFrame(Duration.seconds(1))
);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
}
I also know some of the imports are not used, I would prefer to keep them. Thanks again!
🍒The Font has to do with the Label you are using in the example.
Must
read:http://www.guigarage.com/2014/10/integrate-custom-fonts-javafx-application-using-css/
<-----------------Ways to do----------------->
1)Using external css:
/*The font path*/
#font-face{
src: url("../fonts/Younger than me Bold.ttf");
}
/* An element which has this id*/
#LabelID{
-fx-font-family:"Younger than me";
-fx-font-size:18.0;
}
//or for all labels
.label{
-fx-font-family:"Younger than me";
-fx-font-size:18.0;
}
2)Using setStyle(...):
`label.setStyle("-fx-font-family:monospace; -fx-font-size:16px; -fx-text-fill:black; -fx-border-color:red;");`
3)Using setFont(...):
b.setFont(new Font("Arial", 24));
4)Tricky and not recommended ( not included in JavaFX docs) : here
Relative posts:
How to set custom fonts in JavaFX Scene Builder using CSS
https://blog.idrsolutions.com/2014/04/use-external-css-files-javafx/
Have a look at https://gist.github.com/jewelsea/2658491
Related
Does JavaFX have a binding type where i supply an observable map with a key and the computed value will always update as the key/value pair changes? Removing that key the key from the map will result to a null value, adding it back will track that value back.
I've been looking around the JavaDoc and found MapProperty, MapBinding and ObservableMapValue, but nothing seems to serve this purpose.
I've already designed my own variant, but would like to use a rather failsafe and tested version.
You can just do
someObjectProperty.bind(Bindings.createObjectBinding(
() -> myObservableMap.get(key), myObservableMap);
or, as #VGR points out in the comments
someObjectProperty.bind(Bindings.valueAt(someObservableMap, key));
Here is a SSCCE using the second approach:
import java.util.Arrays;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class BindToObservableMap extends Application {
private static final String[] keys = {"key1", "key2", "key3"};
#Override
public void start(Stage primaryStage) {
ObservableMap<String, String> map = FXCollections.observableHashMap();
for (String k : keys) map.put(k, k.replaceAll("key", "value"));
GridPane grid = new GridPane();
grid.setHgap(5);
grid.setVgap(5);
grid.setPadding(new Insets(10));
for (int i = 0 ; i < keys.length; i++) {
grid.add(new Label(keys[i]), 0, i);
Label boundLabel = new Label();
boundLabel.textProperty().bind(Bindings.valueAt(map, keys[i]));
grid.add(boundLabel, 1, i);
}
ComboBox<String> keyCombo = new ComboBox<>();
keyCombo.getItems().setAll(keys);
TextField valueField = new TextField();
Button update = new Button("Update");
EventHandler<ActionEvent> handler = e -> {
map.put(keyCombo.getValue(), valueField.getText());
valueField.clear();
keyCombo.requestFocus();
};
valueField.setOnAction(handler);
update.setOnAction(handler);
grid.addRow(keys.length, keyCombo, valueField);
grid.add(update, 0, keys.length + 1);
Scene scene = new Scene(grid);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Does JavaFX have a binding type where i supply an observable map with a key and the computed value will always update as the key/value pair changes? Removing that key the key from the map will result to a null value, adding it back will track that value back.
I've been looking around the JavaDoc and found MapProperty, MapBinding and ObservableMapValue, but nothing seems to serve this purpose.
I've already designed my own variant, but would like to use a rather failsafe and tested version.
You can just do
someObjectProperty.bind(Bindings.createObjectBinding(
() -> myObservableMap.get(key), myObservableMap);
or, as #VGR points out in the comments
someObjectProperty.bind(Bindings.valueAt(someObservableMap, key));
Here is a SSCCE using the second approach:
import java.util.Arrays;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class BindToObservableMap extends Application {
private static final String[] keys = {"key1", "key2", "key3"};
#Override
public void start(Stage primaryStage) {
ObservableMap<String, String> map = FXCollections.observableHashMap();
for (String k : keys) map.put(k, k.replaceAll("key", "value"));
GridPane grid = new GridPane();
grid.setHgap(5);
grid.setVgap(5);
grid.setPadding(new Insets(10));
for (int i = 0 ; i < keys.length; i++) {
grid.add(new Label(keys[i]), 0, i);
Label boundLabel = new Label();
boundLabel.textProperty().bind(Bindings.valueAt(map, keys[i]));
grid.add(boundLabel, 1, i);
}
ComboBox<String> keyCombo = new ComboBox<>();
keyCombo.getItems().setAll(keys);
TextField valueField = new TextField();
Button update = new Button("Update");
EventHandler<ActionEvent> handler = e -> {
map.put(keyCombo.getValue(), valueField.getText());
valueField.clear();
keyCombo.requestFocus();
};
valueField.setOnAction(handler);
update.setOnAction(handler);
grid.addRow(keys.length, keyCombo, valueField);
grid.add(update, 0, keys.length + 1);
Scene scene = new Scene(grid);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I have made a desktop clock app in java which uses a specific font (Digital Dream Fat) in order to achieve the desired look but if someone doesn't have the font installed on their computer, it will default with Arial. How would I compensate for that?
Here is my code:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.collections.FXCollections;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Tooltip;
import javafx.stage.StageStyle;
import javafx.scene.paint.Color;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import java.text.DateFormat;
import java.util.Date;
import java.text.SimpleDateFormat;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.util.Duration;
public class Clock extends Application {
public Text text;
#Override
public void start(Stage stage) {
DateFormat df = new SimpleDateFormat("EEE,MMM d yyyy - h:mm:ss a");
Date date = new Date();
String stringDate = df.format(date);
text = new Text(10, 60, stringDate);
text.setFont(Font.font ("Digital Dream Fat", 30f));
text.setFill(Color.RED);
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(0), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
Date update = new Date();
String stringNewDate = df.format(update);
text.setText(stringNewDate);
}
}), new KeyFrame(Duration.seconds(1)));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
ChoiceBox colorChoice = new ChoiceBox(FXCollections.observableArrayList("Red", "Blue", "Green", "Grey", "Black", "White"));
colorChoice.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent e) {
if (colorChoice.getSelectionModel().getSelectedItem().toString().equals("Red")) {
colorChoice.setStyle("-fx-base: red");
text.setFill(Color.RED);
} else if (colorChoice.getSelectionModel().getSelectedItem().toString().equals("Blue")) {
colorChoice.setStyle("-fx-base: blue");
text.setFill(Color.BLUE);
} else if (colorChoice.getSelectionModel().getSelectedItem().toString().equals("Green")) {
colorChoice.setStyle("-fx-base: green");
text.setFill(Color.GREEN);
} else if (colorChoice.getSelectionModel().getSelectedItem().toString().equals("Grey")) {
colorChoice.setStyle("-fx-base: grey");
text.setFill(Color.GREY);
} else if (colorChoice.getSelectionModel().getSelectedItem().toString().equals("White")) {
colorChoice.setStyle("-fx-base: white");
text.setFill(Color.WHITE);
} else if (colorChoice.getSelectionModel().getSelectedItem().toString().equals("Black")) {
colorChoice.setStyle("-fx-base: black");
text.setFill(Color.BLACK);
} else {
colorChoice.setStyle("-fx-base: red");
text.setFill(Color.RED);
}
}
});
HBox hbox = new HBox(colorChoice);
colorChoice.setTooltip(new Tooltip("Select A Colour"));
colorChoice.getSelectionModel().selectFirst();
Scene scene = new Scene(new Group(text, hbox));
scene.setFill(Color.TRANSPARENT);
stage.setScene(scene);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setX(0);
stage.setY(0);
stage.setWidth(710);
stage.setHeight(80);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I am working on a clock program in Java and I am unsure how to make the time update secondly. I have tried using a for loop with thread.sleep(1000); but that did not work. Also, if anybody knows how to stop the Stage from opening in white then having a small delay before turning black, that would be really appreciated.
Here is my code:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.scene.paint.Color;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import java.text.DateFormat;
import java.util.Date;
import java.text.SimpleDateFormat;
public class Clock extends Application {
#Override public void start(Stage stage) {
DateFormat df = new SimpleDateFormat("EEE,MMM d yyyy - h:mm:ss a");
Date date = new Date();
String stringDate = df.format(date);
Text text = new Text(10, 60, stringDate);
text.setFont(Font.font ("Digital Dream Fat", 30f));
text.setFill(Color.RED);
HBox hbox = new HBox();
Scene scene = new Scene(new Group(text));
scene.setFill(Color.BLACK);
stage.setScene(scene);
stage.initStyle(StageStyle.UNDECORATED);
stage.setWidth(710);
stage.setHeight(80);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
First of all, you have to remember that UI's components are not thread-safe thus any update operations on the ui must be done within the ui's thread itself and not from background threads otherwise they will block the UI's thread.
To update it you can use thread safe mechanisms, one of them is Timeline class. Let's now implement it in your code.
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.scene.paint.Color;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import java.text.DateFormat;
import java.util.Date;
import java.text.SimpleDateFormat;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.util.Duration;
public class Clock extends Application {
#Override public void start(Stage stage) {
DateFormat df = new SimpleDateFormat("EEE,MMM d yyyy - h:mm:ss a");
Date date = new Date();
String stringDate = df.format(date);
Text text = new Text(10, 60, stringDate);
text.setFont(Font.font ("Digital Dream Fat", 30f));
text.setFill(Color.RED);
HBox hbox = new HBox();
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(0),
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
Date update = new Date();
String stringNewDate = df.format(update);
text.setText(stringNewDate);
}
}
), new KeyFrame(Duration.seconds(1)));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play(); // timeline.stop()
Scene scene = new Scene(new Group(text));
scene.setFill(Color.BLACK);
stage.setScene(scene);
stage.initStyle(StageStyle.UNDECORATED);
stage.setWidth(710);
stage.setHeight(80);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The sleep/pause part is controlled on this line .. new KeyFrame(Duration.seconds(1))) so every minute will be Duration.minutes(1), to stop it just take Timeline's instance then do timeline.stop()
You have to setup a TimerTask and run it in a separate thead.
https://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html
TimerTask can't update the JavaFX Label text
Am trying to load a new scene from another class into the main javafx page and this is the main javafx page
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Cbt extends Application {
Stage stageCbt;
Scene staffMainPage;
BorderPane border;
FlowPane addFlowPane;
Hyperlink SQuestions, setParameters;
public void start(Stage theMainStage){
stageCbt = theMainStage;
border = new BorderPane();
SQuestions.setOnAction(ae -> createQuestionsLinkClicked(ae));
}
private FlowPane addFlowPaneLO() {
addFlowPane = new FlowPane();
addFlowPane.getStyleClass().addAll("pane", "vbox");
Hyperlink options[] = new Hyperlink[]{
setParameters = new Hyperlink("set Questions Parameters"),
SQuestions = new Hyperlink("Select past jamb questions")
};
for (int i = 0; i < 2; i++) {
addFlowPane.setMargin(options[i], new Insets(0, 0, 0, 8));
addFlowPane.getChildren().add(options[i]);
}
addFlowPane.getStyleClass().addAll("pane", "flow");
addFlowPane.setPrefWrapLength(170);
return addFlowPane;
}
public void createQuestionsLinkClicked(ActionEvent ae) {
if (ae.getSource() == SQuestions) {
//Questions ques = new Questions();
stageCbt.setScene(staffMainPage);
borderpane.setCenter(new Questions().getAnchor());
}
}
public static void main(String[] args) {
launch(args);
}
}
and this is the the subclass(Questions.java)
import javafx.beans.property.StringProperty;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ListView;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextArea;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
public class Questions {
TextArea putQues;
Button end, edit, review, next;
BorderPane bpane;
GridPane gdQues;
AnchorPane anchor;
ToggleGroup oneSelected;
Text msg, option;
public static String lvo[] = new String[]{
"Option A",
"Option B",
"Option C",
"Option D",
"Option E"
};
public static String rbo[] = new String[]{
"A",
"B",
"C",
"D",
"E"
};
RadioButton rbs[] = new RadioButton[rbo.length];
ListView lvs [] = new ListView[lvo.length];
public Questions(){
gdQues = new GridPane();
gdQues.setHgap(10);
gdQues.setVgap(10);;
gdQues.setAlignment(Pos.TOP_LEFT);
gdQues.getStyleClass().add("grid");
msg = new Text("Questions should be put below");
msg.setFont(Font.font("Arial", FontWeight.BOLD, 20));
gdQues.add(msg, 3, 3);
putQues = new TextArea();
putQues.setPromptText("Type question here");
gdQues.add(putQues, 4, 0);
option = new Text("Options");
option.setFont(Font.font("Monotype Corsiva", FontWeight.BOLD, 10));
gdQues.add(option, 6, 0);
//options = new ListView();
//ListView optionAll = new ListView();
for(int i = 0; i < rbo.length; i++){
RadioButton rb = rbs[i] = new RadioButton(rbo[i]);
ListView lv = lvs[i];
rbs[i].setToggleGroup(oneSelected);
}
//gdQues.getChildren().addAll(rbs);
//gdQues.getChildren().addAll(lvs);
anchor = new AnchorPane();
anchor.getStyleClass().add("pane");
end = new Button("End");
edit = new Button("Edit");
review = new Button("Review");
next = new Button("Next");
HBox hb = new HBox();
hb.getStyleClass().add("hb");
hb.getChildren().addAll(end, edit, review, next);
anchor.getChildren().addAll(gdQues, hb);
}
public Parent getGdQues(){
return gdQues;
}
public Parent getAnchor(/*GridPane gdQues*/){
return anchor;
}
public Parent getPutQues(){
return putQues;
}
public Text getMsg(){
return msg;
}
/*public Parent getRbs(){
return rbo;
}
public Parent getLvs(){
return lvs;
}*/
}
all other controls display except the radiobuttons(of which I guess is because the function wasn't move into the constructor).
My question now is how get the radiobuttons to display?
I do not know the format your are using while in instantiating your radio button, see:
RadioButton rb = rbs[i] = new RadioButton(rbo[i]);
See also this question: initialize multiple variables in a same line in java
Maybe are the instantiation in the other oder as you think done. Or you simply forget to delete the fisrt part. Whatever, it seams, you do not use the rb variable, so prefer:
rbs[i] = new RadioButton(rbo[i]);
Or separate it into 2 lines.