Change between two FXML files in JavaFX2.2 on change Listener - javafx

i am new in JavaFX programming. I have an Application, with a simple login page as described in the example here, and i add a StringProperty to the actiontarget element. So when the text changes inside the actiontarget i want a new FXML file with a webview inside, to load from the FXMLLoader and be dipslayed on the screen. Below is the exception i get. I can load any other fxml file, without a webview inside it, without a problem. Thanks in advance.Code samples below
The exception :
java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:237)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:397)
at com.sun.webpane.sg.prism.InvokerImpl.checkEventThread(InvokerImpl.java:33)
at com.sun.webpane.platform.WebPage.<init>(WebPage.java:189)
at com.sun.webpane.sg.ImplementationManager.createPage(ImplementationManager.java:57)
at com.sun.webpane.sg.ImplementationManager.createPage(ImplementationManager.java:51)
at javafx.scene.web.WebEngine.<init>(WebEngine.java:704)
at javafx.scene.web.WebEngine.<init>(WebEngine.java:691)
at javafx.scene.web.WebView.<init>(WebView.java:245)
at student.WebBrowser.<init>(WebBrowser.java:31)
at Login.Login.replaceSceneContent(Login.java:171)
at Login.Login.access$000(Login.java:66)
at Login.Login$2.changed(Login.java:143)
at Login.Login$2.changed(Login.java:137)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:121)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:128)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:161)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:67)
at javafx.scene.text.Text.setText(Text.java:188)
at Login.Client.run(Client.java:66)
First my listener:
// Add change listener
sp.addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> ov, String t, String t1) {
if(t1.equalsIgnoreCase("user authenticated successfully")){
try {
replaceSceneContent(cb.getSelectionModel().getSelectedItem().toString()+".fxml",primaryStage);
System.out.println("everything ok");
} catch (Exception ex) {
System.out.println("something went wrong");
ex.printStackTrace();
}
}
}
});
Second my method : replaceSceneContent(String fxml, Stage stage)
private Parent replaceSceneContent(String fxml, Stage stage) throws Exception {
Parent page = (Parent) FXMLLoader.load(getClass().getResource("/FXML_Files/"+fxml), null, new JavaFXBuilderFactory());
Scene scene = stage.getScene();
if (scene == null) {
scene = new Scene(page, 700, 450);
stage.setScene(scene);
} else {
stage.getScene().setRoot(page);
}
if(fxml.equalsIgnoreCase("Student.fxml")){
Pane spane = (Pane) page.lookup("#pane");
WebBrowser wb = new WebBrowser();
spane.getChildren().add(wb);
}
return page;
}
And my WebBrowser class similar to the example in NetBeans7.2:
public class WebBrowser extends Pane {
public WebBrowser() {
WebView view;
final WebEngine eng;
view = new WebView();
view.setMinSize(10, 10);
view.setPrefSize(500, 400);
eng = view.getEngine();
eng.load("http://www.oracle.com/us/index.html");
VBox.setVgrow(this, Priority.ALWAYS);
setMaxWidth(Double.MAX_VALUE);
setMaxHeight(Double.MAX_VALUE);
final TextField locationField = new TextField("http://www.oracle.com/us/index.html");
locationField.setMaxHeight(Double.MAX_VALUE);
Button goButton = new Button("Go");
goButton.setDefaultButton(true);
EventHandler<ActionEvent> goAction = new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
eng.load(locationField.getText().startsWith("http://") ? locationField.getText() :
"http://" + locationField.getText());
}
};
goButton.setOnAction(goAction);
locationField.setOnAction(goAction);
eng.locationProperty().addListener(new ChangeListener<String>() {
#Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
locationField.setText(newValue);
}
});
GridPane grid = new GridPane();
ButtonsEvents be = new ButtonsEvents();
TilePane tp = be;
tp.setAlignment(Pos.CENTER);
grid.setVgap(5);
grid.setHgap(5);
GridPane.setConstraints(locationField, 0, 0, 1, 1, HPos.CENTER, VPos.CENTER, Priority.ALWAYS, Priority.SOMETIMES);
GridPane.setConstraints(goButton,1,0);
GridPane.setConstraints(view, 0, 1, 2, 1, HPos.CENTER, VPos.CENTER, Priority.ALWAYS, Priority.ALWAYS);
GridPane.setConstraints(tp, 0, 2, 2, 1, HPos.CENTER, VPos.CENTER, Priority.ALWAYS, Priority.NEVER);
grid.getColumnConstraints().addAll(
new ColumnConstraints(100, 100, Double.MAX_VALUE, Priority.ALWAYS, HPos.CENTER, true),
new ColumnConstraints(40, 40, 40, Priority.ALWAYS, HPos.CENTER, true)
);
grid.getChildren().addAll(locationField, goButton,view, tp);
getChildren().add(grid);
}
#Override
protected void layoutChildren() {
List<Node> managed = getManagedChildren();
double width = getWidth();
double height = getHeight();
double top = getInsets().getTop();
double right = getInsets().getRight();
double left = getInsets().getLeft();
double bottom = getInsets().getBottom();
for (int i = 0; i < managed.size(); i++) {
Node child = managed.get(i);
layoutInArea(child, left, top,
width - left - right, height - top - bottom,
0, Insets.EMPTY, true, true, HPos.CENTER, VPos.CENTER);
}
}
}

