JavaFX ChoiceBox doesn't show initial value - user-interface

I have a factory method that gives me a ChoiceBox with a bidirectional binding to an enum property. The choice box works as expected, except that it doesn't show the initial value set in the property constructor. Instead the choice box shows up initially as blank, not showing any value. What's wrong?
Here's an MRE:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ChoiceBoxMRE extends Application {
private ObjectProperty<Table> table = new SimpleObjectProperty<>(Table.BIG);
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
VBox vBox = new VBox();
vBox.getChildren().add(getChoiceBox(table));
primaryStage.setScene(new Scene(vBox));
primaryStage.show();
}
private <T extends Enum<T>> ChoiceBox<T> getChoiceBox(ObjectProperty<T> objectProperty) {
ChoiceBox<T> choiceBox = new ChoiceBox<>();
choiceBox.getItems()
.addAll(objectProperty.getValue().getDeclaringClass().getEnumConstants());
Bindings.bindBidirectional(objectProperty, choiceBox.valueProperty());
return choiceBox;
}
enum Table {
BIG, SMALL;
}
}

I am not sure if that is a bug or not, but there is a simple workaround: simply select the value prior to binding it:
choiceBox.getSelectionModel().select(objectProperty.get());

Related

Dialogue Positioning Javafx

I am trying to create a Javafx game and I want the user to be able to input their name using a dialogue. The problem is that when I try to position the dialogue using setY() or setX() nothing changes. I should note that I am using an online IDE so if this is the problem please somebody tell me.
import javafx.stage.Modality;
import javafx.scene.control.*;
import javafx.scene.control.Dialog;
import javafx.geometry.*;
import javafx.stage.Stage;
import javafx.scene.Scene;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
VBox page = new VBox();
Scene scene = new Scene(page, 600, 700);
primaryStage.setScene(scene);
primaryStage.show();
setUserName();
}
public static void setUserName() {
Dialog<String> dialog = new Dialog<String>();
dialog.setTitle("Dialog");
ButtonType type = new ButtonType("Ok", ButtonData.OK_DONE);
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.initStyle(StageStyle.UNDECORATED);
dialog.setContentText("Hello World");
dialog.setY(100);
dialog.showAndWait();
}
public static void main(String[] args) {
launch(args);
}
}

Set text color of JavaFX TextField without CSS

I've been working a lot in JavaFX lately, by writing code only -- no CSS no FXML and I want to keep it that way. I've managed to do all of the stuff I wanted that way except that now I can't set the text color of TextField without using CSS, so I'm asking for advice here. Is there any way to do it, no matter how hacky it is?
Note that I'm still using Java 8 version.
Considering your points : "No CSS" and "how hacky it can be.." below is one way to achieve the text coloring.
import com.sun.javafx.scene.control.skin.TextFieldSkin;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class TextField_TextColor_Demo extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
TextField textField = new TextField();
textField.setSkin(new TextFieldSkin(textField){
#Override
protected void layoutChildren(double x, double y, double w, double h) {
super.layoutChildren(x, y, w, h);
if(textField.getProperties().get("colorChanged")==null) {
textFill.setValue(Color.RED);
textField.getProperties().put("colorChanged",true);
}
}
});
StackPane root = new StackPane(textField);
Scene scene = new Scene(root, 300,300);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String... args){
Application.launch(args);
}
}
I could not make it work. But made another solution. Although the caret color also changes.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.skin.TextFieldSkin;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.stage.Stage;
public class TextField_TextColor_Demo extends Application {
#Override
public void start(Stage stage) throws Exception {
TextField txt = new TextField();
CustomTextFieldSkin skin = new CustomTextFieldSkin(txt);
txt.setSkin(skin);
skin.setHighlight(Color.RED);
HBox box = new HBox(txt);;
Scene scene = new Scene(box, 300, 100);
stage.setScene(scene);
stage.show();
}
public class CustomTextFieldSkin extends TextFieldSkin{
public CustomTextFieldSkin(TextField textField) {
super(textField);
}
public void setHighlight(Paint value) {
setTextFill(value);
}
}
public static void main(String... args){
Application.launch(args);
}
}
Seems it is possible to color the caret separately, according these two answers:
https://stackoverflow.com/a/47876289/7989121
https://stackoverflow.com/a/27323035/7989121
Both use caretPath though, which I could not use due it not being visible according to my IDE

Event handler for objects of the same Pane

