JavaFX JFXtras CalendarTextField withShowTime - javafx

I feel that I am missing something when using the CalendarTextField so I come here for some help. Here is the SSCCE that I am using:
Main.java:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("CalendarTextFieldTest.fxml"));
Scene scene = new Scene((StackPane) loader.load());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
CalendarTextFieldTest.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<?import jfxtras.scene.control.CalendarTextField?>
<StackPane xmlns:fx="http://javafx.com/fxml/1" prefWidth="200" fx:controller="com.example.test.CalendarTextFieldTestController">
<CalendarTextField fx:id="test"/>
</StackPane>
CalendarTextFieldController.java:
package com.example.test;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javafx.fxml.FXML;
import jfxtras.scene.control.CalendarTextField;
public class CalendarTextFieldTestController {
#FXML
CalendarTextField test;
public void initialize()
{
test.withCalendar(Calendar.getInstance());
//test.withShowTime(Boolean.TRUE);
test.setDateFormat(SimpleDateFormat.getDateTimeInstance());
}
}
In this state the test works fine. But when I comment out the test.showShowTime(Boolean.TRUE) I no longer get any type of response when clicking a date.
Any help as to what I may be overlooking would be appreciated.

I just ran your example and it runs flawlessly, so it is not a bug in JFXtras, it seems.
Maybe you are over looking the two icons in the top right corner? That is, if you use the latests R4-SNAPSHOT, because JavaFX has made some changes to the way they do CSS in 8.20 and those icons are not visible with earlier versions.
Problem with the "show time mode" is that when the time sliders are shown, there are suddenly multiple active buttons to press and slide around. If only date is shown, the popup knows it can close when a date is clicked. But in time mode it cannot; maybe the user still wants to modify the hours, or minutes, or maybe not. There is no way of telling. So in time mode there is an explicit accept or cancel icon in the top right corner.

Related

javafx label message showing with timer does not work

