The scrollTo method in the code below works really slow. Is there any way to speed up it or may be some alternative variant? I need to display almost 100000 items in the application. Probably there are some alternative components. Thanks.
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
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 stage) throws Exception {
final ListView<String> listView = new ListView<>();
Button button = new Button("goto");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
int i = 99998;
System.out.println("before scroll");
long startTime = System.currentTimeMillis();
listView.scrollTo(i);
long elapsedTime = System.currentTimeMillis() - startTime;
System.out.println(elapsedTime);
listView.getFocusModel().focus(i);
}
});
List<String> items = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
items.add(UUID.randomUUID().toString());
}
listView.setItems(FXCollections.observableArrayList(items));
StackPane pane = new StackPane();
VBox vbox = new VBox();
vbox.getChildren().add(button);
vbox.getChildren().add(listView);
pane.getChildren().add(vbox);
stage.setScene(new Scene(pane));
stage.show();
}
}
Related
Here my code (In Java on Eclipse) displays 3 random cards from the a file. I am trying to get a shuffle button to work and randomly shuffle in 3 new cards. I used "Collections.shuffle(cards);" and passed it my boolean array but it says I can't because it wants a List<> list. Is it possible to get the shuffle to work with my boolean or would I have to use a List?
Here is my code:
import java.util.Collections;
import java.util.List;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class DisplayCards extends Application {
HBox imageViews;
#Override
public void start(Stage primaryStage) throws Exception {
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
boolean[] cards = new boolean[52];
int count = 0;
while(count <3) {
int card = (int)(Math.random() * 52);
if(!cards[card]) {
cards[card] = true;
pane.add(new ImageView(new Image("card/" + (card) + ".png")), count, 0);
count++;
}
}
imageViews = new HBox();
imageViews.setAlignment(Pos.CENTER);
shuffle();
Button btnShuffle = new Button("Shuffle");
btnShuffle.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
shuffle();
}
});
BorderPane Bpane = new BorderPane();
Bpane.setCenter(imageViews);
Bpane.setBottom(btnShuffle);
Scene scene = new Scene(pane, 250, 150);
primaryStage.setTitle("Display 4 Cards");
primaryStage.setScene(scene);
primaryStage.show();
}
private void shuffle() {
Collections.shuffle(cards);
}
public static void main(String[] args) {
launch(args);
}
}
You can implement the Fisher–Yates shuffle for an array.
private void shuffle(){
for(int i = cards.length - 1; i > 0; i--){
int j = java.util.concurrent.ThreadLocalRandom.current().nextInt(i + 1);
boolean temp = cards[i];
cards[i] = cards[j];
cards[j] = temp;
}
}
import java.time.DayOfWeek;
import java.time.LocalDate;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.control.Button;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.scene.layout.VBox;
public class Example extends Application {
#Override public void start(Stage stage) {
VBox container = new VBox();
DatePicker datePicker = new DatePicker();
disableSomeDates(datePicker);
Button disableMondaysButton = new Button("No Mondays!");
disableMondaysButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
disableSomeMoreDates(datePicker);
}
});
container.getChildren().add(datePicker);
container.getChildren().add(disableMondaysButton);
Scene scene = new Scene(container);
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
public void disableSomeDates(DatePicker datePicker) {
datePicker.setDayCellFactory(param -> new DateCell() {
#Override
public void updateItem(LocalDate date, boolean empty) {
super.updateItem(date, empty);
//Disables dates before current date
setDisable(empty || date.compareTo(LocalDate.now()) < 0 );
}
});
}
public void disableSomeMoreDates(DatePicker datePicker) {
datePicker.setDayCellFactory(param -> new DateCell() {
#Override
public void updateItem(LocalDate date, boolean empty) {
super.updateItem(date, empty);
//Disables mondays
setDisable(empty || date.getDayOfWeek() == DayOfWeek.MONDAY);
}
});
}
}
In this example code I create a DatePicker and disable some dates (dates before today). Then by pressing the button it should disable Mondays and thus we should have all dates before today and all mondays disabled. In this case we'll end up with only mondays disabled.
How do I make it so that the button disables mondays without re-enabling dates before today?
I'd recommend using a single cell factory, generating cells which observe properties that can then be changed.
E.g.:
import java.time.DayOfWeek;
import java.time.LocalDate;
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Example extends Application {
#Override public void start(Stage stage) {
BooleanProperty mondaysDisabled = new SimpleBooleanProperty(false);
VBox container = new VBox();
DatePicker datePicker = new DatePicker();
datePicker.setDayCellFactory(dp -> new DateCell() {
{
mondaysDisabled.addListener((obs, mondaysWereDisabled, mondaysAreNowDisabled)
-> updateDisabledStatus());
}
#Override
public void updateItem(LocalDate date, boolean empty) {
super.updateItem(date, empty);
updateDisabledStatus();
}
private void updateDisabledStatus() {
if (isEmpty()) {
setDisable(true);
} else {
LocalDate date = getItem();
if (date.isBefore(LocalDate.now())) {
setDisable(true);
} else {
if (mondaysDisabled.get() && date.getDayOfWeek() == DayOfWeek.MONDAY) {
setDisable(true);
} else {
setDisable(false);
}
}
}
}
});
Button disableMondaysButton = new Button("No Mondays!");
disableMondaysButton.setOnAction(event -> mondaysDisabled.set(true));
container.getChildren().add(datePicker);
container.getChildren().add(disableMondaysButton);
Scene scene = new Scene(container);
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
For something of a more modular approach, you could keep an observable list of filters to check. E.g.
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.function.Predicate;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Example extends Application {
#Override public void start(Stage stage) {
ObservableList<Predicate<LocalDate>> dayFilters = FXCollections.observableArrayList();
dayFilters.add(date -> date != null);
dayFilters.add(date -> ! date.isBefore(LocalDate.now()));
VBox container = new VBox();
DatePicker datePicker = new DatePicker();
datePicker.setDayCellFactory(dp -> new DateCell() {
{
dayFilters.addListener((Change<? extends Predicate<LocalDate>> change) -> updateDisabledStatus());
}
#Override
public void updateItem(LocalDate date, boolean empty) {
super.updateItem(date, empty);
updateDisabledStatus();
}
private void updateDisabledStatus() {
setDisable(false);
for (Predicate<LocalDate> check : dayFilters) {
if (! check.test(getItem())) {
setDisable(true);
break ;
}
}
}
});
Button disableMondaysButton = new Button("No Mondays!");
disableMondaysButton.setOnAction(event -> dayFilters.add(date -> date.getDayOfWeek() != DayOfWeek.MONDAY));
container.getChildren().add(datePicker);
container.getChildren().add(disableMondaysButton);
Scene scene = new Scene(container);
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
I need some help if you can spare a few minutes.
I am in a bit of a pickle as I try to make this work.
I have a javaFX class like this
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.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class FoorballTeam extends Application {
int i1=0;
int i3=0;
String[] PlayerNames = new String[12];
int[] goals = new int[12];
#Override
public void start(Stage primaryStage) {
player[] playerData = new player[12];
Button btn = new Button();
btn.setText("add Player");
GridPane root = new GridPane();
root.add(btn,0,0);
int i2;
for (i2=0;i2<=11;i2++)
{playerData[i2]=new player();}
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
playerData[i3].player(root, i3);
i3++;
}
});
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public String[] getPlayerNames() {
return PlayerNames;
}
public void setPlayerNames(String[] PlayerNames) {
this.PlayerNames = PlayerNames;
}
public int[] getGoals() {
return goals;
}
public void setGoals(int[] goals) {
this.goals = goals;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
and a second class named player like this
import javafx.event.EventType;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
public class player {
String NameOfPlayer = new String();
int goalsOfPlayer;
public void player (GridPane root,int numberOfPlayer)
{
TextField name = new TextField();
TextField goals = new TextField();
GridPane grid = new GridPane();
grid.add(name,0,0);
grid.add(goals,1,0);
root.add(grid,0,numberOfPlayer+1);
System.out.println("player " + numberOfPlayer + " added");
name.textProperty().addListener((observable, oldValue, newValue) -> {
NameOfPlayer=newValue;
});
goals.textProperty().addListener((observable, oldValue, newValue) -> {
goalsOfPlayer=Integer.parseInt(newValue);
});
}
}
I want every time that I make a change to a players name or goals to pass this change on the two arrays PlayerNames[] and goals[] of the main class.
for example if player1 changes goals from 1 to 2 I want the goals[1]=2.
Also is it possible to put a listener to this two arrays so when a player changes name or goals to trigger the listener.
Any help will be appreciated.
One simple solution is to warp the int[] array with an observable list, and listen to changes in this list :
import java.util.Arrays;
import java.util.Random;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class ListenToArrayCahnges extends Application {
private final int SIZE = 12;
private final Integer[] goals = new Integer[SIZE];
private final Random rand = new Random();
private int counter = 0;
#Override
public void start(Stage primaryStage) {
Arrays.fill(goals, 0); //initial values
//Warp array with an observable list. list back by array so it is of fixed length
ObservableList<Integer> goalsList = FXCollections.observableArrayList(Arrays.asList(goals));
//add listener to list
goalsList.addListener((ListChangeListener<Integer>) c ->{
//respond to list changes
System.out.println("Goals changed to : "+ goalsList);
});
//button to change the list
Button btn = new Button();
btn.setText("Add goal");
btn.setOnAction(event -> {
goalsList.set(counter, rand.nextInt(100));
counter = ++counter % SIZE ; //increment counter 0,1,2....11 and back to 0
});
GridPane root = new GridPane();
root.add(btn,0,0);
Scene scene = new Scene(root, 150, 50);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Note that the posted mcve represents the problem that needs to be solved (or in this case a solution to it), and not the specific application or use case.
Hi I'm trying to get my progress bar to update as a process is happening. Copying a file. I am also outputting to the console but my progress bar won't update until it has finished the process.
What am I doing wrong? here is my code, it is one file.
package tvconvertversion3;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
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.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.control.ProgressBar;
/**
*
* #author brett
*/
public class CreateWorkFile extends Application {
private final File fileIn = new File("C:\\Users\\brett\\Documents\\Humans Need Not Apply-7Pq-S557XQU.mp4");
private Task task;
private File fileOut;
private ProgressBar mpgb;
#Override
public void start(Stage primaryStage) {
mpgb = new ProgressBar();
mpgb.setVisible(true);
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!");
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
}
});
task = new Task<Integer>() {
#Override
protected Integer call() throws Exception {
fileOut = new File("C:\\Users\\brett\\Documents\\ConvertedTvFiles\\Tenacious D - 39 HQ-86LT83IFDfQ.mp4");
try {
FileInputStream fin;
long length = fileIn.length();
long counter = 0;
int r;
byte[] b = new byte[1024];
fin = new FileInputStream(fileIn);
FileOutputStream fout = new FileOutputStream(fileOut);
while ((r = fin.read(b)) != -1) {
mpgb.setProgress(100 * counter / length);
counter += r;
System.out.println(1.0 * counter / length);
fout.write(b, 0, r);
}
} catch (IOException ex) {
Logger.getLogger(CreateWorkFile.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
};
StackPane root = new StackPane();
StackPane.setAlignment(mpgb, Pos.BOTTOM_CENTER);
root.getChildren().addAll(btn, mpgb);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Any advice would be awesome guys
You are doing the main work in the FX thread and hence you're blocking the UI.
Put the copying code into a Task and let it run in a thread. Take a look at the Task and Concurrency documentation.
I am adding button to grid pane dynamically but after giving them function they all show same function and i don't knows why?
import java.awt.Panel;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
public class TestController implements Initializable {
#FXML
Panel mpanel;
#FXML
GridPane gpnael;
int x=0,y=0,i=0,y1=0;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
private void add(ActionEvent event) {
y1++;
Button temp = new Button("Button " + i);
temp.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
System.out.println("button"+y1);
}
});
gpnael.add(temp,i++,1);
}
}
now i have added three button to grid pane when i click on each button they show same output.
I want that they all show different output as assigned .
You are not defining it in the buttons, you are always using a non final int to express your values you should try do make them with unique values or to set an id for each button and get the value from the id:
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.GridPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class ButtonsOnGPanel extends Application {
private int i = 0;
private GridPane gpnael = new GridPane();
#Override
public void start(Stage stage) throws Exception {
Pane root = new Pane();
while(i<3){
addButton();
}
root.getChildren().add(gpnael);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
private void addButton() {
i++;
final Button temp = new Button("Button " + i);
final int numButton= i;
temp.setId("" + i);
temp.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
System.out.println("id(" + temp.getId() + ") = " + numButton);
}
});
gpnael.add(temp, i, 1);
}
public static void main(String[] args) {
launch(args);
}
}
And if you want to use lambda expressions:
temp.setOnAction((ActionEvent e) -> {
System.out.println("id(" + temp.getId() + ") = " + numButton);
});