TimeLINE javaFX thread - java

At the moment I have a list with images which get displayed for a certain amount of time with a timeline. However I want that a counter is set for each picture i.e. if the amount of time is 30 sec for each picture, there should be a countdown running and showing underneath the picture? Is there a way to achieve that behavior?
Image i1 = new Image(getClass().getResourceAsStream("IMG_YOGA/01.png"),200,200,false,false);
Image i2 = new Image(getClass().getResourceAsStream("IMG_YOGA/02.png"),200,200,false,false);
Image i3 = new Image(getClass().getResourceAsStream("IMG_YOGA/03.png"),200,200,false,false);
Image i4 = new Image(getClass().getResourceAsStream("IMG_YOGA/04.png"),200,200,false,false);
Image i5 = new Image(getClass().getResourceAsStream("IMG_YOGA/05.png"),200,200,false,false);
Image i6 = new Image(getClass().getResourceAsStream("IMG_YOGA/06.png"),200,200,false,false);
Image i7 = new Image(getClass().getResourceAsStream("IMG_YOGA/07.png"),200,200,false,false);
Image i8 = new Image(getClass().getResourceAsStream("IMG_YOGA/08.png"),200,200,false,false);
Y_ImgView.setFitWidth(250);
Y_ImgView.setFitHeight(300);
final int NUM_FRAMES = 9;
final int PAUSE_BETWEEN_FRAMES = 30;
Timeline timeline = new Timeline();
List<Image> images = List.of(i1,i2,i3,i4,i5,i6,i7,i8,i1);
for (int i = 0; i < NUM_FRAMES; i++) {
timeline.getKeyFrames().add(
new KeyFrame(
javafx.util.Duration.seconds(i * PAUSE_BETWEEN_FRAMES),
new KeyValue(Y_ImgView.imageProperty(), images.get(i))
)
);
}
timeline.setCycleCount(1);
timeline.play();
}

Try something like
IntegerProperty countdown = new SimpleIntegerProperty();
Label countdownLabel = new Label();
countdownLabel.textProperty().bind(countdown.asString());
// add label to layout
and then
Timeline timeline = new Timeline();
List<Image> images = List.of(i1,i2,i3,i4,i5,i6,i7,i8,i1);
for (int i = 0; i < NUM_FRAMES; i++) {
timeline.getKeyFrames().add(
new KeyFrame(
javafx.util.Duration.seconds(i * PAUSE_BETWEEN_FRAMES),
new KeyValue(Y_ImgView.imageProperty(), images.get(i)),
new KeyValue(countdown, 0),
new KeyValue(countdown, PAUSE_BETWEEN_FRAMES)
)
);
}

Related

How to raise an int in a string in Java?

I am making a storybook and, because I'm not very creative with names, I gave images page numbers like so.
ImageIcon pg1icon = new ImageIcon("images/1.png");
ImageIcon pg2icon = new ImageIcon("images/2.png");
ImageIcon pg3icon = new ImageIcon("images/3.png");
JLabel pg1Label = new JLabel(pg1icon);
JLabel pg2Label = new JLabel(pg2icon);
JLabel pg3Label = new JLabel(pg3icon);
Because I have 30 pages, this process is getting tedious. Is there a way to scale the page num similar to i++?
Using streams we can handle this requirement concisely as:
List<JLabel> labels = IntStream.rangeClosed(1, 30)
.mapToObj(i -> new JLabel(new ImageIcon("images/" + i + ".png")))
.collect(Collectors.toList());
Assuming you only need the ImageIcon for the JLabel, you could use one array to store your thirty JLabel(s). Like,
int pageCount = 30;
JLabel[] labels = new JLabel[pageCount];
for (int i = 0; i < pageCount; i++) { // <-- i++ as requested
ImageIcon icon = new ImageIcon(String.format("images/%d.png", 1+i));
labels[i] = new JLabel(icon);
}
And then use labels[0] - labels[29] instead of pg1Label - pg30Label.

JavaFX z-buffer issues

