I have this wierd problem when trying to CSS style a TreeView.
This TreeView is Filterable to show only the items which I'm looking for.
This is how it looks when the Tree is shown without any filtering
And here's how it looks like, when there's a filtering active
I wanted to have all expanded nodes to have a colored background (green in this example).
So I added a Stylesheet containing the following code
.search-tree .tree-cell:expanded {
-fx-background-color: green;
-fx-text-fill: white;
}
But as you can see, the empty cells in the 2nd image are still colored even there's no content in it.
I also checked the component with ScenicView and indeed the pseudoClassState is still 'expanded'.
Does anyone have a idea why this empty cell is still in this state?
Here's the sample code that I used:
import java.io.File;
import java.util.ArrayList;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TreeTest extends Application {
TreeView<Object> t;
private TextField searchField;
private TreeViewHelper helper;
#Override
public void start(Stage s) throws Exception {
helper = new TreeViewHelper();
t = new TreeView<>();
t.getStyleClass().add("search-tree");
TreeItem rootItem = new TreeItem("");
TreeItem cars = new TreeItem("Cars");
cars.getChildren().addAll(helper.getCars());
cars.setExpanded(true);
TreeItem buses = new TreeItem("Buses");
buses.getChildren().addAll(helper.getBuses());
buses.setExpanded(true);
rootItem.setExpanded(true);
rootItem.getChildren().add(cars);
rootItem.getChildren().add(buses);
t.setRoot(rootItem);
t.setShowRoot(false);
VBox root = new VBox();
root.getChildren().add(t);
searchField = new TextField();
searchField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> prop, String lastValue, String v) {
scanItems();
}
});
root.getChildren().add(searchField);
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(new File("style.css").toURI().toURL().toExternalForm());
s.setScene(scene);
s.show();
}
void scanItems()
{
t.getRoot().getChildren().clear();
TreeItem cars = new TreeItem("Cars");
helper.getCars().stream().filter(e -> e.getValue().toString().toLowerCase().contains(searchField.getText().toLowerCase()))
.forEach(item -> cars.getChildren().add(item));
t.getRoot().getChildren().add(cars);
cars.setExpanded(true);
TreeItem buses = new TreeItem("Buses");
helper.getBuses().stream().filter(e -> e.getValue().toString().toLowerCase().contains(searchField.getText().toLowerCase()))
.forEach(item -> buses.getChildren().add(item));
t.getRoot().getChildren().add(buses);
buses.setExpanded(true);
}
public static void main(String[] args) {
Application.launch( args );
}
class TreeViewHelper
{
public TreeViewHelper()
{
}
// This method creates an ArrayList of TreeItems (Products)
public ArrayList<TreeItem> getProducts()
{
ArrayList<TreeItem> products = new ArrayList<TreeItem>();
TreeItem cars = new TreeItem("Cars");
cars.getChildren().addAll(getCars());
cars.setExpanded(true);
TreeItem buses = new TreeItem("Buses");
buses.getChildren().addAll(getBuses());
buses.setExpanded(true);
products.add(cars);
products.add(buses);
return products;
}
// This method creates an ArrayList of TreeItems (Cars)
ArrayList<TreeItem> getCars()
{
ArrayList<TreeItem> cars = new ArrayList<TreeItem>();
TreeItem ferrari = new TreeItem("Ferrari");
TreeItem porsche = new TreeItem("Porsche");
TreeItem ford = new TreeItem("Ford");
TreeItem mercedes = new TreeItem("Mercedes");
cars.add(ferrari);
cars.add(porsche);
cars.add(ford);
cars.add(mercedes);
return cars;
}
// This method creates an ArrayList of TreeItems (Buses)
ArrayList<TreeItem> getBuses()
{
ArrayList<TreeItem> buses = new ArrayList<TreeItem>();
TreeItem gm = new TreeItem("GM");
TreeItem vw = new TreeItem("VW");
TreeItem man = new TreeItem("MAN");
TreeItem volvo = new TreeItem("Volvo");
buses.add(gm);
buses.add(man);
buses.add(volvo);
buses.add(vw);
return buses;
}
}
}
Edit: I have this issue on MacOSX 10.11 using Java 1.8.0_77b3
I think I found a solution.
By simply adding following style and defining the empty state
.search-tree .tree-cell:empty {
-fx-background-color: transparent;
-fx-text-fill: white;
}
it was working as expected.
Related
My setup
I have added an EventFilter to an Hbox node which also contains two VBoxes.
In one of the VBoxes I have a Button, a Label, and a TextArea class instance.
The EventHandler is:
public static EventHandler<MouseEvent> pageEventFilter = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
EventTarget target = e.getTarget();
String name = target.getClass().getName();
System.out.println("NAME: " + name);
}
};
In the event filter, I want to get the id string for buttons or labels that the user clicks on.
I cannot determine the button or label clicked
When I click on a part of the button or label, I get the following class names reported:
click on button text ->
com.sun.javafx.scene.control.LabeledText
click outside button text ->
javafx.scene.control.Button or javafx.scene.control.Label
Trying to cast the event target of LabeledText to a Button or a Label gives me a ClassCastException.
If I try to create a variable:
LabeledText lbt = target
I get a compilation error that the LabeledText class does not exist.
Similarly for TextArea
When I click on the TextArea, I get javafx.scene.control.skin.TextAreaSkin$ContentView as the name of the target class. I am unable to click anywhere to get TextArea reported as the event target class. When I click the text in the TextArea, I get javafx.scene.text.Text, I cannot get the id of the TextArea node from either of these.
My Question
How do I find the parent of the target node, for the types of nodes I am interested in (buttons, labels and perhaps some other types), for which I can then get the node ID string using:
String nodeId = targetParentNode.getId();
In the screenshot, the user has clicked on a descendent node of a TextArea which is of type ContentView.
On intercepting the click event in a filter, the application has walked up the scene graph branch via repeated getParent() calls until it has found a higher level node of one of the specified types. In this case it has found a TextArea. It has then queried that text area for its "id" value and reported it in the appropriate label.
IdReporterApp.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class IdReporterApp extends Application {
private static final String CSS =
"""
data:text/css,
.label {
-fx-padding: 3px;
-fx-background-color: lightblue;
}
VBox {
-fx-spacing: 10px;
-fx-padding: 10px;
-fx-background-color: lemonchiffon;
}
HBox {
-fx-padding: 10px;
-fx-background-color: palegreen;
}
""";
#Override
public void start(Stage stage) {
Scene scene = new Scene(new IdController().getUI());
scene.getStylesheets().add(CSS);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
IdController.java
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import java.util.List;
class IdController {
private final Label clickedTargetTypeLabel = new Label();
private final Label reportedTargetTypeLabel = new Label();
private final Label reportedTargetIdLabel = new Label();
private final EventTargetFinder eventTargetFinder = new EventTargetFinder(
List.of(
Label.class, Button.class, TextArea.class
)
);
public Parent getUI() {
final VBox layout = new VBox(
new VBox(
id("box1", new Label("Box 1")),
id("button1", new Button("Button"))
),
new VBox(
id("box2", new Label("Box 2")),
id("textArea1", new TextArea("Text Area"))
),
new HBox(
id("clickTargetLabel", new Label("Clicked target Type")),
id( "clickTargetValueLabel", clickedTargetTypeLabel)
),
new HBox(
id("reportedTargetLabel", new Label("Reported target Type")),
id( "reportedTargetTypeLabel", reportedTargetTypeLabel)
),
new HBox(
id("reportedTargetIdLabel", new Label("Reported target ID")),
id("reportedTargetIdValueLabel", reportedTargetIdLabel)
)
);
layout.addEventFilter(
MouseEvent.MOUSE_CLICKED,
this::updateTargetLabels
);
return layout;
}
private Node id(String id, Node node) {
node.setId(id);
return node;
}
private void updateTargetLabels(MouseEvent e) {
EventTargetFinder.TargetSearchResult searchResult =
eventTargetFinder.findTargetsForMouseEvent(e);
clickedTargetTypeLabel.setText(
searchResult
.clickedTarget()
.getClass()
.getSimpleName()
);
reportedTargetTypeLabel.setText(
searchResult.reportedTarget() == null
? "null"
: searchResult
.reportedTarget()
.getClass()
.getSimpleName()
);
reportedTargetIdLabel.setText(
searchResult.reportedTarget() == null
? "none"
: searchResult.reportedTarget().getId() == null
? "null"
: searchResult.reportedTarget().getId()
);
}
}
EventTargetFinder.java
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import java.util.Collections;
import java.util.List;
record EventTargetFinder(List<Class<? extends Node>> filterTargetTypes) {
EventTargetFinder(List<Class<? extends Node>> filterTargetTypes) {
this.filterTargetTypes = Collections.unmodifiableList(filterTargetTypes);
}
record TargetSearchResult(
Node clickedTarget,
Node reportedTarget
) {}
public TargetSearchResult findTargetsForMouseEvent(MouseEvent event) {
Node target = (Node) event.getTarget();
Node clickedTarget = target;
while (target != null && !isTargetFiltered(target)) {
target = target.getParent();
}
Node reportedTarget = target;
return new TargetSearchResult(clickedTarget, reportedTarget);
}
private boolean isTargetFiltered(Node target) {
return filterTargetTypes.stream()
.anyMatch(
t -> t.isInstance(target)
);
}
}
I am very new to Java so please be patient with me. I have successfully added buttons, labels and even a progress bar to a listview cell. I need to be able to detect when one of the buttons has been clicked. Adding controls to listview content I managed to get from a couple of posts here the code i am using is shown below
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ProgressBar;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class ListViewDemo extends Application {
public static class lvCell extends VBox {
Label labelName = new Label();
Label labelPath = new Label();
Label labelElapse = new Label();
Button buttonPlayPause = new Button();
Button buttonStop = new Button();
ImageView ivStop = new ImageView();
ImageView ivPlay = new ImageView();
Pane buttonSpacer = new Pane();
Pane progressBarSpacer = new Pane();
HBox hbDetail = new HBox();
HBox hbProgress = new HBox();
ProgressBar pbProgress = new ProgressBar();
File filePlay;
File fileStop;
double prefWidth = 10;
double prefHeight = 10;
lvCell(String labelText) {
super();
labelName.setText(labelText);
labelName.setMaxWidth(Double.MAX_VALUE);
labelPath.setMaxWidth(0);
labelPath.setText("Path");
pbProgress.setMaxWidth(Double.MAX_VALUE);
HBox.setHgrow(labelName, Priority.ALWAYS);
HBox.setHgrow(pbProgress, Priority.ALWAYS);
HBox.setMargin(labelName, new Insets(5, 0, 0, 0));
HBox.setMargin(pbProgress, new Insets(0, 0, 0, 0));
labelPath.setVisible(false);
buttonSpacer.setPrefSize(prefWidth, prefHeight);
labelElapse.setPrefSize(50, prefHeight);
labelElapse.setText("Time");;
progressBarSpacer.setPrefSize(prefWidth * 6, prefHeight);
filePlay = new File("src/image/play.png");
fileStop = new File("src/image/stop.png");
Image imagePlay = new Image(filePlay.toURI().toString());
Image imageStop = new Image(fileStop.toURI().toString());
ivPlay.setImage(imagePlay);
ivStop.setImage(imageStop);
ivPlay.setFitHeight(prefHeight);
ivPlay.setFitWidth(prefWidth);
ivStop.setFitHeight(prefHeight);
ivStop.setFitWidth(prefWidth);
buttonPlayPause.setGraphic(ivPlay);
buttonStop.setGraphic(ivStop);
buttonPlayPause.setMaxSize(prefWidth, prefHeight);
buttonStop.setMaxSize(prefWidth, prefHeight);
pbProgress.setMaxHeight(2);
pbProgress.setPrefHeight(2);
hbDetail.getChildren().addAll(buttonPlayPause, buttonStop, buttonSpacer, labelName, labelPath);
hbProgress.getChildren().addAll(progressBarSpacer, pbProgress, labelElapse);
this.getChildren().addAll(hbDetail, hbProgress);
}
}
public Parent createContent() {
BorderPane layout = new BorderPane();
List < lvCell > list = new ArrayList < > ();
for (int i = 0; i < 10; i++) {
list.add(new lvCell("Item " + i));
}
ListView < lvCell > listView = new ListView < lvCell > ();
ObservableList < lvCell > myObservableList = FXCollections.observableList(list);
listView.setItems(myObservableList);
layout.setCenter(listView);
return layout;
}
#Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setWidth(300);
stage.setHeight(200);
stage.show();
}
public static void main(String args[]) {
launch(args);
}
}
The screen looks like this:
Any help will be greatly appreciated.
Thanks in advance, and wishing you a peaceful journey.
Yas
This is not a class well designed to put into a ListView. An object used as item in a ListView should contain data; the ListCell implementation produced by the cellFactory is responsible for determining the visual representation of the data in the ListView. This way you avoid the creation of nodes for every object reducing the memory footprint, which is exactly what ListView is designed for.
Simplified example
The data here contains just the progress and some text; it's displayed in a ProgressBar and the text of the cell; an additional button in the cell allows increasing the progress by 0.25 for each click and removing any items reaching a progress of 1.
Data class
public class Data {
private final DoubleProperty progress = new SimpleDoubleProperty();
private final String text;
public Data(String text) {
this.text = text;
}
public double getProgress() {
return progress.get();
}
public void setProgress(double value) {
progress.set(value);
}
public String getText() {
return text;
}
public ObservableValue<? extends Number> progressProperty() {
return progress;
}
}
ListView code
ListView<Data> listView = new ListView<>(someData);
listView.setCellFactory(l -> new ListCell<Data>() {
private final ProgressBar progressBar = new ProgressBar();
private final Button button = new Button("increase");
private final HBox content = new HBox(progressBar, button);
{
button.setOnAction(evt -> {
Data item = getItem();
int index = getIndex();
double progress = item.getProgress() + 0.25;
item.setProgress(progress);
if (progress >= 1) {
getListView().getItems().remove(index);
}
});
}
#Override
protected void updateItem(Data item, boolean empty) {
super.updateItem(item, empty);
progressBar.progressProperty().unbind();
if (item == null) {
setGraphic(null);
setText("");
} else {
setGraphic(content);
setText(item.getText());
progressBar.progressProperty().bind(item.progressProperty());
}
}
});
How would I implement the method
private void wipeTreeViewStructure(TreeItem node)
where "node" is a TreeItem which, along with all of its connected TreeItems, gets erased on execution? I tried something along the lines of
private void wipeTreeViewStructure(TreeItem node) {
for (TreeItem i : node.getChildren()) {
wipeTreeViewStructure(i);
i.delete();
}
}
but that has two major flaws:
I'm getting an "Incompatible types" error in the "i", which I don't know what to make out of.
there is apparently no delete() or any similar method implemented for TreeItem.
With this many unknowns, I thought it would be better to just ask how it's done.
Your incompatible types error is (I think) because you are using raw types, instead of properly specifying the type of the object in the TreeItem. In other words, you should be using
TreeItem<Something>
instead of just the raw
TreeItem
The Something is whatever you are using as data in your tree. Your IDE should be giving you lots of warnings over this.
You don't need recursion at all here. To remove the tree item, just remove it from its parent's list of child nodes. It will effectively take all its descendents with it. You can do
node.getParent().getChildren().remove(node);
and that should do everything you need. (If the node might be the root of the tree, then you should check for that first.)
SSCCE:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class TreeViewWithDelete extends Application {
#Override
public void start(Stage primaryStage) {
TreeItem<String> treeRoot = new TreeItem<>("Root");
treeRoot.setExpanded(true);
TreeView<String> tree = new TreeView<>(treeRoot);
tree.getSelectionModel().select(treeRoot);
Button delete = new Button("Delete");
delete.setOnAction(e -> {
TreeItem<String> selected = tree.getSelectionModel().getSelectedItem();
selected.getParent().getChildren().remove(selected);
});
delete.disableProperty().bind(tree.getSelectionModel().selectedItemProperty().isNull()
.or(tree.getSelectionModel().selectedItemProperty().isEqualTo(treeRoot)));
TextField textField = new TextField();
Button add = new Button("Add");
EventHandler<ActionEvent> addAction = e -> {
TreeItem<String> selected = tree.getSelectionModel().getSelectedItem();
if (selected == null) {
selected = treeRoot ;
}
String text = textField.getText();
if (text.isEmpty()) {
text = "New Item";
}
TreeItem<String> newItem = new TreeItem<>(text);
selected.getChildren().add(newItem);
newItem.setExpanded(true);
tree.getSelectionModel().select(newItem);
};
textField.setOnAction(addAction);
add.setOnAction(addAction);
HBox controls = new HBox(5, textField, add, delete);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(5));
BorderPane root = new BorderPane(tree, null, null, controls, null);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
So i have this code in which i'm trying to do a scene for my game. I'm really a beginner in a Java and especially JAVAFX world and doing this as a school project (Once again..) and trying to figure out a way to refresh my label.
I've found one URL from stackoverflow, which was a similar issue but didn't work for my problem (or was i too stupid to make it work..) anyways, link is here
This is the part where the problem occurs - i have a text box, from which you have to enter player names. Every time a user inputs player name the label shows how many names have been entered, according to the nimedlist.size() which holds the names inside.
Label mängijate_arv = new Label("Mängijaid on sisestatud: "+nimedlist.size());
// if we press enter, program will read the name
nimiTekst.setOnKeyPressed(new EventHandler<KeyEvent>() {
public void handle(final KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
if (nimiTekst.getText() != null) {
nimedlist.add(nimiTekst.getText());
nimiTekst.setText(null);
}
}
}
});
startBox.getChildren().addAll(sisestus_mängijad, nimiTekst, mängijate_arv,
startButton2);
This is the whole code:
package application;
import java.util.ArrayList;
import javafx.application.Application;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class Baila2 extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(final Stage peaLava) {
final Group root = new Group();
final BorderPane piir = new BorderPane();
piir.setPrefSize(960, 540);
final Text tekst = new Text();
tekst.setText("JOOMISMÄNG");
tekst.setFont(Font.font("Verdana", 40));
VBox nupudAlam = new VBox();
Button startButton = new Button("Start");
nupudAlam.setSpacing(20);
Button reeglidButton = new Button("Reeglid");
nupudAlam.setAlignment(Pos.CENTER);
startButton.setId("btn3");
startButton.setMaxWidth(160);
reeglidButton.setMaxWidth(160);
reeglidButton.setId("btn3");
nupudAlam.getChildren().addAll(startButton, reeglidButton);
piir.setTop(tekst);
piir.setAlignment(tekst, Pos.CENTER);
piir.setCenter(nupudAlam);
root.getChildren().add(piir);
// START NUPP TÖÖ
startButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(final ActionEvent event) {
final ArrayList nimedlist = new ArrayList();
piir.setVisible(false);
final BorderPane startPiir = new BorderPane();
final VBox startBox = new VBox();
Button startButton2 = new Button("ALUSTA!");
startButton2.setId("btn2");
startButton2.setMaxWidth(160);
startPiir.setPrefSize(960, 540);
final Text startTekst = new Text();
startTekst.setText("JOOMISMÄNG");
startTekst.setFont(Font.font("Verdana", 40));
startPiir.setTop(startTekst);
startPiir.setAlignment(startTekst, Pos.CENTER);
final TextField nimiTekst = new TextField();
nimiTekst.setText(null);
nimiTekst.setMaxWidth(250);
Label sisestus_mängijad = new Label(
"Sisesta 3-9 mängija nimed:");
sisestus_mängijad.setFont(Font.font("Verdana", 30));
sisestus_mängijad.setTextFill(Color.ORANGE);
Label mängijate_arv = new Label("Mängijaid on sisestatud: "+nimedlist.size());
// kui vajutatakse ENTER,siis loeme nime
nimiTekst.setOnKeyPressed(new EventHandler<KeyEvent>() {
public void handle(final KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
if (nimiTekst.getText() != null) {
nimedlist.add(nimiTekst.getText());
nimiTekst.setText(null);
}
}
}
});
startBox.getChildren().addAll(sisestus_mängijad, nimiTekst, mängijate_arv,
startButton2);
startBox.setSpacing(20);
startBox.setAlignment(Pos.CENTER);
startPiir.setCenter(startBox);
root.getChildren().add(startPiir);
}
});
// aknasündmuse lisamine
peaLava.setOnHiding(new EventHandler<WindowEvent>() {
public void handle(WindowEvent event) {
// luuakse teine lava
final Stage kusimus = new Stage();
// küsimuse ja kahe nupu loomine
Label label = new Label("Kas tõesti tahad kinni panna?");
Button okButton = new Button("Jah");
Button cancelButton = new Button("Ei");
// sündmuse lisamine nupule Jah
okButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
kusimus.hide();
}
});
// sündmuse lisamine nupule Ei
cancelButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
peaLava.show();
kusimus.hide();
}
});
// nuppude grupeerimine
FlowPane pane = new FlowPane(10, 10);
pane.setAlignment(Pos.CENTER);
pane.getChildren().addAll(okButton, cancelButton);
// küsimuse ja nuppude gruppi paigutamine
VBox vBox = new VBox(10);
vBox.setAlignment(Pos.CENTER);
vBox.getChildren().addAll(label, pane);
// stseeni loomine ja näitamine
Scene stseen2 = new Scene(vBox);
kusimus.setScene(stseen2);
kusimus.show();
}
}); // siin lõpeb aknasündmuse kirjeldus
// stseeni loomine ja näitamine
Scene stseen1 = new Scene(root, 960, 540, Color.GREEN);
peaLava.setTitle("BAILA 2.0");
// peaLava.setResizable(false);
stseen1.getStylesheets().add(
getClass().getClassLoader().getResource("test.css")
.toExternalForm());
peaLava.setScene(stseen1);
peaLava.show();
}
}
Sorry about Estonian language, it's compulsory in our school to write in our native language..
You can just do
nimiTekst.setOnKeyPressed(new EventHandler<KeyEvent>() {
public void handle(final KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
if (nimiTekst.getText() != null) {
nimedlist.add(nimiTekst.getText());
nimiTekst.setText(null);
mängijate_arv.setText("Mängijaid on sisestatud: "+nimedlist.size());
}
}
}
});
If you are not using Java 8 (you appear not to be, since you are implementing all the handlers the old, long way...), you will have to declare mängijate_arv as final:
final Label mängijate_arv = new Label("Mängijaid on sisestatud: "+nimedlist.size());
If you want to be extra cool with this, you can use bindings instead. You will have to make nimidlist an observable list:
final ObservableList<String> nimedlist = FXCollections.observableArrayList();
and then:
mängijate_arv.bind(Bindings.format("Mängijaid on sisestatud: %d", Bindings.size(nimedList)));
and don't put the mängijate_arv.setText(...) call in the handler. This solution is nicer in many ways, as if you remove items from the list (or add other items elsewhere in your code), then the label will still remain properly updated without any additional code.
One other thing: it's a bit better to use an action handler on the text field, instead of a low-level key event handler:
nimiTekst.setOnAction(new EventHandler<ActionEvent>() {
public void handle(final ActionEvent keyEvent) {
if (nimiTekst.getText() != null) {
nimedlist.add(nimiTekst.getText());
nimiTekst.setText(null);
mängijate_arv.setText("Mängijaid on sisestatud: "+nimedlist.size());
}
}
});
(Sorry if I mangled your variable names. My Estonian is a bit weak ;). Your school's policy is a good one, for what it's worth.)
I'm trying to get my clipboard to receive some custom data in a drag and drop. The custom data is another java type. This other type does implement serializable, so I'm really not sure why this isn't working. Any ideas are appreciated!
imgView.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
ClipboardContent content = new ClipboardContent();
content.put(dataFormat, RHSIconizedToken.this);
Dragboard db = imgView.startDragAndDrop(TransferMode.ANY);
db.setContent(content);
event.consume();
}
});
To retrieve this object later I'm using:
RHSIconizedToken replacementRHSiToken = (RHSIconizedToken) db.getContent(RHSIconizedToken.getDataFormat());
I'm getting the following error, but the RHSIconizedToken does implement Serializable
java.lang.IllegalArgumentException: Could not serialize the data
GetDataFormat returns the DataFormat Object that is used in the put argument in the first code example.
That's because your object is not serializable.
Indeed, it's not because it implements Serializable that it is Serializable.
Look deeper inside the exception, you might find something like this
Caused by: java.io.NotSerializableException: javafx.beans.property.SimpleObjectProperty
Maybe making some fields transient will help.
If your drag object isn't serializable, save it in a global variable during the drag. Here's a JavaFx (Java8 with lambdas) example with draggable tabs that go bewteen panes within the same JVM.
import java.util.Random;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class DraggingTabPane extends Application {
private static final DataFormat TAB_TYPE = new DataFormat("nonserializableObject/tab");
private static Tab dndTab;// global for drag-n-drop of non-serializable type
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
TabPane tabPane1 = createDndTabPane();
TabPane tabPane2 = createDndTabPane();
VBox root = new VBox(10);
root.getChildren().addAll(tabPane1, tabPane2);
final Random rng = new Random();
for (int i=1; i<=8; i++) {
final Tab tab = createDraggableTab("Tab "+i);
final StackPane pane = new StackPane();
int red = rng.nextInt(256);
int green = rng.nextInt(256);
int blue = rng.nextInt(256);
String style = String.format("-fx-background-color: rgb(%d, %d, %d);", red, green, blue);
pane.setStyle(style);
final Label label = new Label("This is tab "+i);
label.setStyle(String.format("-fx-text-fill: rgb(%d, %d, %d);", 256-red, 256-green, 256-blue));
pane.getChildren().add(label);
pane.setMinWidth(600);
pane.setMinHeight(250);
tab.setContent(pane);
if (i<=4) {
tabPane1.getTabs().add(tab);
} else {
tabPane2.getTabs().add(tab);
}
}
primaryStage.setScene(new Scene(root, 600, 600));
primaryStage.show();
}
public TabPane createDndTabPane() {
final TabPane tabPane = new TabPane();
tabPane.setOnDragOver(event -> {
if (event.getDragboard().hasContent(TAB_TYPE)
&& dndTab.getTabPane() != tabPane) {// && different from source location
event.acceptTransferModes(TransferMode.MOVE);
event.consume();
}
});
tabPane.setOnDragDropped(event -> {
if (event.getDragboard().hasContent(TAB_TYPE)
&& dndTab.getTabPane() != tabPane) {// && different from source location
dndTab.getTabPane().getTabs().remove(dndTab);
tabPane.getTabs().add(dndTab);
event.setDropCompleted(true);
event.consume();
}
});
return tabPane;
}
private Tab createDraggableTab(String text) {
final Tab tab = new Tab();
final Label label = new Label(text);
tab.setGraphic(label);
label.setOnDragDetected(event -> {
Dragboard dragboard = label.startDragAndDrop(TransferMode.MOVE);
ClipboardContent clipboardContent = new ClipboardContent();
clipboardContent.put(TAB_TYPE, 1);
dndTab = tab;
dragboard.setContent(clipboardContent);
event.consume();
});
return tab ;
}
}