As stated in the exception, changes in the JavaFX scene graph can only be made in the JavaFX application thread. To make sure your code is run in this thread, try the following:
Platform.runLater(new Runnable() {
#Override
public void run() {
// This method is invoked on JavaFX thread
replaceSceneContent(cb.getSelectionModel().getSelectedItem().toString()+".fxml",primaryStage);
}
});
The javafx manager will run this code at some point in the future on the correct thread.
More information:
http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm

Related

I'm trying to implemenet GUI on some kind of Doubly Linked list

I've so far done this, it's adding labels on the stage but removing thing is working but not as intended...
How can I store data of labels in an array or something so I can compare the remove.getText(); with that and delete that typed value if previous added as a label on stage.
public class Main extends Application {
Group root;
Label label1,label;
int count=1,count1=1;
public static void main(String[] args) {launch(args);}
public void start(Stage stage) throws Exception {
stage.setTitle("LinkedList GUI");
stage.setResizable(false);
root = new Group();
LinkedList<Integer> Linked =new LinkedList<Integer>();
Button Addfirst = new Button("AddFirst");
Addfirst.setTranslateX(40);
Addfirst.setTranslateY(350);
TextField first=new TextField();
first.setPrefWidth(60);
first.setTranslateX(120);
first.setTranslateY(350);
Addfirst.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
int a = Integer.parseInt(first.getText());
Linked.addFirst(a);
label1=new Label(" "+first.getText());
label1.setFont(Font.font("Buxton Sketch",FontWeight.BOLD,FontPosture.ITALIC,12));
label1.setPrefWidth(25);
label1.setPrefHeight(25);
label1.setTranslateY(60);
label1.setTextFill(Color.GREEN );
label1.setStyle("-fx-border-color: Blue;");
root.getChildren().addAll(label1);
label1.setTranslateX(250-(20*count++));
count++;
}
});
Button Addlast = new Button("AddLast");
Addlast.setTranslateX(200);
Addlast.setTranslateY(350);
TextField last=new TextField();
last.setPrefWidth(60);
last.setTranslateX(270);
last.setTranslateY(350);
Addlast.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
int b= Integer.parseInt(last.getText());
Linked.addLast(b);
label=new Label(" "+last.getText());
label.setFont(Font.font("Buxton Sketch",FontWeight.BOLD,FontPosture.ITALIC,12));
label.setPrefWidth(25);
label.setPrefHeight(25);
label.setTranslateY(60);
label.setTextFill(Color.GREEN );
label.setStyle("-fx-border-color: Blue;");
root.getChildren().add(label);
label.setTranslateX(250+(20*count1++));
count1++;
}
});
Button delete = new Button("Delete");
delete.setTranslateX(350);
delete.setTranslateY(350);
TextField remove=new TextField();
remove.setPrefWidth(60);
remove.setTranslateX(420);
remove.setTranslateY(350);
delete.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
if(remove.getText().equals(first.getText())) {
Linked.remove(first.getText());
root.getChildren().remove(label1);
}
else if(remove.getText().equals(last.getText())) {
Linked.remove(last.getText());
root.getChildren().remove(label);
}
else {
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Error");
alert.setContentText("Not in List");
alert.showAndWait();
}
}
});
Text text =new Text("Doubly LinkedList GUI");
text.setStyle("-fx-border-color: Blak;");
text.setFont(Font.font("Buxton Sketch",FontWeight.BOLD,FontPosture.ITALIC,16));
text.setTranslateX(150);
text.setTranslateY(30);
root.getChildren().addAll(text,Addfirst,first,Addlast,last,delete,remove);
Scene scene = new Scene(root,500,400);
stage.setScene(scene);
stage.show();
}
}
I recommend using a layout that positions the children for you instead of positioning them yourself. E.g. using a HBox as parent for the labels allows you to simply add/remove the child at the same index as the one added/removed in the list:
#Override
public void start(Stage stage) throws Exception {
HBox container = new HBox(20);
container.setPrefHeight(40);
Button addFirst = new Button("add head");
Button addLast = new Button("add tail");
Button remove = new Button("remove");
TextField textField = new TextField();
HBox buttonContainer = new HBox(10, textField, addFirst, addLast, remove);
final LinkedList<Integer> list = new LinkedList<>();
addFirst.setOnAction(evt -> {
String text = textField.getText();
Integer value = Integer.parseInt(text);
list.addFirst(value);
container.getChildren().add(0, new Label(text));
});
addLast.setOnAction(evt -> {
String text = textField.getText();
Integer value = Integer.parseInt(text);
list.addLast(value);
container.getChildren().add(new Label(text));
});
remove.setOnAction(evt -> {
String text = textField.getText();
int value = Integer.parseInt(text);
ListIterator<Integer> iterator = list.listIterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
if (element == value) {
container.getChildren().remove(iterator.nextIndex() - 1);
iterator.remove();
break;
}
}
});
VBox root = new VBox(container, buttonContainer);
Scene scene = new Scene(root, 500, 400);
stage.setScene(scene);
stage.show();
}