i'm studying the mechanism of the event handler on javaFX ,but i'm not sure that i have understand it , in Fact I have a little doubt :
if i have two object , they have all necessary code to handle the event (EventHandler interface ecc..),that they BELONG at the SAME stackPane ,the question is : is there a way for the 1st object to launch an event (ActionEvent for example ) that will be handled by the 2 object though they belong at the same Pane?
Because for what i have understand about the "event route",this is not possible ,at least directly.
In essence my little program have a splitpane that divided in two stackpane the screen,in the left panel i have put a gridpane with the button, each of them have the function that permit to draw a different shape ,in the right panel with a canvas.
My idea it was to launch an ActionEvent in setonaction of each button ,implements the EventHandlers on canvas to capture the event
with relative handle method ,and in the corp of he handle mode discriminate which button is Clicked for drawing the correct shape.
Can someone help me ? Thanks a lot anyway
package es1;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
*
* #author DAVIDE
*/
public class Es1 extends Application {
#Override
public void start(Stage primaryStage) {
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!");
lanciaevento(this.getClass().toString());
}
});
//add a button on left panel and a textfiled on the right for test if the event launched
//on the click of the button is reached by the textfield
Textfield text = new Textfield();
StackPane panel1 = new StackPane();
panel1.getChildren().addAll(btn);
StackPane panel2 = new StackPane();
panel2.getChildren().addAll(text);
splitpane divisore = new splitpane();
divisore.addEventHandler(ActionEvent.ACTION, divisore);
divisore.getItems().addAll(panel1,panel2);
Scene scene = new Scene(divisore, 600, 450);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public void lanciaevento(String oggetto)
{
ActionEvent evento = new ActionEvent();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
package es1;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.SplitPane;
/**
*
* #author DAVIDE
*/
public class splitpane extends SplitPane implements EventHandler<ActionEvent>{
private String message_event;
public String get_message()
{
return(message_event);
}
public void set_message(String messaggio)
{
message_event = messaggio;
}
#Override
public void handle(ActionEvent event) {
System.out.println("mi ha mandato un messaggio "+event.getSource().toString());
}
}
/*
* To change this license header, choose License Headers in Project Properties.
package es1;
import javafx.event.ActionEvent;
javafx.event.EventHandler;
import javafx.scene.control.TextField;
/**
*
* #author DAVIDE
*/
public class Textfield extends TextField implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent event) {
this.appendText(event.getSource().toString());
}
}

How to inject objects which are not annotated Spring classes

Lets say I've got a JavaFx class and an ViewState class which needs to have referance of stage created in start method. How am I able to autowire such dependency? I know that Stage.class is not annotated as #Component so Spring is unable to detect duch #Bean.
#SpringBootApplication
#ComponentScan({"controller","service","dao","javafx.stage.Stage"})
#EntityScan( basePackages = {"Model"})
#Import({ SpringConfig.class})
public class JavaFXandSpringBootTestApplication extends Application{
private ApplicationContext ctx;
public static void main(String[] args) {
launch();
}
#Override
public void start(Stage stage) throws Exception {
ViewState viewState = ctx.getBean(ViewState.class);
}
ViewState class:
#Componenet
public class ViewState {
#Autowired
private ApplicationContext ctx;
private Stage stage;
#Autowired
public ViewState(Stage stage)
{
this.stage = stage;
}
}
Compiler massage:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javafx.stage.Stage' available: expected at least 1
You probably don't want to do this at all: your ViewState class would seem to be a model class of some kind, so it should not have references to UI elements (such as Stages).
For completeness, though, here is an example that works, using ConfigurableApplicationContext.getBeanFactory().registerResolvableDependency(...). Note that, since you won't be able to create the View object until the stage is registered, you need to make the View bean #Lazy:
package example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
#Component
#Lazy
public class View {
#Autowired
public View(Stage stage) {
Button close = new Button("Close");
close.setOnAction(e -> stage.hide());
StackPane root = new StackPane(close);
Scene scene = new Scene(root, 400, 400);
stage.setScene(scene);
stage.show();
}
}
package example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import javafx.application.Application;
import javafx.stage.Stage;
#SpringBootApplication
public class Main extends Application {
private ConfigurableApplicationContext ctx ;
#Override
public void start(Stage primaryStage) {
ctx = SpringApplication.run(Main.class);
ctx.getBeanFactory().registerResolvableDependency(Stage.class, primaryStage);
ctx.getBean(View.class);
}
#Override
public void stop() {
ctx.close();
}
public static void main(String[] args) {
launch(args);
}
}

Add image to a button at a specific position JavaFX

When I add image and text to a button, by default elements are set horizontally. How can I change this behavior to get text under image ?
Set the contentDisplayProperty on the button.
button.setContentDisplay(ContentDisplay.TOP);
Here is an executable example:
import javafx.application.Application;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ButtonGraphicTest extends Application {
#Override public void start(final Stage stage) throws Exception {
final Label response = new Label();
final ImageView imageView = new ImageView(
new Image("http://icons.iconarchive.com/icons/eponas-deeway/colobrush/128/heart-2-icon.png")
);
final Button button = new Button("I love you", imageView);
button.setStyle("-fx-base: coral;");
button.setContentDisplay(ContentDisplay.TOP);
button.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
response.setText("I love you too!");
}
});
final VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.getChildren().addAll(button, response);
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10; -fx-font-size: 20;");
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) { launch(args); }
}
// icon license: (creative commons with attribution) http://creativecommons.org/licenses/by-nc-nd/3.0/
// icon artist attribution page: (eponas-deeway) http://eponas-deeway.deviantart.com/gallery/#/d1s7uih

Resources