I would like to add a text area where the user can see some information that i can see in the console while the progress bar is updating.
How can i add the text area ?
Here is a sample of the code I have used to make the progress bar. Can i add below the progress bar the text area which should fill while computations are mare?
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class ProgressDialogExample extends Application {
static int option = 0;
static ProgressForm pForm = new ProgressForm();
#Override
public void start(Stage primaryStage) {
Button startButton = new Button("Start");
startButton.setOnAction(e -> {
// In real life this task would do something useful and return
// some meaningful result:
Task<Void> task = new Task<Void>() {
#Override
public Void call() throws InterruptedException {
for (int i = 0; i < 10; i++) {
updateProgress(i, 10);
Thread.sleep(200);
}
updateProgress(10, 10);
return null;
}
};
// binds progress of progress bars to progress of task:
pForm.activateProgressBar(task);
// in real life this method would get the result of the task
// and update the UI based on its value:
task.setOnSucceeded(event -> {
startButton.setDisable(false);
});
startButton.setDisable(true);
pForm.getDialogStage().show();
Thread thread = new Thread(task);
thread.start();
});
StackPane root = new StackPane(startButton);
Scene scene = new Scene(root, 350, 75);
primaryStage.setScene(scene);
primaryStage.show();
}
private int closeWindow() {
return option;
}
private static void setCloseWindow() {
// TODO Auto-generated method stub
option = 1;
}
public static class ProgressForm {
private final Stage dialogStage;
private final ProgressBar pb = new ProgressBar();
private final ProgressIndicator pin = new ProgressIndicator();
public ProgressForm() {
dialogStage = new Stage();
dialogStage.initStyle(StageStyle.UTILITY);
// dialogStage.setResizable(false);
// dialogStage.setWidth(400);
// dialogStage.setHeight(300);
// final VBox vbox = new VBox();
dialogStage.initModality(Modality.APPLICATION_MODAL);
final Button exitButton = new Button("Exit");
exitButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
pForm.getDialogStage().close();
setCloseWindow();
}
});
// PROGRESS BAR
pb.setProgress(-1F);
pin.setProgress(-1F);
final HBox hb = new HBox();
hb.setSpacing(5);
hb.setAlignment(Pos.CENTER);
hb.getChildren().addAll(pb, pin, exitButton);
Scene scene = new Scene(hb);
dialogStage.setScene(scene);
}
public void activateProgressBar(final Task<?> task) {
pb.progressProperty().bind(task.progressProperty());
pin.progressProperty().bind(task.progressProperty());
dialogStage.show();
}
public Stage getDialogStage() {
return dialogStage;
}
}
public static void main(String[] args) {
launch(args);
}
}
Have you heard of Label Labelled before use Label instead of the Text Node you want to use and write your text when you want to, when you want to show your Progressbars do
Label.setGraphic(myprogressbarNode);
Hope it helps
EDIT
I would like to add a text area where the user can see some information that i can see in the console while the progress bar is updating... Can i add below the progress bar the text area which should fill while computations are mare?
and i gave you a solution to it.
suppose you have your ProgressBar pb; and you are adding your ProgressBar to a StackPane you do not have to add the ProgressBar directly but rather add your Text which you will implement that by Label so presume your Label is lb this is how your code will look like
StackPane sp; // parent
ProgressBar pb; // progress indicator
Lable lb; // my text area
sp.getChildren().add(lb);// i have added the text area
lb.setGraphic(pb); we have added the progressbar to the text area
lb.setContentDisplay(ContentDisplay.***);//the *** represents the position you want your graphic
//whether top or left or bottom
//now you are done, your pb will show aligned to your lb, and be updated
//if you want to show text lb.setText("your text");
how implicit is this? :-)
Try adding a listener to the task's messageProperty that will append the text to a TextArea whenever it is changed.
TextArea ta = new TextArea();
public void activateTextArea(final Task<?> task) {
task.messageProperty().addListener((property, oldValue, newValue) -> {
ta.setText(ta.getText() + "\n" + newValue);
});
}
Then put something like this inside the task:
Task<Void> task = new Task<Void>() {
#Override
public Void call() throws InterruptedException {
for (int i = 0; i < 10; i++) {
updateProgress(i, 10);
updateMessage((i*10) + "% done");
Thread.sleep(200);
}
updateProgress(10, 10);
updateMessage("All done!");
return null;
}
};
Related
The program below makes use of the java fx class to create a graphical user interface to validate if a person is eligible to drink. The problem is that the output is displayed on the console not on the graphical user interface I. How do I fix this problem ?
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ValidateAge extends Application {
//Class Variables
Stage window;
Scene scene;
Button button;
//Main Methods
public static void main(String[] args) { // Main
launch(args);
}
#Override //Method that creates Graphical User Interface
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
window.setTitle("Validate Age For Drinking");// displays "Validate age" on top of window
TextField ageInput = new TextField();// Object for display text field
Label label1 = new Label();
button = new Button("Verify Age"); //Displays Verify Age Buttom
button.setOnAction( e -> isInt(ageInput, ageInput.getText() , label1));
//Parameters for Layouts
VBox layout = new VBox(10);
layout.setPadding(new Insets(20, 20, 20, 20)); //sets the size of the layout
layout.getChildren().addAll(ageInput, label1, button);
scene = new Scene(layout, 400, 550);//sets dimensions for scene
window.setScene(scene);
window.show();
}
//Validates user age
private int isInt(TextField input, String message, Label label){
// validates to see if user is above 18 to drink
try{
int age = Integer.parseInt(input.getText());
if(age< 18) {
label.setText("You are not allowed to drink");
}else {
System.out.println("You are allowed to drink");
}
}catch(NumberFormatException e){ // displays when user fails to type in a number
System.out.println("Error: " + message + " Tye in a number ");
}
return 0;
}
}
Instead of
System.out.println("You are allowed to drink");
put
label.setText("You are allowed to drink");
And you are good to go.
I was wondering if there was anyway to either find the index when a certain RadioButton is pressed or to pass myBuns.get(i) when the RadioButton. Using the code below to create the RadioButtons
RadioButton rButton;
for (i = 0; i < myBuns.size(); i ++){
rButton = new RadioButton("" + myBuns.get(i));
rButton.setToggleGroup(bunGroup);
rButton.setOnAction(this);
this.getChildren().add(rButton);
}
Thanks for any help or suggestions!
You can get the index of the selected toggle using:
toggleGroup.getToggles().indexOf(toggleGroup.getSelectedToggle());
And the text of the selected toggle using:
((RadioButton) toggleGroup.getSelectedToggle()).getText();
By placing the code in the change listener for the selected toggle property, you can monitor when the selected toggle changes and take action as appropriate.
Sample App
import javafx.application.Application;
import javafx.collections.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import java.util.stream.*;
public class ToggleIndexer extends Application {
#Override
public void start(final Stage stage) throws Exception {
ToggleGroup toggleGroup = new ToggleGroup();
ObservableList<RadioButton> buttons = IntStream.range(0, 5)
.mapToObj(i -> new RadioButton("Radio " + i))
.collect(Collectors.toCollection(FXCollections::observableArrayList));
toggleGroup.getToggles().setAll(buttons);
Label selectedIndex = new Label();
selectedIndex.setFont(Font.font("monospace"));
Label selectedItem = new Label();
selectedItem.setFont(Font.font("monospace"));
toggleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
if (newValue == null) {
selectedIndex.setText("");
selectedItem.setText("");
} else {
final int selectedIndexValue =
toggleGroup.getToggles().indexOf(newValue);
selectedIndex.setText("Selected Index: " + selectedIndexValue);
final String selectedItemText =
((RadioButton) toggleGroup.getSelectedToggle()).getText();
selectedItem.setText( "Selected Item: " + selectedItemText);
}
});
VBox layout = new VBox(8);
layout.setPadding(new Insets(10));
layout.setPrefWidth(250);
layout.getChildren().setAll(buttons);
layout.getChildren().addAll(selectedItem, selectedIndex);
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
I'm new to JavaFX but have a good understanding of object orientated Java. The following program is a combination of two examples, one that animates and moves shapes , the other animates an object on a mouse button press. Much of the functionality has been removed or changed for my needs.
I've searched through many examples but haven't found one I fully understand regarding moving a sprite and animating on key press.In my program I'm sure that I'm not using the right classes to create the game object, even though with some tweaking I'm sure it could work.
I added some println functions to test the animation. The problem seems to be that the KeyFrame part in the walkSouth animation isn't working/playing.
My question is:
Should I be using different JavaFX classes to create the sprite-sheet animation?
Can this code be easily adapted to function so I can get a better understanding of how JavaFX works.
Here is the main class:
package testing;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private enum UserAction{
NONE,NORTH,SOUTH;
}
private static int APP_W = 200;
private static int APP_H = 200;
private Scene scene;
private UserAction action = UserAction.NONE;
private Timeline timeline = new Timeline();
private boolean running = true;
private int FPS = 60;
private Parent createContent(){
Pane root = new Pane();
root.setPrefSize(APP_W,APP_H);
Image cat_image = new Image("file:res/cata.png");
GameObject obj = new GameObject(cat_image,12,8);
obj.setTranslateX(100);
obj.setTranslateY(100);
KeyFrame frame = new KeyFrame(Duration.millis(1000/FPS), event -> {
if(!running)
return;
switch(action){
case NORTH:
obj.setTranslateY(obj.getTranslateY()-1);
break;
case SOUTH:
obj.walkSouth();
obj.setTranslateY(obj.getTranslateY()+1);
break;
case NONE:
obj.pauseAnimation();
break;
}
});
timeline.getKeyFrames().add(frame);
timeline.setCycleCount(Timeline.INDEFINITE);
root.getChildren().add(obj);
return root;
}
private void restartGame(){
stopGame();
startGame();
}
private void stopGame(){
running = false;
timeline.stop();
}
private void startGame(){
timeline.play();
running = true;
}
public void start(Stage primaryStage) throws Exception{
scene = new Scene(createContent());
scene.setOnKeyPressed(event -> {
switch (event.getCode()) {
case W:
action = UserAction.NORTH;
break;
case S:
action = UserAction.SOUTH;
break;
}
});
scene.setOnKeyReleased(event -> {
switch (event.getCode()) {
case W:
action = UserAction.NONE;
break;
case S:
action = UserAction.NONE;
break;
}
});
primaryStage.setTitle("Simple Animation");
primaryStage.setScene(scene);
primaryStage.show();
startGame();
}
public static void main(String[] args) {
launch(args);
}
}
Here is the GameObject class:
package testing;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.Rectangle2D;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.util.Duration;
/**
* Created by matt on 26/02/17.
*/
public class GameObject extends Pane {
ObjectImage objectImage;
public GameObject( Image image, int columns, int rows){
objectImage = new ObjectImage(image,columns,rows);
getChildren().setAll(objectImage);
}
public void pauseAnimation(){
getChildren().setAll(objectImage);
objectImage.pauseAnimation();
}
public void walkSouth(){
getChildren().setAll(objectImage);
objectImage.walkSouth();
}
}
class ObjectImage extends ImageView {
private Rectangle2D[] clips;
private double width,height;
private Timeline timeline = new Timeline();
public ObjectImage(Image image,int columns,int rows){
width = image.getWidth()/columns;
height = image.getHeight()/rows;
clips = new Rectangle2D[rows*columns];
int count=0;
for(int row =0;row < rows;row++ )
for(int column = 0 ; column < columns; column++,count++)
clips[count] = new Rectangle2D(width * column, height * row,width,height);
setImage(image);
setViewport(clips[0]);
}
public void pauseAnimation(){
timeline.pause();
}
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
KeyFrame frame = new KeyFrame( Duration.millis(1000/5), event -> {
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
System.out.println("frame test");
});
timeline.setCycleCount(timeline.INDEFINITE);
timeline.getKeyFrames();
timeline.play();
}
}
This is the sprite-sheet image I'm working with
This is the outcome
As hinted by the comment, you did forget to add the frame in the walkSouth method. (Also you set each picture frame in walkSouth method to 200ms. Did you meant to change that?) Here's the code after changing:
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
KeyFrame frame = new KeyFrame( Duration.millis(1000/FPS), event -> {
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
});
timeline.setCycleCount(timeline.INDEFINITE);
timeline.getKeyFrames().add(frame); //This was the offending line.
timeline.play();
}
To answer your first question, yes there are many other options of classes you could use. Two options you could do is use the AnimationTimer or the Transition class. Here's a brief explanation for both (with code samples).
AnimationTimer is called every cycle or frame of rendering, which I believe you might be wanting this one:
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
AnimationTimer tmr = new AnimationTimer() {
#Override
public void handle(long nanoTime)
{
//nanoTime specifies the current time at the beginning of the frame in nano seconds.
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
}
};
tmr.start();
//call tmr.stop() to stop/ pause timer.
}
If however, you don't want an animation to be called each frame, you could extend Transition. A transition has an frac (fractional) value ranging from 0 to 1 that increases with respect to time. I'm not going to go into a whole lot detail, but I'm sure you could look up some more information on the api.
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
Transition trans = new Transition() {
{
setCycleDuration(Duration.millis(1000 / 60.0));
}
#Override
public void interpolate(double frac)
{
if (frac != 1)
return;
//End of one cycle.
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
}
};
trans.setCycleCount(Animation.INDEFINITE);
trans.playFromStart();
//Use trans.pause to pause, trans.stop to stop.
}
I have the following schema:
A VBox, containing a HBox and a TilePane.
In HBox are buttons, labels, and text fields.
Every time I click on the root (HBox), I should add a ImageView to the tile pane. This ImageView shold contain an image (example: "2.jpg"). Maximum of tile pane components is 5.
Every time I click the image, i should load a new image to the clicked ImageView, exemple "1.jpg". It is not working. When I click on my image it is like i'm clicking on the root so it creates another cell of TilePane. Here's the code, can you help me?
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package dadao1;
import java.util.HashSet;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.TilePane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/**
*
* #author Ambra
*/
public class Dadao1 extends Application {
VBox root;
HashSet dadi = new HashSet();
//static int numeroDadi = 0;
#Override
public void start(Stage primaryStage) {
setGui();
Scene scene = new Scene(root, 300, 300);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
*This private method sets up the GUI.
* No parameters are required
*/
private void setGui(){
root = new VBox();
HBox buttons = new HBox();
final Button newGame = new Button("New Game");
final Button print = new Button("Print");
final Button animation = new Button("Moving");
animation.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
// this button is labeled "Moving" at the begin. If pressed it changes its label to "Dissolving" and viceversa.
#Override
public void handle(ActionEvent event) {
if (animation.getText().equals(new String("Moving")))
animation.setText("Dissolving");
else animation.setText("Mooving");
}
});
final Label score = new Label("Total");
final TextField points = new TextField();
final Label pointsLabel = new Label("Score");
root.setStyle("-fx-background-color: green");
buttons.getChildren().addAll(newGame,print,animation,score,points,pointsLabel);
final TilePane dadiPane = new TilePane();
dadiPane.setVgap(10);
dadiPane.setHgap(10);
root.getChildren().addAll(buttons, dadiPane);
root.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if(dadi.size()<5){
System.out.println("Adding img");
final ImageView img = new ImageView("2.jpg");
// should I put final in front of ImageView?
img.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// I want that when a tile is pressed an event occours.
// that event should be "add a new image to the ImageView just clicked",
// for example: img is not "2.jpg" but "3.jpj", by the way, I'm not able neither
// to to print the folowing messagge :(
// It's like my root is pressed even if my mouse ha clicked at the image in img var.
System.out.println("Tile pressed ");
}
});
dadi.add(img);
dadiPane.getChildren().add(img);
}else System.out.println("You cannot create more than 5 dices");
}
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
ImageViews don't generate ActionEvents; so it is no surprise that your event handler is never invoked. Since the mouse event is not processed by the ImageView, it propagates up to the container.
Try
img.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("Tile pressed ");
event.consume();
}
});
#James_D is correct; but note for Java 8 you can use the simpler syntax:
img.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
System.out.println("Tile pressed ");
event.consume();
});
Note that MouseEvent.MOUSE_CLICKED is a class from javafx, not from java.awt.event package
imgView. addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, event -> {
//event clicked here
});
For someone who mistakenly import java.awt.event.MouseEvent class
I have a main menu in Blackberry application. I want to access different screens when I enter the menu items and need to come back to the main menu. How can I do it?
Here is what I tried but caught up a runtime exception when pressed Back button:
package com.stockmarket1;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.decor.*;
import net.rim.blackberry.api.push.PushApplication;
public class StockMarket extends UiApplication implements FieldChangeListener {
public Screen _clientList;
public Screen _comments;
public Runnable _popRunnable;
public static void main(String[] args)
{
StockMarket theApp = new StockMarket();
theApp.enterEventDispatcher();
}
public StockMarket() {
//Code for MainScreen
final MainScreen baseScreen = new MainScreen();
baseScreen.setTitle("Colombo Stock Exchange");
ButtonField clientList = new ButtonField("View Client List", ButtonField.CONSUME_CLICK);
clientList.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
pushScreen(_clientList);
}
});
ButtonField comments= new ButtonField("View Comments", ButtonField.CONSUME_CLICK);
comments.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
pushScreen(_comments);
}
});
Bitmap bitmap = Bitmap.getBitmapResource("logo1.png");
BitmapField logo = new BitmapField(bitmap, BitmapField.FIELD_HCENTER);
LabelField newLine = new LabelField("\n");
baseScreen.add(logo);
baseScreen.add(newLine);
baseScreen.add(clientList);
baseScreen.add(comments);
//Code for _comments
_comments = new FullScreen();
_comments.setBackground(BackgroundFactory.createSolidBackground(Color.LIGHTCYAN));
LabelField title = new LabelField("Comments",LabelField.FIELD_HCENTER);
LabelField comment = new LabelField("Type");
RichTextField rtfComment = new RichTextField();
_comments.add(title);
_comments.add(comment);
_comments.add(rtfComment);
//Code for _clientList
_clientList = new FullScreen();
_clientList.setBackground(BackgroundFactory.createSolidBackground(Color.LIGHTBLUE));
LabelField clientTitle = new LabelField("Listed Companies\n\n", LabelField.FIELD_HCENTER);
LabelField line = new LabelField("__", LabelField.USE_ALL_HEIGHT);
ButtonField closeClient = new ButtonField("Close", ButtonField.CONSUME_CLICK);
closeClient.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
pushScreen(baseScreen);
}
});
_clientList.add(clientTitle);
_clientList.add(line);
//Events
pushScreen(baseScreen);
}
public void fieldChanged(Field field, int context) {
// TODO Auto-generated method stub
}
}
The code for your 'Close' button is a problem, but I think you said you get a RuntimeException when hitting the 'back' button on the device, which I think has a different cause.
Instead of pushing the menu screen onto the screen stack, you should just pop the current screen. This will return to the menu screen that was displayed previously:
closeClient.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
// previous code:
// pushScreen(baseScreen);
// correct code:
popScreen(_clientList);
}
});