Javafx TilePane PrefColumns - javafx

I am having problems producing the correct number of columns in a TilePane row.
I'm trying just to have ten columns per row. I know I'm missing the obvious. So, I need another pair of eyes.
The setPrefColumns method does not appear to work the way I have it coded.
#SuppressWarnings("unused")
public class Main extends Application {
TilePane tp = new TilePane();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
primaryStage.setResizable(false);
tp.setPrefColumns(10);
setTP();
Scene scene = new Scene(tp,800,600);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public void setTP() {
tp.setVisible(true);
int[] numbers = {1,2,3,4,5,6,7,8,9,10};
for(int row=0; row<11; row++) {
for (int i: numbers ) {
Text t = new Text(String.valueOf(i));
HBox hbox = new HBox();
hbox.getChildren().add(t);
hbox.setStyle("-fx-border-color: red;");
tp.getChildren().add(hbox);
}
}
}
}

Your example TilePane behaves as specified:
Note that prefColumns/prefRows is used only for calculating the preferred size and may not reflect the actual number of rows or columns, which may change as the tilepane is resized and the tiles are wrapped at its actual boundaries.
As root of the scene it is sized to fill the complete width (800 in your context):
Scene scene = new Scene(tp,800,600);
To make it wrap on its prefColumns, you need to add it to a layout that respects its content's prefWidth, f.i. a HBox:
Scene scene = new Scene(new HBox(tp),800,600);

Related

JavaFX Button EventHandler works one time(Card Shuffler)

I'm trying to make a program that will display a random set of 4 cards, then when I click the button again it will clear the old set and display a new random set.
Right now my program will display 4 random images of cards when I click the button; however, when I try to click it again nothing happens. I'm assuming it has something to do with the EventHandler no longer being registered to the button after I clear the root children. However, I don't know how to go about fixing this. Any help is greatly appreciated! I haven't been able to find an answer to this yet, and have only been learning JavaFX for about a week. Thank you.
The code I have so far:
public class CardShuffle extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
Scanner input = new Scanner(System.in);
File cardsFolder = new File("C:\\Users\\timsp\\Pictures\\JPEG");
ArrayList<File> cardsFilePaths = new ArrayList<File> (Arrays.asList(cardsFolder.listFiles()));
Button deal = new Button("DEAL");
Pane hb = new HBox(10);
hb.setPadding(new Insets(5, 5, 5, 5));
root.getChildren().add(deal);
deal.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
root.getChildren().clear();
ArrayList<ImageView> cards = getRandomCards(cardsFilePaths);
for (int i = 0; i < 4; i++) {
cards.get(i).setFitWidth(150);
cards.get(i).setFitHeight(100);
hb.getChildren().add(cards.get(i));
}
root.getChildren().addAll(deal, hb);
}
});
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public ArrayList<ImageView> getRandomCards(ArrayList<File> cardsFilePaths) {
ArrayList<ImageView> cards = new ArrayList<ImageView>();
try {
for (int i = 0; i < 4; i++) {
Image card = new Image((new FileInputStream(cardsFilePaths.get((int) (Math.random() * 52)).getPath())));
ImageView temp = new ImageView();
temp.setImage(card);
cards.add(temp);
}
} catch (FileNotFoundException e) {
e.getMessage();
}
return cards;
}
}
Many problems here :
the first one, and the most important (because it hides your further error) is the root layout : you use a StackPane, the first thing you should do is to replace it by a VBox for example and rerun your program, it will be easier to see what really happens. (you will not have 4 cards, but 8, 12, 16 and so on).
the first one generates the second one. By doing this root.getChildren().addAll(deal, hb); you put the HBox layout above the button, and the click is first consumed by the HBox. Here is an example to see it more easily :
// Add the HBox as soon as the initialization
root.getChildren().add(deal);
hb.setOnMouseClicked(e -> System.out.println("HBox clicked"));
deal.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
root.getChildren().clear();
ArrayList<ImageView> cards = getRandomCards(cardsFilePaths);
for(int i = 0; i < 4; i++) {
cards.get(i).setFitWidth(150);
cards.get(i).setFitHeight(100);
hb.getChildren().add(cards.get(i));
}
hb.setStyle("-fx-background-color:CORNFLOWERBLUE;-fx-opacity:0.8;");
root.getChildren().addAll(deal, hb);
}
});
And the last one, you don't really want to remove all root's children, what you want is to replace your cards by another 4 ones. Thus it is not necessary to remove the button, only the HBox can be manipulated as shown by the following example :
// Add the HBox as soon as the initialization
root.getChildren().addAll(hb, deal);
deal.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// root.getChildren().clear();
// Replace the previous line by the following :
hb.getChildren().clear();
ArrayList<ImageView> cards = getRandomCards(cardsFilePaths);
for(int i = 0; i < 4; i++) {
cards.get(i).setFitWidth(150);
cards.get(i).setFitHeight(100);
hb.getChildren().add(cards.get(i));
}
// The following is useless now.
// root.getChildren().addAll(hb, deal);
}
});

