JavaFX TreeTableView Disclosure Node arrow stops row selection - java
I have a JavaFX application using TreeTableViews using JFX8.
Is there a way to stop TreeTableViews from intercepting mouse-clicks in the region of the Disclosure Node arrow even when the row is a leaf (ie has no children) and thereby has no Disclosure Node expand arrow? The current behaviour seems to be to intercept these mouse-clicks in the far-left of the Row, though I think users would expect the row to be selected as there is no disclosure node.
See below example...
public class TestTreeTableViewApplication extends Application {
#Override
public void start(Stage primaryStage) {
AnchorPane anchorPane = new AnchorPane();
anchorPane.setPrefWidth(600);
anchorPane.setPrefHeight(600);
TreeTableView<String> treeTableView = new TreeTableView<>();
TreeTableColumn<String, String> primaryColumn = new TreeTableColumn<>("Col1");
primaryColumn.setPrefWidth(200);
treeTableView.getColumns().add(primaryColumn);
//Just to show some data in the column for test purposes...
primaryColumn.setCellValueFactory(call -> new ReadOnlyStringWrapper(call.getValue().getValue()));
treeTableView.setRoot(new TreeItem<>("Root"));
for (int i = 0; i < 15; i++) {
TreeItem<String> newChild = new TreeItem<>("1st Tier Test " + i);
treeTableView.getRoot().getChildren().add(newChild);
for (int j = 0; j < 3; j++) {
TreeItem<String> newChild2 = new TreeItem<>("2nd Tier Test " + i);
newChild.getChildren().add(newChild2);
}
}
anchorPane.getChildren().add(treeTableView);
Scene scene = new Scene(anchorPane, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Related
How to fix the borders of a node to the contents in it
I have a BorderPane in JavaFx and I want the center's size to be fixed to the size of its children public class Main extends Application { #Override public void start(Stage primaryStage) throws Exception{ GridPane gridPane = new GridPane(); for(int i = 0; i<3; i++) { for(int j = 0; j<3; j++) { Label label = new Label(""); label.setMinHeight(70); label.setMinWidth(70); label.setStyle("-fx-background-color: rgb(226, 155, 100);"); gridPane.add(label, i, j); } } gridPane.setStyle("-fx-border-width: 10px; -fx-border-color: #663820;"); BorderPane borderPane = new BorderPane(); borderPane.setCenter(gridPane); primaryStage.setScene(new Scene(borderPane, 300, 275)); primaryStage.show(); } public static void main(String[] args) { launch(args); } } After running this code if you resize the application, the border follows the edge while the content in it has expanded to its max size. How do I attach the border to the contents. Ideally I want the extra space generated on resizing to go to the outer nodes(top left bottom right) and the center to remain packed with its contents. Thus the center expands till all its children reach Max specified size and then stop.
Do not Scroll TableView When Adding More Items
I would like to add items to a table dynamically. I do it like this: public class TestApp extends Application { public static void main(final String[] args) { launch(args); } private final AtomicLong counter = new AtomicLong(); #Override public void start(final Stage primaryStage) { final VBox root = new VBox(5); root.setPadding(new Insets(10)); root.setAlignment(Pos.CENTER); final TableView<String> tableView = new TableView<>(); final TableColumn<String, String> column = new TableColumn<>("Text"); column.setCellValueFactory(f -> new SimpleStringProperty(f.getValue())); tableView.getColumns().add(column); // Add some sample items to our TableView for (int i = 0; i < 100; i++) { tableView.getItems().add("Item #" + counter.incrementAndGet()); } final Button button = new Button("Add items"); final long oldElement = counter.get(); button.setOnAction(e -> { // Add more elements for (int i = 0; i < 10; i++) { tableView.getItems().add("Item #" + counter.incrementAndGet()); } tableView.scrollTo("Item #" + oldElement); }); root.getChildren().add(button); root.getChildren().add(tableView); // Show the Stage primaryStage.setWidth(300); primaryStage.setHeight(300); primaryStage.setScene(new Scene(root)); primaryStage.show(); } } (Example taken from here) What I would like to change now, is, that when the table is already scrolled down completely, and I add more items, the table automatically scrolls down. The 'scroll-state' seems to be maintained, which is why I still see the very bottom of the table (and the new elements). How can I add items to the table but keeping the scroll at the current position / current row? The 'scrollTo' works, but moves the last element from the bottom of the view to the top, which is also a litte irritating.
New to JavaFX and still trying to figure out a shrinking bullseye Application
So far everything in my application is working. Function: The bullseye will appear, then once the animate me button is clicked, the first three circles inside the bullseye will shrink. Then new circles will be created in alternating colors. Problem: Everything is working thus far except for the pause and play functions I'm trying to implement. I'm planning on making the bullseye stop when the user hits the stop button in the middle, yet pick up wherever it was left off with no hiccups, no skipped circles, etc. Like i said, I'm fairly new to this so I'm just wondering if the problem was that I didn't use the Timeline class in order to try and manage how it was paused and played? Or is the problem with the last two event handlers (btn.setOnMousedPressed and btn.setOnMouseReleased) and the for loops not reaching a certain index? Thanks for the help! public class BullsEye extends Application { Circle[] cir = new Circle[100]; Button btn = new Button("Animate me!"); StackPane root = new StackPane(); public static void main(String[] args) { launch(args); } #Override public void start(Stage primaryStage) { root.setStyle("-fx-border-color:black;"); cir[0] = new Circle(400, 250, 200); cir[0].setFill(Color.RED); cir[0].setStyle("-fx-border-color:black;"); cir[1] = new Circle(315, 165, 115); cir[1].setFill(Color.WHITE); cir[1].setStyle("-fx-border-color:black;"); cir[2] = new Circle(230, 80, 30); cir[2].setFill(Color.RED); cir[2].setStyle("-fx-border-color:black;"); root.getChildren().addAll(cir[0], cir[1], cir[2]); root.getChildren().add(btn); primaryStage.setScene(new Scene(root)); primaryStage.show(); btn.setOnAction(e -> { animation(); btn.setText("Press to Stop"); }); } public void animation() { ScaleTransition[] st = new ScaleTransition[100]; st[0]= new ScaleTransition(Duration.seconds(7), cir[0]); st[0].setToX(0.0f); st[0].setToY(0.0f); st[0].play(); st[1] = new ScaleTransition(Duration.seconds(5.5), cir[1]); st[1].setToX(0.0f); st[1].setToY(0.0f); st[1].play(); st[2] = new ScaleTransition(Duration.seconds(4), cir[2]); st[2].setToX(0.0f); st[2].setToY(0.0f); st[2].play(); // int delayInc = 1; int delay = 1; for(int i = 3; i<st.length; i++) { if(i % 2 == 1) { cir[i] = new Circle(400,250,200); cir[i].setFill(Color.WHITE); cir[i].setStyle("-fx-border-color:black;"); root.getChildren().add(cir[i]); cir[i].toBack(); st[i] = new ScaleTransition(Duration.seconds(7), cir[i]); st[i].setDelay(Duration.seconds(delay)); delay++; st[i].setToX(0.0f); st[i].setToY(0.0f); st[i].play(); } else if(i%2==0) { cir[i] = new Circle(400, 250, 200); cir[i].setFill(Color.RED); cir[i].setStyle("-fx-border-color:black;"); root.getChildren().add(cir[i]); cir[i].toBack(); st[i] = new ScaleTransition(Duration.seconds(7), cir[i]); //st[i].setDuration(Duration.seconds(7)); //st[i].setNode(cir[i]); st[i].setDelay(Duration.seconds(delay)); delay++; st[i].setToX(0.0f); st[i].setToY(0.0f); st[i].play(); } } btn.setOnMousePressed(event -> { for(int x = 0; x<st.length;x++) st[x].pause(); btn.setText("Release to Resume"); }); btn.setOnMouseReleased(event -> { for(int y = 0; y<st.length;y++) st[y].play(); }); } }
Can't add multiple of same rectangle
I want to make multiple of the same rectangle on my borderPane to make walls for the game. Each wall is going to look the same and be the same size. I know the image works and that there are no other errors. I use the following code to add the rectangles: public class Antz extends Application{ public BorderPane borderPane; public Scene scene; public Image wallImage = new Image("/recources/images/walls.png"); public Rectangle wall = new Rectangle(); public int[][] walls = {{1,0,0,0,0,1,1,1,0,1,0,0,0,0,0,1,0}, {1,1,1,1,0,1,0,0,0,1,0,1,1,1,0,1,0}, {0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0}, {0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0}, {0,0,0,0,1,0,0,1,0,0,0,1,0,1,1,1,0}, {1,0,1,1,1,1,0,1,1,1,1,1,0,1,0,0,0}, {1,0,1,0,0,1,0,0,0,0,0,1,0,0,0,1,1}, {1,0,1,1,0,1,0,1,0,1,0,0,0,1,0,0,1}, {1,0,0,0,0,0,0,1,1,1,0,0,1,1,1,0,1}, {0,0,1,0,1,1,0,1,0,1,1,0,1,0,0,0,0}, {1,1,1,0,1,0,0,0,0,0,1,0,1,1,0,1,0}, {1,0,0,0,0,0,1,1,1,0,1,0,0,1,1,1,0}, {1,0,1,0,1,1,1,0,1,1,1,1,0,0,0,1,0}, {0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0}, {1,0,1,1,1,1,0,1,1,1,0,1,0,1,1,0,1}, {0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0}}; public static void main(String[] args){ launch(args); } #Override public void start(Stage primaryStage) throws Exception { buildWindows(); buildWalls(); primaryStage.setScene(scene); primaryStage.setTitle("Formicidae"); primaryStage.show(); primaryStage.setMinHeight(550); primaryStage.setMinWidth(700); primaryStage.setFullScreenExitHint(""); primaryStage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH); } public void buildWindows() { borderPane = new BorderPane(); borderPane.setStyle("-fx-background-color: #000000;"); scene = new Scene(borderPane, 700, 550); } public void buildWalls(){ wall = new Rectangle(wallImage.getWidth(), wallImage.getHeight()); wall.setFill(new ImagePattern(wallImage)); for(int i = 0;i<walls.length;i++){ for(int j = 0;j<walls[i].length;j++){ if(walls[i][j]==1){ wall.setX(j*20); wall.setY(i*20); borderPane.getChildren().add(wall); } } } } } I get this error when it is ran: Caused by: java.lang.IllegalArgumentException: Children: duplicate children added: parent = BorderPane#4a17c25d[styleClass=root]
Trying to add the same Node twice in the Pane object is not a correct behavior. So, you have to create new one every time adding object on a pane object. public void buildWalls(){ wall.setFill(new ImagePattern(wallImage)); for(int i = 0;i<walls.length;i++){ for(int j = 0;j<walls[i].length;j++){ if(walls[i][j]==1){ wall = new Rectangle(wallImage.getWidth(), wallImage.getHeight()); wall.setX(j*20); wall.setY(i*20); borderPane.getChildren().add(wall); } } } } Well, I tested the program with some image from google. I don't know what you are supposed to do with your game but here is the output image.
Animations in JavaFX using RxJava without blocking GUI
This is a simple class that uses bubble sort to sort a List of Integers and push the result of every iteration to a Subject from RxJava library, with some delay. public class Sorter { private PublishSubject<List<Integer>> subject = PublishSubject.create(); public void bubbleSort(int delay) throws InterruptedException { List<Integer> ints = randomIntegers(0,200,10); for (int i = 0; i < ints.size(); i++) { for (int j = 0; j < ints.size() - 1; j++) { if (ints.get(j) > ints.get(j + 1)) { Collections.swap(ints, j, j + 1); subject.onNext(ints); Thread.sleep(delay); } } } } private List<Integer> randomIntegers(int origin, int bound, int limit) { return new Random() .ints(origin, bound) .limit(limit) .boxed() .collect(Collectors.toList()); } public PublishSubject<List<Integer>> getSubject() { return subject; } } I can observe the result very easily with a sample code: int delay = 100; Sorter sorter = new Sorter(); PublishSubject<List<Integer>> subject = sorter.getSubject(); subject.subscribe(System.out::println); sorter.bubbleSort(delay); I want, however, to see the results of the iterations as moving rectangles of different height representing the numbers. I use JavaFX. After every iteration, I want to clear the application window and redraw everything. public class Main extends Application { private Group root; #Override public void start(Stage primaryStage) throws InterruptedException { root = new Group(); Scene scene = new Scene(root, 500, 500, Color.WHITE); primaryStage.show(); primaryStage.setScene(scene); Sorter sorter = new Sorter(); PublishSubject<List<Integer>> subject = sorter.getSubject(); subject.subscribe(this::drawRectangles); sorter.bubbleSort(100); } private void drawRectangles(List<Integer> integers) { root.getChildren().clear(); rectangles.clear(); for (int i = 0; i<integers.size(); i++) { Rectangle rectangle = new Rectangle(i * 20, 500 - integers.get(i), 10, integers.get(i)); rectangle.setFill(Color.BLACK); rectangles.add(rectangle); } root.getChildren().addAll(rectangles); } public static void main(String[] args) { launch(args); } } However, I only see the last iteration's result. Prior to that, I can only see that the application is running and the GUI thread is blocked. How can I make the background RxJava calculations non-blocking to my GUI? EDIT: I solved the issue by running the computation code in another thread, like so: #Override public void start(Stage primaryStage) throws InterruptedException { new Thread(() -> { Sorter sorter = new Sorter(); sorter.getSubject().subscribe(this::drawRectangles); try { sorter.bubbleSort(100); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); root = new Group(); Scene scene = new Scene(root, 1500, 500, Color.WHITE); primaryStage.show(); primaryStage.setScene(scene); } And wrapper the drawRectangles in Platform.runLater(() -> {} expression. This seems to be working, although I feel like there might me a possibility to run this with observeOn somehow.
Use RxJavaFX scheduler your UI tasks. You need do the sort task sorter.bubbleSort in another thread instead of UI thread. And observeOn(JavaFxScheduler.getInstance()) to schedule UI task back into UI thread. Only change your start method to: #Override public void start(Stage primaryStage) throws InterruptedException { root = new Group(); Scene scene = new Scene(root, 500, 500, Color.WHITE); primaryStage.show(); primaryStage.setScene(scene); Sorter sorter = new Sorter(); sorter.getSubject() .observeOn(JavaFxScheduler.platform()) .subscribe(this::drawRectangles); new Thread(() -> uncheck(() -> sorter.bubbleSort(100))).start(); }