JavaFX cannot close scene by Esc using getAccelerators() [duplicate]

Im calling a new stage in my program which I like to close on pressing escape. I did this which gives me a NullPointerException:
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
KeyCode key = t.getCode();
if (key == KeyCode.ESCAPE){
stage.close();
}
}
});
try this..
scene.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>
() {
#Override
public void handle(KeyEvent t) {
if(t.getCode()==KeyCode.ESCAPE)
{
System.out.println("click on escape");
Stage sb = (Stage)label.getScene().getWindow();//use any one object
sb.close();
}
}
});
Add the event handler to the stage/window you want to close on ESC.
JavaFX 8 style:
stage.addEventHandler(KeyEvent.KEY_RELEASED, (KeyEvent event) -> {
if (KeyCode.ESCAPE == event.getCode()) {
stage.close();
}
});
why you dont show us more of your code? However, try this:
public class Login extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage primaryStage) {
primaryStage.setTitle("JavaFX Welcome");
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25, 25, 25, 25));
Text scenetitle = new Text("Welcome");
scenetitle.setId("welcome-text");
grid.add(scenetitle, 0, 0, 2, 1);
Label userName = new Label("User Name:");
grid.add(userName, 0, 1);
TextField userTextField = new TextField();
grid.add(userTextField, 1, 1);
Label pw = new Label("Password:");
grid.add(pw, 0, 2);
PasswordField pwBox = new PasswordField();
grid.add(pwBox, 1, 2);
Button btn = new Button("Sign in");
HBox hbBtn = new HBox(10);
hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
hbBtn.getChildren().add(btn);
grid.add(hbBtn, 1, 4);
Scene scene = new Scene(grid, 660, 300);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
public void handle(KeyEvent ke) {
if (ke.getCode() == KeyCode.ESCAPE) {
System.out.println("Key Pressed: " + ke.getCode());
primaryStage.close();
}
}
});
//primaryStage.setFullScreen(true);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Done.
Hope the imported Eventhandler package is not of JavaFX.
Try using,
import javafx.event.EventHandler;
Note:As the naming convention are same but only the package name differs between swing and JavaFX, Your NetBeans/Eclipse may auto import different packages, so make sure of it.

JavaFX WhatApp-Like ConversationView