JavaFX unable to display rectangle inside grid

So my teacher has just started teaching us how to use JavaFx and up until now, I had thought I had a pretty good grasp of the material. But, I am stuck and I don't quite know how to fix the issue or even what's causing the issue. I am trying to create a green rectangle that is three nodes high on a grid that is 64x64. The grid shows up just fine but for the life of me, I cannot understand why the rectangle is not showing up as well. Can someone please help me figure out why the rectangle won't show up? I am sure it's a small stupid issue but again I can't see it. Here is my code:
public class test2 extends Application {
private Cell[][] cell = new Cell[64][64];
public void start(Stage primaryStage) {
GridPane pane = new GridPane();
pane.setStyle("-fx-background-color: black");
for (int col = 1; col < 64; col++)
for (int row = 1; row < 64; row++)
pane.add(cell[col][row] = new Cell(), row, col);
Rectangle rectangle = new Rectangle(1,3);
rectangle.setFill(Color.GREEN);
VBox box2 = new VBox(rectangle);
box2.setAlignment(Pos.CENTER);
BorderPane bp = new BorderPane();
bp.setCenter(pane);
Scene scene = new Scene(bp, 1000, 700);
primaryStage.setScene(scene);
primaryStage.show();
}
public class Cell extends Pane{
public Cell(){
setStyle("-fx-border-color: white");
setPrefSize(1000, 1000);
return;
}
}
public static void main(String[] args) {
launch(args);
}

JavaFX:how to resize the stage when using webview

for example:
public class WebViewTest extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
final WebView view = new WebView();
final WebEngine webEngine = view.getEngine();
Scene scene = new Scene(view, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
Platform.runLater(() -> {
webEngine.getLoadWorker().progressProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (newValue.doubleValue() == 1D) {
String heightText = webEngine.executeScript(
"window.getComputedStyle(document.body, null).getPropertyValue('height')"
).toString();
double height = Double.valueOf(heightText.replace("px", ""));
String widthText = webEngine.executeScript(
"window.getComputedStyle(document.body, null).getPropertyValue('width')"
).toString();
double width = Double.valueOf(widthText.replace("px", ""));
System.out.println(width + "*" + height);
primaryStage.setWidth(width);
primaryStage.setHeight(height);
}
}
});
webEngine.load("http://www.baidu.com/");
});
}
public static void main(String[] args) {
launch(args);
}
}
I want to resize the primaryStage after loading. But finally, I get the size is 586*586, and the primaryStage shows like this:
enter image description here
Actually, I don't want the rolling style, so how can I remove the scroll bar? If I use primaryStage.setWidth() or primaryStage.setHeight() to set the size of primaryStage very big at the beginning, the scroll bar will not exist. But that not I need, I want to resize the size dynamically, because the url will change.
This is similar to the solution given by RKJ (relies on querying WebView for the document width and height).
This solution adds a couple of things:
Ability to completely remove WebView scroll bars at all times (you may or may not want this as it stops the user being able to scroll large documents or view complete documents if the user manually makes the window smaller).
A call to stage.sizeToScene() to size the stage precisely to the scene size.
The behavior of this solution is kind of weird due to some implementation details of WebView. WebView does not load the document unless it is displayed on the stage, so you can't know the document size until you try to display it. So you need to display the document, then resize the stage to fit the document, which results in a delay after the stage has been initially shown and when it resizes to exactly fit the document. This provides, for certain documents, a visible jump in the stage size which just looks weird. Also documents larger than the screen size (which are common on the web) cannot be displayed in full as the stage can only maximally resize to fill the available screen real estate and without any scroll bars you can't see part of the document. So in all, I don't think this solution is really useful.
no-overflow.css
body {
overflow-x: hidden;
overflow-y: hidden;
}
WebViewTest.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class WebViewTest extends Application {
#Override
public void start(Stage stage) throws Exception {
final WebView view = new WebView();
view.getEngine().setUserStyleSheetLocation(
getClass().getResource("no-overflow.css").toExternalForm()
);
final WebEngine webEngine = view.getEngine();
webEngine.getLoadWorker().runningProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Running: " + newValue);
if (!newValue) {
String heightText = webEngine.executeScript(
"document.height"
).toString();
double height = Double.valueOf(heightText.replace("px", ""));
String widthText = webEngine.executeScript(
"document.width"
).toString();
double width = Double.valueOf(widthText.replace("px", ""));
System.out.println(width + "*" + height);
view.setMinSize(width, height);
view.setPrefSize(width, height);
view.setMaxSize(width, height);
stage.sizeToScene();
System.out.println(view.getLayoutBounds());
}
});
webEngine.load("http://www.baidu.com");
Scene scene = new Scene(view);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
public class WebViewTest extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
final WebView view = new WebView();
final WebEngine webEngine = view.getEngine();
Scene scene = new Scene(view, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
Platform.runLater(() -> {
webEngine.getLoadWorker().progressProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (newValue.doubleValue() == 1D) {
String heightText = webEngine.executeScript("document.height").toString();
double height = Double.valueOf(heightText.replace("px", ""));
String widthText = webEngine.executeScript("document.width").toString();
double width = Double.valueOf(widthText.replace("px", ""));
System.out.println(width + "*" + height);
primaryStage.setWidth(width+50);
primaryStage.setHeight(height+50);
primaryStage.hide();
primaryStage.show();
}
}
});
webEngine.load("http://baidu.com/");
});
}
public static void main(String[] args) {
launch(args);
}
}
use document.height and document.width to get the actual dimension, there is slight difference between the pixel size and stage size measurement so, I added 50 pixel extra and hide the stage and show it again but it is more better if you use WebView inside StackPane Container.
rkjoshi