I'm filling a container with a lot of small boxes and the problem is that you can see trough them from some angles. I've already enabled the depth buffer, but that doesn't work.
The code that handles this part is split into 3. setupUIPreElements sets everything up, setupUIElements adds the boxes and setupUIPostElements adds the container and some camera stuff.
public static void setupUIPreElements(Stage stage){
//Setup grids, groups, scenes, camera and such so that the scene is made from scratch
topGrid = new GridPane();
twoDGroup = new Group();
threeDGroup = new SmartGroup();
root = new HBox();
mainScene = new Scene(root, SCREEN_WIDTH, SCREEN_HEIGHT, true, SceneAntialiasing.BALANCED);
twoD = new SubScene(twoDGroup, SCREEN_WIDTH*.2, SCREEN_HEIGHT);
threeD = new SubScene(threeDGroup, SCREEN_WIDTH*.8, SCREEN_HEIGHT);
anchorAngleX = 0;
anchorAngleY = 0;
angleX = new SimpleDoubleProperty(0);
angleY = new SimpleDoubleProperty(0);
camera = new PerspectiveCamera();
pins = new ProgressIndicator[1];
pin = pins[0] = new ProgressIndicator();
parcels = new ArrayList<UIParcel>();
//add subscenes to scene
root.getChildren().addAll(twoD, threeD);
root.setSpacing(10);
root.setPadding(new Insets(20, 20, 20, 20));
/*START Setup top menu*/
//Setup grid
topGrid.setHgap(10);
topGrid.setVgap(10);
//Setup items
//Add scoring label
scoringLabel = new Label("Score: " + Wrapper.score);
startButton = new Button("Start");
modeSelection = new ChoiceBox(FXCollections.observableArrayList(
"Parcels", "Pentominoes"
));
modeSelection.setValue("");
//Parcel selection UI
ParcelAAmountLabel = new Label("Amount of parcel A: ");
ParcelBAmountLabel = new Label("Amount of parcel B: ");
ParcelCAmountLabel = new Label("Amount of parcel C: ");
ParcelAAmountTextField = new TextField();
ParcelBAmountTextField = new TextField();
ParcelCAmountTextField = new TextField();
ParcelAValueLabel = new Label("Value of parcel A: ");
ParcelBValueLabel = new Label("Value of parcel B: ");
ParcelCValueLabel = new Label("Value of parcel C: ");
ParcelAValueTextField = new TextField();
ParcelBValueTextField = new TextField();
ParcelCValueTextField = new TextField();
//Pentominoe selection UI
LPentominoAmountLabel = new Label("Amount of L pentominoes: ");
PPentominoAmountLabel = new Label("Amount of P pentominoes: ");
TPentominoAmountLabel = new Label("Amount of T pentominoes: ");
LPentominoAmountTextField = new TextField();
PPentominoAmountTextField = new TextField();
TPentominoAmountTextField = new TextField();
LPentominoValueLabel = new Label("Value of L pentominoes: ");
PPentominoValueLabel = new Label("Value of P pentominoes: ");
TPentominoValueLabel = new Label("Value of T pentominoes: ");
LPentominoValueTextField = new TextField();
PPentominoValueTextField = new TextField();
TPentominoValueTextField = new TextField();
//-1 will make it display an animated disk, set to 1 to show that it's done
//pin is the progress indicator
pin.setProgress(-1);
topGrid.add(scoringLabel, 0, 0);
topGrid.add(modeSelection, 0, 1);
topGrid.add(startButton, 0, 8);
twoDGroup.getChildren().add(topGrid);
/*END*/
//Set materials
container_material.setDiffuseColor(CONTAINER_COLOR);
edge_material.setDiffuseColor(EDGE_COLOR);
}
public static void setupUIElements(Stage stage, int[][][] resultBoxesArray){
//TODO check if I can assume the IDs to be either 1, 2 or 3 if filled in or 0 if not
int colorStart = 0;
int colorEnd = 0;
//give every filled in field a box representation and keep color in mind
//create all the boxes
for(int x=0; x<resultBoxesArray.length; x++){
for(int y=0; y<resultBoxesArray[x].length; y++){
for(int z=0; z<resultBoxesArray[x][y].length; z++){
int currentValue = resultBoxesArray[x][y][z];
//if this field is filled
if(currentValue!=0){
//update color range
if(currentValue==1){
colorStart = 0;
colorEnd = 70;
} else if (currentValue==2){
colorStart = 85;
colorEnd = 155;
} else {
colorStart = 170;
colorEnd = 255;
}
//50 is used because that is the size that is given for each cell in the array
UIParcel cellBox = new UIParcel(x*50, y*50, z*50, 50, 50, 50, colorStart, colorEnd);
parcels.add(cellBox);
}
}
}
}
//show them
threeDGroup.getChildren().addAll(parcels);
}
public static void setupUIPostElements(Stage stage){
//Create container (note: Has to be created after adding all the other objects in order to use transparency (I know, javaFX can be crappy))
Box container = new Box(Wrapper.CONTAINER_WIDTH, Wrapper.CONTAINER_HEIGHT, Wrapper.CONTAINER_DEPTH);
container.setTranslateX(Wrapper.CONTAINER_WIDTH/2);
container.setTranslateY(Wrapper.CONTAINER_HEIGHT/2);
container.setTranslateZ(Wrapper.CONTAINER_DEPTH/2);
container.setMaterial(container_material);
threeDGroup.getChildren().add(container);
//Setup camera (so that you can have the container at the origin and can still see it well
//The +threeDOffsetLeft comes from the compensation for the 2D subscene on the left
camera.setTranslateX(-SCREEN_WIDTH/2+Wrapper.CONTAINER_WIDTH/2+threeDOffsetLeft);
camera.setTranslateY(-SCREEN_HEIGHT/2+Wrapper.CONTAINER_HEIGHT/2);
camera.setTranslateZ(-Wrapper.CONTAINER_DEPTH/0.5);
//Setup mouse rotation
initMouseControl(threeDGroup, mainScene, stage);
//Set eventListener for mode selection
modeSelection.getSelectionModel().selectedItemProperty().addListener((v, oldValue, newValue) -> {
//check what mode was selected and show the corresponding options
if(newValue.equals("Parcels")){
//remove other option
if(oldValue.equals("Pentominoes")){
topGrid.getChildren().removeAll(LPentominoAmountLabel, PPentominoAmountLabel, TPentominoAmountLabel, LPentominoAmountTextField, PPentominoAmountTextField, TPentominoAmountTextField, LPentominoValueLabel, PPentominoValueLabel, TPentominoValueLabel, LPentominoValueTextField, PPentominoValueTextField, TPentominoValueTextField);
}
//add labels
topGrid.add(ParcelAAmountLabel, 0, 2);
topGrid.add(ParcelBAmountLabel, 0, 4);
topGrid.add(ParcelCAmountLabel, 0, 6);
topGrid.add(ParcelAValueLabel, 0, 3);
topGrid.add(ParcelBValueLabel, 0, 5);
topGrid.add(ParcelCValueLabel, 0, 7);
//add text fields
topGrid.add(ParcelAAmountTextField, 1, 2);
topGrid.add(ParcelBAmountTextField, 1, 4);
topGrid.add(ParcelCAmountTextField, 1, 6);
topGrid.add(ParcelAValueTextField, 1, 3);
topGrid.add(ParcelBValueTextField, 1, 5);
topGrid.add(ParcelCValueTextField, 1, 7);
} else if (newValue.equals("Pentominoes")){
//remove other option
if(oldValue.equals("Parcels")){
topGrid.getChildren().removeAll(ParcelAAmountLabel, ParcelBAmountLabel, ParcelCAmountLabel, ParcelAAmountTextField, ParcelBAmountTextField, ParcelCAmountTextField, ParcelAValueLabel, ParcelBValueLabel, ParcelCValueLabel, ParcelAValueTextField, ParcelBValueTextField, ParcelCValueTextField);
}
//add labels
topGrid.add(LPentominoAmountLabel, 0, 2);
topGrid.add(PPentominoAmountLabel, 0, 4);
topGrid.add(TPentominoAmountLabel, 0, 6);
topGrid.add(LPentominoValueLabel, 0, 3);
topGrid.add(PPentominoValueLabel, 0, 5);
topGrid.add(TPentominoValueLabel, 0, 7);
//add text fields
topGrid.add(LPentominoAmountTextField, 1, 2);
topGrid.add(PPentominoAmountTextField, 1, 4);
topGrid.add(TPentominoAmountTextField, 1, 6);
topGrid.add(LPentominoValueTextField, 1, 3);
topGrid.add(PPentominoValueTextField, 1, 5);
topGrid.add(TPentominoValueTextField, 1, 7);
}
});
//Set evenListener for start button
startButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event-> {
//Show loading circle (that was created at the start)
topGrid.add(pin, 0, 9);
//TODO use values from the textFields as input
//TODO start calculations
//TODO remove after testing
test.giveInput();
});
threeD.setCamera(camera);
stage.setTitle("Filling 3D objects");
threeD.setFill(BACKGROUND_COLOR);
stage.setScene(mainScene);
stage.show();
}
From the angle that works as desired is looks like this:
From the angle that doesn't work properly it looks like this:
Note that the boxes are added as UIParcel, this is just a class that extends the regular Box with some extra info, it doesn't effect any 3D stuff.
The solution was to also enable depth buffering for the SubScene that contained the 3D elements, it doesn't just follow the settings from the mainScene.
threeD = new SubScene(threeDGroup, SCREEN_WIDTH*.8, SCREEN_HEIGHT);
becomes
threeD = new SubScene(threeDGroup, SCREEN_WIDTH*.8, SCREEN_HEIGHT, true, SceneAntialiasing.BALANCED);
Setting the SceneAntialiasing is also required by the SubScene constructor.