So im trying to show a message in javafx on a label and then make it disapear after 1 second. Im able to show the message as desired but i cannot make it dissapear. Actually my problem is that i never appear. So if i use only this:
lbReserva.setText("RESERVA REALITZADA");
Works as expected but obviously it just stay like that. So then i tried this:
try {
lbReserva.setText("RESERVA REALITZADA");
TimeUnit.SECONDS.sleep(1);
lbReserva.setText("");
} catch (InterruptedException e) {
System.err.format("IOException: %s%n", e);
}
But then the label it just never appears. I've tried placing the first set text outside right before the try block. I've tried placing the second set text just after the catch. In any case i got the same result, the label never appears, or probably appears and straight away dissapear. Any clues what im doing wrong? thank you so much in advance.
pd: i have tried using Thread.sleep instead of TimeUnit but i got the same result.
Use PauseTransition.
import javafx.animation.PauseTransition;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class TestingGround extends Application
{
#Override
public void start(Stage stage) throws Exception
{
Label label = new Label("Hello World!");
PauseTransition wait = new PauseTransition(Duration.seconds(1));
wait.setOnFinished((e) -> {
label.setVisible(false);
});
wait.play();
VBox root = new VBox(label);
stage.setScene(new Scene(root, 700, 500));
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}

Selecting ComboBox option on key press. I would like the selection model to auto scroll/jump to the selected option

What I have so far:
When I press for example the C key button, this happens:
First item starts with C is selected.
The selectOptionOnKey (see below) function selected the option that starts with letter C.
The problem:
The combo box stores more option that can be displayed at once. So when the option which is selected is not in the displayed area I want the combo box to scroll down/jump to that option but I don't know how to do that.
Selected an option by pressing a letter key - option is not in the displayed area. - This will happen with the current code.
Selected an option by pressing a letter key - option is not in the displayed area. - This is what I want to happen!
Sample code:
Main:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root, 850.0, 650.0);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller:
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.SingleSelectionModel;
import javafx.scene.input.KeyCode;
public class SampleController implements Initializable {
#FXML private ComboBox<String> cb;
//Entered random options
private final ObservableList<String> options = FXCollections.observableArrayList(
"Aab",
"Aer",
"Aeq",
"Arx",
"Byad",
"Csca",
"Csee",
"Cfefe",
"Cead",
"Defea",
"Dqeqe",
"Fefaf",
"Gert",
"Wqad",
"Xsad",
"Zzz"
);
#Override
public void initialize(URL location, ResourceBundle resources) {
cb.getItems().addAll(options);
selectOptionOnKey();
}
/* When you press a letter key
* this method will search for an option(item) that starts with the input letter key
* and it selects the first occurrence in combo box
*/
public void selectOptionOnKey() {
cb.setOnKeyPressed(e -> {
KeyCode keyCode = e.getCode();
if (keyCode.isLetterKey()) {
char key = keyCode.getName().charAt(0);
SingleSelectionModel<String> cbSelectionModel = cb.getSelectionModel();
cbSelectionModel.select(0);
for (int i = 0; i < options.size(); i++) {
if(cbSelectionModel.getSelectedItem().charAt(0) == key) {
// option which starts with the input letter found -> select it
cbSelectionModel.select(i);
/* Before exiting the function it would be nice if after the selection,
the combo box would auto slide/jump to the option which is selected.
I don't know how to do that. */
return;
}
else
cbSelectionModel.selectNext();
}
}
});
}
}
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="SampleController">
<children>
<ComboBox fx:id="cb" layoutX="300.0" layoutY="300.0" prefHeight="25.0" prefWidth="173.0" />
</children>
</AnchorPane>
Any help is much appreciated.
As general behaviour, selection in a virtual control does not scroll the selected index/item into the visible region. Slightly astonished that the list in a comboBox' dropdown is no exception to that rule - would have expected at the one that's selected on opening to be visible.
The way out is to scroll the newly selected item in code. This involves:
get hold of the comboBox' skin
get the listView by skin.getPopupContent(): while that method is public, its return type is an implementation detail ..
call list.scrollTo(index)
A code snippet, could be called whenever the selection changed, f.i. in your key handler:
cbSelectionModel.select(i);
ComboBoxListViewSkin<?> skin = (ComboBoxListViewSkin<?>) cb.getSkin();
ListView<?> list = (ListView<?>) skin.getPopupContent();
list.scrollTo(i);

JavaFX imageview actions