How to write a MouseListener for JavaFX

I want to write a little game where I shoot from an object to a specific direction on a JavaFX Panel using my mouse position.
I want to turn a Line in the direction where my Mouse is.
Line line = new Line(startPosX, startPosY, mouseDirectionX, mouseDirectionY);
How can I do that?
Add a MOUSE_MOVED event filter like this:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane root = new Pane();
Line line = new Line( 400,200,400,200);
root.addEventFilter(MouseEvent.MOUSE_MOVED, e -> {
line.setEndX(e.getSceneX());
line.setEndY(e.getSceneY());
});
root.getChildren().add(line);
Scene scene = new Scene(root, 800, 400);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
If you want the line to be limited in length, you'll have to do the proper calculations of course via the angle.

Sort ObservableList from high to low - javafx

Is there any way to sort a ObservableList based on the values from high to low?
Say I have a
ObservableList<XYChart.Data> data;
containing a String and a Double. I want the list sorted based on the Double from highest to lowest values. The reason I want this is because charts look way better if their values are shown from the highest to the lowest.
I have something like this now:
sortedData = new SortedList<>(data);
sortedData.comparatorProperty().bind(mycomparatorProperty());
You can create a Comparator, compare by the Y value, and then reverse the order:
data.sort(Comparator.comparing(XYChart.Data<String,Double>::getYValue).reversed());
This will sort your collection as intented.
Or you can return a new collection:
List<XYChart.Data<String,Double>> sortedData =
data.stream()
.sorted(Comparator.comparing(XYChart.Data<String,Double>::getYValue).reversed())
.collect(Collectors.toList());
EDIT
For the sake of clarity, this is a full sample:
public class FXMain extends Application {
private final ObservableList<XYChart.Data<String,Double>> data =
FXCollections.observableArrayList(
new XYChart.Data("P1",200d),
new XYChart.Data("P2",150d),
new XYChart.Data("P3",250d));
#Override
public void start(Stage primaryStage) {
Button btn = new Button"Sort data!");
btn.setOnAction(e -> {
ObservableList<XYChart.Data<String,Double>> data2 =
data.stream()
.sorted(Comparator.
comparing(XYChart.Data<String,Double>::getYValue).reversed())
.peek(System.out::println)
.collect(Collectors.toCollection(()->FXCollections.observableArrayList()));
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Resources