I'm trying to make a WhatsApp-Like Conversation-View in JavaFX.
In order to make the sent messages appear on the right and the received messages appear on the left then I cannot use TextArea. How can I do it? I tried GridPane without TextArea but it didn't make things easier.
Moreover, is it a good practice to make controls static?
Extra: if you can also help me do the chat bubble behind the text, it would be great.
Here is my code:
public class ConversationView implements WhatAppView {
private static Label nameLabel, statusLabel;
private static TextField messageTextField;
static TextArea messagesTextArea;
private static GridPane conversationSection;
private static Label changeViewLink;
private static Button sendMsgButton;
// private static int rowIndex = 1;
public void showView() {
AppMain.stage.setResizable(false);
AppMain.stage.setWidth(350);
AppMain.stage.setHeight(550);
BorderPane rootPane = new BorderPane();
rootPane.setPadding(new Insets(5, 5, 5, 5));
final int sectionHeight = 55;
StackPane contactSection = new StackPane();
nameLabel = new Label("RW");
statusLabel = new Label("Online");
changeViewLink = new Label("Go Back");
changeViewLink.setStyle("-fx-text-fill: blue;");
changeViewLink.styleProperty().bind(
Bindings.when(changeViewLink.hoverProperty())
.then(new SimpleStringProperty("-fx-underline: true; -fx-text-fill: blue;"))
.otherwise(new SimpleStringProperty("-fx-underline: false; -fx-text-fill: blue;")));
changeViewLink.setOnMouseClicked(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
AppMain.changeView(new ChatsView());
}
});
contactSection.getChildren().addAll(nameLabel, statusLabel, changeViewLink);
StackPane.setAlignment(changeViewLink, Pos.TOP_RIGHT);
StackPane.setAlignment(statusLabel, Pos.BOTTOM_CENTER);
contactSection.setPrefHeight(sectionHeight);
conversationSection = new GridPane();
conversationSection.setStyle("-fx-background-image: url('whatsapp-wallpaper.jpg')");
messagesTextArea = new TextArea();
messagesTextArea.setEditable(false);
// conversationSection.getColumnConstraints().addAll(new
// ColumnConstraints(AppMain.stage.getWidth()/2 - 10), new
// ColumnConstraints(AppMain.stage.getWidth()/2 - 10));
conversationSection.add(messagesTextArea, 0, 0);
conversationSection.setPrefSize(AppMain.stage.getWidth(), AppMain.stage.getHeight());
// conversationSection.getStylesheets().add("conversation.css");
ScrollPane scroll = new ScrollPane();
scroll.setPrefSize(conversationSection.getWidth(), conversationSection.getHeight());
scroll.setContent(conversationSection);
FlowPane messageSection = new FlowPane();
sendMsgButton = new Button("_Send");
sendMsgButton.setDisable(true);
sendMsgButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
sendMsg();
}
});
sendMsgButton.setPrefHeight(sectionHeight);
Tooltip sendMsgToolTip = new Tooltip("Send Message");
Tooltip.install(sendMsgButton, sendMsgToolTip);
FlowPane.setMargin(sendMsgButton, new Insets(0, 0, 0, 5));
messageTextField = new TextField();
messageTextField.setPromptText("Type your message here...");
Platform.runLater(new Runnable() { // 100% focus
public void run() {
messageTextField.requestFocus();
}
});
messageTextField.setPrefWidth(AppMain.stage.getWidth() - AppMain.stage.getWidth() / 5);
messageTextField.setPrefHeight(sectionHeight);
messageTextField.setAlignment(Pos.TOP_LEFT);
messageTextField.setOnKeyTyped(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (messageTextField.getText() != null && !messageTextField.getText().isEmpty()) {
sendMsgButton.setDisable(false);
} else {
sendMsgButton.setDisable(true);
}
}
});
messageTextField.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode().equals(KeyCode.ENTER) && messageTextField.getText() != null
&& !messageTextField.getText().isEmpty()) {
sendMsg();
}
}
});
messageSection.getChildren().add(messageTextField);
messageSection.getChildren().add(sendMsgButton);
messageSection.setPrefHeight(sectionHeight);
rootPane.setTop(contactSection);
rootPane.setCenter(conversationSection);
rootPane.setBottom(messageSection);
Scene scene = new Scene(rootPane);
AppMain.stage.setScene(scene);
AppMain.stage.setTitle("WhatsApp");
}
}
public class AppMain extends Application {
static Stage stage;
#Override
public void start(Stage primaryStage) throws Exception {
stage = primaryStage;
AppMain.stage.show();
changeView(new ConversationView());
}
public static void changeView(WhatAppView view) {
view.showView();
}
}
public interface WhatAppView {
public void showView();
}
You can create a custom control to determine message alignment and aesthetics such as the bubble like appearance. As a fan of HBox and VBox, I would recommend their usage in combination with an SVGPath to decorate the message.
SVGPath's let you draw custom shapes by providing information on the lines, arcs etc. These aren't unique to java so there are a few resources available to see some basic/advanced examples. My recommendation would be to read here: SVGPath and use the TryitEditor to experiment
Here are two quick examples:
When it comes to laying out the messages a VBox would suffice. You can bind the viewable children to an ObservableList of messages you would be able to iterate later. The added benefit of this is that adding to the list will update the UI automatically, and you'll also be able to iterate these later in the event you implement additional features such as delete, forward etc
I'd recommend reading up on the Bindings api, particularly bindContentBidirectional for more information on this
Using my above recommendations i've written a small example below you can reference. It's not visually impressive, but hopefully you can get some ideas from it, particularly this:
Extra: if you can also help me do the chat bubble behind the text, it
would be great.
The messages/speech bubbles:
enum SpeechDirection{
LEFT, RIGHT
}
public class SpeechBox extends HBox{
private Color DEFAULT_SENDER_COLOR = Color.GOLD;
private Color DEFAULT_RECEIVER_COLOR = Color.LIMEGREEN;
private Background DEFAULT_SENDER_BACKGROUND, DEFAULT_RECEIVER_BACKGROUND;
private String message;
private SpeechDirection direction;
private Label displayedText;
private SVGPath directionIndicator;
public SpeechBox(String message, SpeechDirection direction){
this.message = message;
this.direction = direction;
initialiseDefaults();
setupElements();
}
private void initialiseDefaults(){
DEFAULT_SENDER_BACKGROUND = new Background(
new BackgroundFill(DEFAULT_SENDER_COLOR, new CornerRadii(5,0,5,5,false), Insets.EMPTY));
DEFAULT_RECEIVER_BACKGROUND = new Background(
new BackgroundFill(DEFAULT_RECEIVER_COLOR, new CornerRadii(0,5,5,5,false), Insets.EMPTY));
}
private void setupElements(){
displayedText = new Label(message);
displayedText.setPadding(new Insets(5));
displayedText.setWrapText(true);
directionIndicator = new SVGPath();
if(direction == SpeechDirection.LEFT){
configureForReceiver();
}
else{
configureForSender();
}
}
private void configureForSender(){
displayedText.setBackground(DEFAULT_SENDER_BACKGROUND);
displayedText.setAlignment(Pos.CENTER_RIGHT);
directionIndicator.setContent("M10 0 L0 10 L0 0 Z");
directionIndicator.setFill(DEFAULT_SENDER_COLOR);
HBox container = new HBox(displayedText, directionIndicator);
//Use at most 75% of the width provided to the SpeechBox for displaying the message
container.maxWidthProperty().bind(widthProperty().multiply(0.75));
getChildren().setAll(container);
setAlignment(Pos.CENTER_RIGHT);
}
private void configureForReceiver(){
displayedText.setBackground(DEFAULT_RECEIVER_BACKGROUND);
displayedText.setAlignment(Pos.CENTER_LEFT);
directionIndicator.setContent("M0 0 L10 0 L10 10 Z");
directionIndicator.setFill(DEFAULT_RECEIVER_COLOR);
HBox container = new HBox(directionIndicator, displayedText);
//Use at most 75% of the width provided to the SpeechBox for displaying the message
container.maxWidthProperty().bind(widthProperty().multiply(0.75));
getChildren().setAll(container);
setAlignment(Pos.CENTER_LEFT);
}
}
Conversation window:
public class ConversationView extends VBox{
private String conversationPartner;
private ObservableList<Node> speechBubbles = FXCollections.observableArrayList();
private Label contactHeader;
private ScrollPane messageScroller;
private VBox messageContainer;
private HBox inputContainer;
public ConversationView(String conversationPartner){
super(5);
this.conversationPartner = conversationPartner;
setupElements();
}
private void setupElements(){
setupContactHeader();
setupMessageDisplay();
setupInputDisplay();
getChildren().setAll(contactHeader, messageScroller, inputContainer);
setPadding(new Insets(5));
}
private void setupContactHeader(){
contactHeader = new Label(conversationPartner);
contactHeader.setAlignment(Pos.CENTER);
contactHeader.setFont(Font.font("Comic Sans MS", 14));
}
private void setupMessageDisplay(){
messageContainer = new VBox(5);
Bindings.bindContentBidirectional(speechBubbles, messageContainer.getChildren());
messageScroller = new ScrollPane(messageContainer);
messageScroller.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
messageScroller.setHbarPolicy(ScrollBarPolicy.NEVER);
messageScroller.setPrefHeight(300);
messageScroller.prefWidthProperty().bind(messageContainer.prefWidthProperty().subtract(5));
messageScroller.setFitToWidth(true);
//Make the scroller scroll to the bottom when a new message is added
speechBubbles.addListener((ListChangeListener<Node>) change -> {
while (change.next()) {
if(change.wasAdded()){
messageScroller.setVvalue(messageScroller.getVmax());
}
}
});
}
private void setupInputDisplay(){
inputContainer = new HBox(5);
TextField userInput = new TextField();
userInput.setPromptText("Enter message");
Button sendMessageButton = new Button("Send");
sendMessageButton.disableProperty().bind(userInput.lengthProperty().isEqualTo(0));
sendMessageButton.setOnAction(event-> {
sendMessage(userInput.getText());
userInput.setText("");
});
//For testing purposes
Button receiveMessageButton = new Button("Receive");
receiveMessageButton.disableProperty().bind(userInput.lengthProperty().isEqualTo(0));
receiveMessageButton.setOnAction(event-> {
receiveMessage(userInput.getText());
userInput.setText("");
});
inputContainer.getChildren().setAll(userInput, sendMessageButton, receiveMessageButton);
}
public void sendMessage(String message){
speechBubbles.add(new SpeechBox(message, SpeechDirection.RIGHT));
}
public void receiveMessage(String message){
speechBubbles.add(new SpeechBox(message, SpeechDirection.LEFT));
}
}
Output:

Stage loses fill (gradient) after simply creating a new control

I have reduced my recreate of this to the following. The line where a ToggleButton is instantiated causes my stage to lose its fill color; it goes white. I am just getting started with JavaFX, so please let me know if I'm doing something I shouldn't, here. This is using jre1.8.0_92 with Eclipse Neon (jfx8_2.3.0 plugin) on Windows 7 sp1.
public class Main extends Application {
public static void main(String[] args) {
if(args.length > 0) {
String s = args[0].toLowerCase();
if(s.equals("full"))
Machine.isFullScreen = true;
}
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Machine.startMachine(primaryStage);
}
}
public class Machine {
static boolean isFullScreen = false;
static Rectangle2D screenRect, backRect;
static Stage backStage;
static Scene backScene;
static Pane backPane;
private Machine() {}
static public void startMachine(Stage primaryStage) {
// backscreen
startScene(primaryStage);
// This line causes the fill to be lost
ToggleButton foo = new ToggleButton("hi");
}
static private void startScene(Stage primaryStage) {
// Stage
backStage = primaryStage;
backStage.initStyle(StageStyle.UNDECORATED);
backStage.setFullScreen(isFullScreen);
screenRect = Screen.getPrimary().getBounds();
if(!isFullScreen) {
int w = 1000, h = 500, t = 20;
backStage.setWidth(w);
backStage.setHeight(h);
backStage.setX((screenRect.getWidth() - w)/2);
backStage.setY(t);
}
backRect = new Rectangle2D(backStage.getX(), backStage.getY(),
backStage.getWidth(), backStage.getHeight());
// Scene
backScene = new Scene(backPane = new Pane());
// backScene.getStylesheets().add(Machine.class.getResource("mainStyle.css").toExternalForm());
// backScene.getRoot().setStyle("-fx-background-color: #CCFF99;");
backScene.setFill(new LinearGradient(0,0,1,1, true, CycleMethod.NO_CYCLE,
new Stop[]{
new Stop(0,Color.web("#4977A3")),
new Stop(0.5, Color.web("#B0C6DA")),
new Stop(1,Color.web("#9CB6CF")), } ));
// Logo
Text logo = new Text("AMT");
logo.setFill(Color.DEEPSKYBLUE);
Font font = Font.font("Times New Roman", FontWeight.BOLD, FontPosture.ITALIC, 96);
logo.setFont(font);
logo.setX(100);
logo.setY(150);
backPane.getChildren().add(logo);
backStage.setScene(backScene);
backStage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
backStage.show();
}
}
The setFill() API suggests that this may be a stylesheet effect. The default stylesheet is installed statically when the first Control is instantiated. If that stylesheet is Modena, "the default fill is set to be a light gray color." Instead of backScene.setFill(), try backPane.setBackground(), as suggested here and here.
// Scene
backPane = new Pane();
backScene = new Scene(backPane);
LinearGradient linearGradient = new LinearGradient(
0, 0, 1, 1, true, CycleMethod.NO_CYCLE,
new Stop(0, Color.web("#4977A3")),
new Stop(0.5, Color.web("#B0C6DA")),
new Stop(1, Color.web("#9CB6CF")));
backPane.setBackground(new Background(new BackgroundFill(
linearGradient, CornerRadii.EMPTY, Insets.EMPTY)));
As an aside, note that the varargs constructor parameter of LinearGradient allows you to add instances of Stop directly, without creating a new array.