javafx Array of Images Randomly Displayed BINGO

I am trying to get my list of images to display on a 5x5 grid. I cannot figure out what the issue is.
This is the assignment instructions:
Assignment:
Create image BINGO. Using the exercise 14.1 page 586 as a foundation: Write a program that randomly displays images on a Bingo card. This should be a 5X5 grid with the letters B I N G O across the top.
//package
package javafxapplication2;
//import
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.scene.image.ImageView;
import javafx.scene.image.Image;
/**
*
* #author travis.dutton
*/
public class JavaFXApplication2 extends Application {
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setHgap(5);
pane.setVgap(5);
ImageView flags[];
flags = new ImageView[25];
flags[0] = new ImageView("images/1.png");
flags[1] = new ImageView("images/2.jpg");
flags[2] = new ImageView("images/3.gif");
flags[3] = new ImageView("images/4.gif");
flags[4] = new ImageView("images/5.jpg");
flags[5] = new ImageView("images/6.png");
flags[6] = new ImageView("images/7.gif");
flags[7] = new ImageView("images/8.jpg");
flags[8] = new ImageView("images/9.png");
flags[9] = new ImageView("images/10.png");
flags[10] = new ImageView("images/11.jpg");
flags[11] = new ImageView("images/12.png");
flags[12] = new ImageView("images/13.png");
flags[13] = new ImageView("images/14.png");
flags[14] = new ImageView("images/15.png");
flags[15] = new ImageView("images/16.png");
flags[16] = new ImageView("images/17.gif");
flags[17] = new ImageView("images/18.gif");
flags[18] = new ImageView("images/19.png");
flags[19] = new ImageView("images/20.jpg");
flags[20] = new ImageView("images/21.png");
flags[21] = new ImageView("images/22.png");
flags[22] = new ImageView("images/23.png");
// flags[23] = new ImageView("images/24.gif");
// flags[24] = new ImageView("images/25.png");
// pane.add(flags[0], 0, 0);
// pane.add(imageView2, 1, 0);
// pane.add(imageView3, 0, 1);
// pane.add(imageView4, 1, 1);
// for(int i = 0; i < flags.length; i++){
//
// GridPane.setRowIndex(flags[i],1);
// GridPane.setColumnIndex(flags[i],i);
// pane.getChildren().add(flags[i]);
// }
for(int i = 0; i < 5; i++){
for (int j = 0; j < 5; j++) {
ImageView image = new ImageView();
image.setColumnIndex(1);
image.getChildren(String.valueOf(flags));
pane.add(image, i, j);
}
}
// Create a scene and place it in the stage
Scene scene = new Scene(pane);
primaryStage.setTitle("Exercise14_01"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);//launch javafx
}//end main
}//end of class
ImageView does not provide a getChildren method. (I don't know a JavaFX class that provides one that takes a String parameter btw). ImageViews are nodes and should be placed in the GridPane directly using the GridPane.add(Node, int, int) method.
You can use Collections.shuffle to generate the premutation:
String[] images = new String[] {
"images/1.png",
"images/2.jpg",
...
"images/25.png"
};
// using a list with indices here to keep the original index order intact.
// (You could use a list of String and shuffle it otherwise)
List<Integer> permutation = IntStream.range(0, images.length).boxed().collect(Collectors.toCollection(ArrayList::new));
Collections.shuffle(permutation);
for(int i = 0, index = 0; i < 5; i++){
for (int j = 1; j <= 5; j++) {
ImageView image = new ImageView(images[permutation.get(index)]);
pane.add(image, i, j);
index++;
}
}
// bingo accross the top (not sure if this is what was asked for)
pane.add(new Label("Bingo"), 0, 0, 5, 1);
If you want put random images to GridPane, like:
you have to do something like this:
final ArrayList<ImageView> flags = new ArrayList<>();
flags.add(new ImageView("images/1.png"));
flags.add(new ImageView("images/2.png"));
flags.add(new ImageView("images/3.png"));
// add flags
for (int columnIndex = 0; columnIndex < 5; i++) {
for (int rowIndex = 0; rowIndex < 5; j++) {
if(isNotBingoCell(columnIndex, rowIndex)) { //check that cell is not BINGO cell
final int imageIndex = Objects.equals(flags.size(), 1)
? 0
: ThreadLocalRandom.current().nextInt(0, flags.size() - 1);
pane.add(flags.get(imageIndex), columnIndex, rowIndex);
flags.remove(imageIndex);
flags.trimToSize();
}
}
}
, isNotBingoCell(...) implemintation:
private boolean isNotBingoCell(int columnIndex, int rowIndex) {
return !Objects.equals(columnIndex, rowIndex);
}

Add background color to TextView in Android studio

I'm trying to add a background color to two TextViews in Android studio, one is supposed to be red, and the other one is supposed to be blue. I currently have it set to random.
public void buildGuiByCode( Activity activity, int width, int height,
int numberOfPieces )
{
positions = new int[numberOfPieces];
tvs = new TextView[numberOfPieces];
colors = new int[tvs.length];
params = new LayoutParams[tvs.length];
Random random = new Random( );
labelHeight = height ;
labelwidth = width / numberOfPieces;
for( int i = 0; i < tvs.length; i++ ) {
tvs[i] = new TextView( activity );
tvs[i].setGravity( Gravity.CENTER);
colors[i] = Color.rgb( random.nextInt(255 ),
random.nextInt(255 ), random.nextInt(255 ) );
tvs[i].setBackgroundColor( colors[i] );
params[i] = new LayoutParams( labelwidth, height );
params[i].topMargin = 0;
params[i].leftMargin = labelwidth * i;
addView( tvs[i], params[i] );
}
}
You can use setBackgroundResource for setting up the background color. Here is a snippet.
TextView textView = new TextView(activity);
textView.setBackgroundResource(R.color.red);
Refer to this official doc

Sprites array merges the when rendering sprites

Sprite bucketImage, background, r1, r2, r5,
r10, r20, r50, r100, r200, r500, k1, k2, k5, k10, k20, k50;
I create objects in the method called spawnRaindrop(). I have an array of sprites and I want to sprites were changed in the cycle as it is now, it works, but the images are merged with each other.
sprites = new Sprite[15];
r1 = new Sprite(atlas.findRegion("r1"));
r1.flip(false, true);
r2 = new Sprite(atlas.findRegion("r2"));
r2.flip(false, true);
r5 = new Sprite(atlas.findRegion("r5"));
r5.flip(false, true);
r10 = new Sprite(atlas.findRegion("r10"));
r10.flip(false, true);
r20 = new Sprite(atlas.findRegion("r20"));
r20.flip(false, true);
r50 = new Sprite(atlas.findRegion("r50"));
r50.flip(false, true);
r100 = new Sprite(atlas.findRegion("r100"));
r100.flip(false, true);
r200 = new Sprite(atlas.findRegion("r200"));
r200.flip(false, true);
r500 = new Sprite(atlas.findRegion("r500"));
r500.flip(false, true);
k1 = new Sprite(atlas.findRegion("k1"));
k1.flip(false, true);
k2 = new Sprite(atlas.findRegion("k2"));
k2.flip(false, true);
k5 = new Sprite(atlas.findRegion("k5"));
k5.flip(false, true);
k10 = new Sprite(atlas.findRegion("k10"));
k10.flip(false, true);
k20 = new Sprite(atlas.findRegion("k20"));
k20.flip(false, true);
k50 = new Sprite(atlas.findRegion("k50"));
k50.flip(false, true);
sprites[0] = r1;
sprites[1] = r2;
sprites[2] = r5;
sprites[3] = r10;
sprites[4] = r20;
sprites[5] = r50;
sprites[6] = r100;
sprites[7] = r200;
sprites[8] = r500;
sprites[9] = k1;
sprites[10] = k2;
sprites[11] = k5;
sprites[12] = k10;
sprites[13] = k20;
sprites[14] = k50;
Create game object
private void spawnRaindrop() {
Rectangle raindrop = new Rectangle();
raindrop.x = MathUtils.random(0, 800 - 100);
raindrop.y = 480;
raindrop.width = 100;
raindrop.height = 100;
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
}
Create and draw array sprite
game.batch.draw(bucketImage, bucket.x, bucket.y);
for (Rectangle raindrop : raindrops) {
for (int i = 0; i < sprites.length - 1; i++) {
game.batch.draw(sprites[i], raindrop.x, raindrop.y);
}
}
game.batch.end();
RESULT:
I attached the picture, and it can be seen that the images accumulate on each other
It looks like your problem is that you are using the same raindrop.x and raindrop.y coordinates for all sprites!
for (Rectangle raindrop : raindrops)
{
for (int i = 0; i < sprites.length - 1; i++)
{
// The following will draw ALL sprites at the same location!
game.batch.draw(sprites[i], raindrop.x, raindrop.y);
}
}
What you can try is to create a new class called (for example): Raindrops and then in this class maintain a single x,y coordinate for each individual image:
class Raindrop
{
Vector2 coordinates;
Sprite sprite;
}
Then in your spawnRaindrop method, create an array of these Raindrop's and an individual (random?) image for each.
EDIT: I wrote the following code directly here without testing anything, so it will most likely have some errors, but nothing you shouldn't be able to fix yourself...
// This goes into your initialisation method
String regions[] = {"r1", "r2", "r5", "r10", "etc etc etc"}
Raindrop raindrops[] = new Raindrop[15];
for ( int i = 0; i < raindrops.length; i++ )
{
raindrop[i] = new Raindrop();
raindrop[i].coordinate.x = MathUtils.random(screenWidth);
raindrop[i].coordinate.y = MathUtils.random(screenHeight);
raindrop[i].sprite = atlas.findRegion(regions[(int)MathUtils.random(regions.length)]);
}
Then your main loop should look something like this:
game.batch.draw(bucketImage, bucket.x, bucket.y);
for ( Raindrop raindrop : raindrops )
{
game.batch.draw(raindrop.sprite, raindrop.coordinate.x, raindrop.coordinate.y);
}
game.batch.end();

Categories