I'm trying to build a replica of MineSweeper, to do this I'm trying to setup some premade images (100x100 pixels made in Photoshop) into an imageview and then when clicked hiding it (to reveal the number below). Without much complexity -- Just the image going visible and invisible I am finding a lot of issues and difficulties.
It is likely due to a complete lack of knowledge on Javafx in general but I even following tutorials to the t I am still unable to implement this feature. I will attach to this my Main.Java code, my sample.fxml code (although it's not called anymore), and then the image I'm trying to hide when clicked.
I have done a lot of research on this (past couple of days) and haven't found anything that solves my problems.
Main.java:
package sample;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
ImageView button;
#Override
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("MineSweeper XP");
button = new ImageView();
button.setOnMouseClicked(new EventHandler<MouseEvent>)(){
public void handle(MouseEvent event){
}
}
StackPane layout = new StackPane();
layout.getChildren().add(button);
Scene scene = new Scene(layout,1000, 1000);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
sample.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="100.0" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1">
<children>
<ImageView fx:id="button" fitHeight="150.0" fitWidth="100.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../textures/Button_Custom.png" />
</image>
</ImageView>
</children>
</AnchorPane>
The "Button" that will be used for all the MineSweeper keys
My singular goal at this given moment is to create a window of any size where I can put the button anywhere and then when the user clicks that button it disappears.
One possible solution is to create your own ImageView that holds the code for mouse clicks within.
Here's a sample TileButton class:
class TileButton extends ImageView {
public TileButton() {
// Set parameters for the image
Image graphic = new Image("minesweeper/tile.png");
setImage(graphic);
setFitWidth(24);
setFitHeight(24);
// When this button is click, set its visibility to false.
setOnMouseClicked(e -> {
setVisible(false);
});
}
}
Using this custom class, all the logic for the "button" is contained within the TileButton itself.
Now, you can populate your mine field with a GridPane of StackPane containers in each cell. The StackPane allows you to stack nodes on top of each other. So, place a Label with the number you want into each StackPane and then add your new TileButton on top of it.
Below is a complete sample application to demonstrate. Note, I am not implementing any of the actual game logic here, just providing a sample you can copy/paste and see in action. I also have not spent any time formatting and styling the ImageView, but your could use CSS to make it act like a standard button as well.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
VBox root = new VBox(5);
root.setPadding(new Insets(10));
root.setAlignment(Pos.CENTER);
// GridPane to hold the cells
GridPane gridPane = new GridPane();
gridPane.setGridLinesVisible(true);
gridPane.setHgap(2);
gridPane.setVgap(2);
// Populate the Gridpane with a 10x10 grid
int number = 0;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
// Add a new StackPane for each grid cell. The Stackpane will hold a number and the
// TileButton. When the TileButton is clicked, it disappears, revealing the number below
StackPane pane = new StackPane();
pane.getChildren().add(new Label(String.valueOf(number)));
pane.getChildren().add(new TileButton());
gridPane.add(pane, j, i);
// Just increment our sample number
number++;
}
}
root.getChildren().add(gridPane);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
class TileButton extends ImageView {
public TileButton() {
// Set parameters for the image
Image graphic = new Image("minesweeper/tile.png");
setImage(graphic);
setFitWidth(24);
setFitHeight(24);
// When this button is click, set its visibility to false.
setOnMouseClicked(e -> {
setVisible(false);
});
}
}
The above sample application produces this:
Note I am not using FXML for this as creating a grid of multiple custom objects is much simpler in Java than FXML.
Per kleopatra's suggestion, this can be accomplished using a custom Button instead. With the new TileButton class below, you can add the buttons in our loop using gridPane.add(new TileButton(String.valueOf(number)), j, i);:
class TileButton extends Button {
public TileButton(String text) {
// Set the button's size
setPrefSize(24,24);
setStyle("-fx-padding: 0");
// Set the graphic to our tile.png image
setGraphic(new ImageView("sample/done/minesweeper/tile.png"){{
setFitWidth(24);
setFitHeight(24);
}});
// Set the button to display only our graphic initially
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
// Set the action to remove the graphic when the button is clicked
setOnAction(event -> {
setGraphic(new Label(text));
});
}
}

How to vertically center content of Alert/DialogPane?