How do I run two processes separately from inside one EventHandler?

I am using JavaFx, and I have an EventHandler that runs when a button is clicked. The Handler is supposed to 1) put a progress bar on the screen, and AFTERWARDS make a new window. The window takes a little while to create, so the progress bar is there to let people know that the program did not just freeze.
Here is the code that contains the EventHandler
public HBox SelectionSection(){
final HBox hb = new HBox();
GridPane grid = new GridPane();
grid.setAlignment(Pos.BASELINE_LEFT);
hb.setStyle("-fx-background-color: linear-gradient(#CEF5FD 0%, #1864E2 100%);");
hb.setPrefSize(350, HEIGHT);
Button done = new Button("Create Data");
final CheckBox ch1 = new CheckBox("Class Stats");
ch1.setSelected(true);
final CheckBox ch2 = new CheckBox("Class Chart");
ch2.setSelected(true);
final CheckBox ch5 = new CheckBox("Interactive Stats");
final CheckBox ch3 = new CheckBox("Objectives Summary");
final CheckBox ch4 = new CheckBox("part 4");
final JFXDragAndDrop JFX = this;
CheckBox sdf = new CheckBox();
done.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent arg0) {
if(dir!=null){
grid.getChildren().add(p1);
new Excel(JFX, dir, ch1.isSelected(), ch2.isSelected(), ch3.isSelected(), ch4.isSelected(), ch5.isSelected());
}
else{
Platform.runLater(new Runnable(){
public void run(){
JFX.createError(2);
}
});
}
}
});
GridPane.setConstraints(ch1, 7, 7, 1, 1,HPos.LEFT, VPos.CENTER);
GridPane.setConstraints(ch2, 7, 8, 1, 1,HPos.LEFT, VPos.CENTER);
GridPane.setConstraints(ch5, 7, 9, 1, 1, HPos.LEFT, VPos.CENTER);
GridPane.setConstraints(ch3, 7, 10, 1, 1,HPos.LEFT, VPos.CENTER);
GridPane.setConstraints(done, 7, 16, 1, 1,HPos.CENTER, VPos.CENTER);
GridPane.setConstraints(p1,7,15,1,1,HPos.CENTER,VPos.CENTER);
grid.getChildren().addAll(ch1,ch2,ch3,ch5,done);
hb.getChildren().add(grid);
return hb;
}
Here is a picture of what it should look like. The loading bar should pop up as soon as you click the 'done' button. Instead, it finishes running Excel() before the loading bar pops up.
try this it may help you...!!
initialize some variables
#FXML
private ProgressBar bar;
int max = 1000000;
int i=0;
now perform event on button
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t)
{
loadAppConfigurationFile();
}
});
function definition
private void loadAppConfigurationFile() {
Task task = new Task<Void>() {
#Override public Void call() throws InterruptedException {
for ( i=1; i<=max; i=i+10) {
if (isCancelled()) {
break;
}
// System.out.println("value of time - "+now.getMinutes());
//if(i==1)
//{
// Thread.sleep(pk);
//}
updateProgress(i, max);
//System.out.println("1");
DecimalFormat df = new DecimalFormat("#.00");
System.out.println("progress - "+df.format(bar.getProgress()));
Double abc = Double.parseDouble(df.format(bar.getProgress()));
if(abc==1.00)
{
System.out.println("at here");
Parent root;
try
{
URL url = getClass().getResource("Check.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(url);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
root = (Parent)fxmlLoader.load(url.openStream());
Stage stage = new Stage();
//sstage.initStyle(StageStyle.UNDECORATED);
// stage.setFullScreen(true);
stage.setTitle("Welcome User");
stage.setScene(new Scene(root, 631, 437));
stage.show();
}
catch(IOException ea)
{
System.out.println(ea.toString());
ea.printStackTrace();
}
}
}
return null;
}
};
bar.progressProperty().bind(task.progressProperty());
new Thread(task).start();
}

Resources