I created an Alert that is undecorated and I want the content to be centered in the alert. However, there seems to be some padding at the bottom that I can not get rid of.
Here is an MCVE:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Alert;
import javafx.scene.control.DialogPane;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Alert alert = new Alert(Alert.AlertType.NONE);
DialogPane pane = new DialogPane();
HBox contentPane = new HBox(10);
contentPane.setPadding(new Insets(10));
contentPane.setAlignment(Pos.CENTER);
// Add progress indicator and label to contentPane
contentPane.getChildren().addAll(
new ProgressIndicator(ProgressIndicator.INDETERMINATE_PROGRESS) {{
setPrefSize(30, 30);
}},
new Label("Loading ...")
);
// Add border to demonstate the lower padding
contentPane.setStyle("-fx-border-color: black");
pane.setPadding(new Insets(10));
pane.setStyle("-fx-border-color: black");
pane.setContent(contentPane);
alert.setDialogPane(pane);
alert.initStyle(StageStyle.UNDECORATED);
alert.showAndWait();
}
}
The result is this window:
How do I create an Alert or DialogPane without that gap at the bottom?
Using:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Alert;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Main extends Application {
private static Border createBorder(Paint stroke) {
return new Border(new BorderStroke(stroke, BorderStrokeStyle.SOLID,
null, new BorderWidths(2)));
}
#Override
public void start(Stage primaryStage) throws Exception {
ProgressIndicator indicator = new ProgressIndicator();
indicator.setPrefSize(30, 30);
Label label = new Label("Loading...");
label.setMinWidth(Label.USE_PREF_SIZE);
HBox content = new HBox(10, indicator, label);
content.setBorder(createBorder(Color.BLUE));
content.setPadding(new Insets(10));
content.setAlignment(Pos.CENTER);
Alert alert = new Alert(Alert.AlertType.NONE);
alert.initStyle(StageStyle.UNDECORATED);
alert.getDialogPane().getStylesheets()
.add(getClass().getResource("Main.css").toExternalForm());
alert.getDialogPane().setPadding(new Insets(10));
alert.getDialogPane().setContent(content);
alert.getDialogPane().setBorder(createBorder(Color.RED));
alert.show();
}
}
Where this is Main.css:
.dialog-pane .button-bar .container {
-fx-padding: 0px;
}
.dialog-pane:no-header .graphic-container {
-fx-padding: 0px;
}
Resulted in the following:
Some of the needed style-classes I got from here (JavaFX CSS Reference). However, I mostly figured this out from looking at modena.css (where they have the styles for dialog-pane).
If you don't want to use external CSS you can replace alert.getDialogPane().getStylesheets().add(...) with:
alert.getDialogPane().applyCss(); // Seems to stop the lookup calls
// from returning null
alert.getDialogPane()
.lookup(".button-bar")
.lookup(".container")
.setStyle("-fx-padding: 0px;");
alert.getDialogPane().lookup(".graphic-container").setStyle("-fx-padding: 0px;");
alert.show();
Update following your comments.
I initially tried this using Java 10.0.2 but I just tried using Java 8u181 and it still worked for me. I notice in your MCVE you are using a new DialogPane whereas I am using the DialogPane that initially comes with the Alert. Note that the applyCss() method will only work if the Node is a part of a Scene. Apparently the DialogPane is made part of a Scene as soon as it's part of the Alert. So one way you could avoid the NullPointerExceptions is to use the DialogPane that comes with the Alert, as I do.
If you still want to use your own DialogPane you just have to call alert.setDialogPane before calling applyCss(). Note that when I tried this, however, the call lookup(".graphic-container") still returned null. I guess that Node is only present on the original DialogPane. Removing that lookup call fixed it and the other lookup call (for .button-bar > .container) still worked as expected.
All this seems like implementation behavior that should not be relied upon but it works for me on both Java 8 and Java 10. I'd watch this code when changing Java versions just in case though.

How can I remove my javafx program from the taskbar

I need remove my javafx app from the taskbar. I tried StageStyle.UTILITY. This is works but I need both UNDECORATED and UTILITY stage styles or another solvings.
Thank you for your replies.
Sorry you've been waiting so long for some sort of an answer on this, the following is mainly for people who come to this in the future hoping to discover a way of achieving this.
Let me start of by saying I wouldn't consider the following a solution but more of a workaround.
Assigning more than one initStyle to a stage is not possible however hiding the application from the task-bar and assigning an initStyle other than utility to the stage that is shown is.
To achieve this one must create two stages, the stage they want the user to see, and an another stage that will be considered the parent of the main stage and will be of initStyle.UTILITY this will prevent the icon from showing in the task-bar.
Below you can see the hello world example from oracles documentation modified to allow for an undecorated window with no icon (Note if one wanted to achieve a transparent/decorated window they could do so by changing the style of mainStage).
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class MultipleStageStyles extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.initStyle(StageStyle.UTILITY);
primaryStage.setOpacity(0);
primaryStage.setHeight(0);
primaryStage.setWidth(0);
primaryStage.show();
Stage mainStage = new Stage();
mainStage.initOwner(primaryStage);
mainStage.initStyle(StageStyle.UNDECORATED);
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
mainStage.setScene(new Scene(root, 300, 250));
mainStage.show();
}
}

Resources