I'm playing around with JavaFX and wanted to add a tooltip that pops up with the data value when the mouse is hovering over the node. I found several links and answers out there describing CSS methods for doing it, or using Tooltip.install(node, tooltip) and while I could get a tooltip working on a dummy example, I was still having no luck with the chart, using code like so :
LineChart<Number, Number> chart = new LineChart(xaxis, yaxis);
ObservableList<Data<Number, Number>> data = FXCollections.observableArrayList();
Data<Number, Number> d1 = new XYChart.Data<Number, Number>(5, 15);
Tooltip tooltip = new Tooltip("15");
Tooltip.install(d1.getNode(), tooltip);
data.add(d1);
Data<Number, Number> d2 = new XYChart.Data<Number, Number>(10, 25);
Tooltip tooltip2 = new Tooltip("25");
Tooltip.install(d2.getNode(), tooltip2);
data.add(d2);
chart.setData(data);
//add chart to scene etc etc etc
After some digging, the issue here is that a data element (XYChart.Data) does not have a node created at construction time. chart.setData(data) will populate the node field - I believe this is to allow the user to create and set their own nodes if so desired. So d1.getNode() is actually returning null, and Tooltip.install() is silently failing.
Moving the Tooltip.install call after chart.setData solves the issue.
Related
I have a basic question for JavaFX but coudn't figure it out. For HBox, When I'm using getChildren().addAll() for Label and ImageView, I get the following message:
The method addAll(int, Collection<? extends Node>) in the type List<Node> is not applicable for the argument (Label, ImageView[])
I'm not sure what's the issue. I can use normally if its (TextField, ImageView[]), but it doesn't work for (Label, ImageView[]).
This is my simplified code:
ImageView[] imagesRow = new ImageView[2];
Image[] img = new Image[2];
String title = "Result";
img[0] = new Image("sample1.png", 60, 35, true, true);
img[1] = new Image("sample2.png", 60, 35, true, true);
imagesRow[0] = new ImageView();
imagesRow[1] = new ImageView();
imagesRow[0].setImage (img[0]);
imagesRow[1].setImage (img[1]);
Label label = new Label();
label.setText(title + ": ");
// Create horizontal box
HBox box = new HBox();
box.setPadding(new Insets(20, 5 , 2, 50));
box.getChildren().addAll(label, imagesRow); // issue here
May I seek the reason and what should I do instead to align label and image horizontally?
Thanks in advance.
A Collection needs to be of one type (or inheriting from a common parent somewhere in the heirarchy).
A Label is a type of Node and therefore anything else you try to pass as a part of the Collection parameter must also be a Node. An array is obviously not.
In your case, you would need to use two calls to populate the children of the HBox:
box.getChildren().add(label);
box.getChildren().addAll(imagesRow);
The reason you can call addAll(imagesRow) without a problem is because with only the one argument, you're only passing in one Collection, an array.
By calling addAll(label, imagesRow), you're telling Java that you're passing a Collection of one type, but you actually passed it a Node and an array.
In the controller of my view, I created a list of HBoxes for the input of different values, each hbox consists of a textfield with an index number and two text boxes with information I want to retrieve. This is how I dynamically create each HBox.
void addRowToList() {
HBox hb = new HBox(50);
Text num = new Text(Integer.toString(numEdges + 1));
hb.getChildren().add(num);
TextField sep = new TextField();
makeNumeric(sep);
hb.getChildren().add(sep);
TextField area = new TextField();
makeNumeric(area);
hb.getChildren().add(area);
rows.add(hb);
}
After this, there is a point in which I need the information from those textBoxes in order to continue the execution of my program, my question is what is the method should I follow to access these since they don't have any given id? Thanks in advance.
since my code is quite long, I'll try to only describe the issue first to see if someone has faced it before.
I have a TableView that i populate with various objects which works just fine. I created a context menu so whenever I right-click an Item i can edit certain columns. Everything works fine but when i maximize the window, I cant select any Items anymore by clicking on them.
Has anyone faced that issue before?
Thx for the help!
edit:
I added some lines of code. Im using Java 1.8.
anchorPane = new AnchorPane();
anchorPane.setMaxWidth(550.0);
tabPane = new TabPane();
tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
tabPane.setTabMinHeight(22.0);
tabPane.setPrefWidth(this.navigationWidth);
homeTableView = new TableView<Player>();
homeTableView.setEditable(true);
homeTableView.setContextMenu(homeContextMenu);
List<Player> test= mainWindow.getHomeTeamPlayer();
ObservableList<Player> homeTeamPlayer = FXCollections.observableArrayList(test);
homeTableView.setItems(homeTeamPlayer);
homeTableView.setContextMenu(homeContextMenu);
Field[] fields = Player.class.getDeclaredFields();
for(Field field: fields){
// Get column information from Metadata
ColumnMetadata columnMetadata = field.getAnnotation(ColumnMetadata.class);
if(!columnMetadata.showInTable()) continue;
TableColumn<Player, String> HomeCol = new TableColumn<>(columnMetadata.displayTitle());
HomeCol.setCellValueFactory(new PropertyValueFactory<>(field.getName()));
if(columnMetadata.isEditable()){
HomeCol.setEditable(true);
}
homeTableView.getColumns().add(HomeCol);
}
homeTab = addTab("homename", homeTableView);
AnchorPane.setRightAnchor(tabPane, 0.0);
AnchorPane.setLeftAnchor(tabPane, 0.0);
AnchorPane.setTopAnchor(tabPane, 0.0);
AnchorPane.setBottomAnchor(tabPane, 0.0);
anchorPane.getChildren().addAll(tabPane);
public Tab addTab(String name, TableView tableView){
Tab tab = new Tab();
tab.setText(name);
tab.setContent(tableView);
tabPane.getTabs().addAll(tab);
return tab;
}
I get this weird exception and I think that it is a bug. I am trying to clear a Series, which contains a list of points to plot in the graph. However, after clearing I want to add new Data and this gives me a nul pointer exception. My code:
public static void main(String[] args) {
Series<String, Number> series = new Series<String, Number>();
Number value1 = new Integer(5);
Number value2 = new Integer(6);
Data<String, Number> point1 = new Data<String, Number>("Something", value1);
Data<String, Number> point2 = new Data<String, Number>("Something", value2);
series.getData().add(point1);
series.getData().add(point2);
series.getData().clear();
Number value3 = new Integer(7);
Data<String, Number> point3 = new Data<String, Number>("Something", value3);
**series.getData().add(point3);**
}
I get a null pointer exception at the marked code line. I just need a way to reset this series, but to me it seems like a bug in JavaFX. I use Java 8, which has JavaFX as an integration.
Can someone help me?
The technical reason is a NPE in the listener on the data list, installed by series:
if (c.getAddedSize() > 0) {
for (Data<X,Y> itemPtr = begin; itemPtr != null; itemPtr = itemPtr.next) {
if (itemPtr.setToRemove) {
getChart().dataBeingRemovedIsAdded(itemPtr, Series.this);
itemPtr.setToRemove = false;
}
}
}
This will throw on the next addition if an item had been deleted while the chart is null.
The deeper reason is the slightly convoluted delete mechanism: the series doesn't delete the item itself but only marks it as ready for deletion. Then it delegates the change to its chart which then calls back into the series to do the actual delete. And that mechanism breaks if there is no chart.
Real solutions might be hard from the outside, because everything is so tightly and secretly knitted - no way to hook your own listener to do the actual remove. If you really have to manipulate (remove items) the series without a chart attached, you might try to implement a dummy chart and set that to the series.
I have an application that I am building that has a table in it, I'm not using a tableview to build this table because I need each row to be able to expand similar to an accordion. I was able to achieve what I need by using a timeline and looping through the data and building each row (its kind of crude right now since I'm still working with dummy data eventually it will be a list iterator and not just a for loop) but I'm not happy with how its done. There are a lot of default values that will never change so I don't really need to set them in my worker class every time, I decided to just add them to the object class that I put together. So basically, at a high level it looks something like this:
for (int i = 0; i < 30; i++) {
RowBuilder builder = new RowBuilder(tableBox, i);
try {
builder.run();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I'm passing it the parent which is a VBox - tableBox, then I'm passing the count for later use.
Inside the RowBuilder I'm getting a new instance of the object DashboardRow which has all the defaults set in it, then I'm setting the data for each row and returning the DashboardRow.
Here is an example of a getter setting values in the DashboardRow
public HBox getMainRow() {
mainRow.setAlignment(Pos.CENTER_LEFT);
mainRow.setPrefHeight(60);
mainRow.setMinHeight(60);
mainRow.setMaxHeight(60);
mainRow.setPrefWidth(-1);
mainRow.setStyle("-fx-background-color:#FFFFFF;");
return mainRow;
}
Inside the DashboardRow class I have a ton of new objects being created for every element I need in the row. There are 21 for each row, mostly VBox, HBox and StackPane to build the actual row, the rest are just labels and buttons.
This is what is looks like so far. Opened and closed states.
Is there a better way to dynamically build things like this in javafx? I'm basically pulling data from a database and looping through that data to populate a row.
I can't comment but it may be an answer anyway. Why can't you use the setGraphic method of a custom table cell and put the accordion node in a table. setGraphic takes any kind of node.
It sounds simpler than what you're doing.
I just tried it out with the Oracle sample and it works great.
I added
Callback<TableColumn<Person, String>, TableCell<Person, String>> accCellFactory
= new Callback<TableColumn<Person, String>, TableCell<Person, String>>() {
#Override
public TableCell call(TableColumn p) {
TitledPane t1 = new TitledPane("T1", new Button("B1"));
TitledPane t2 = new TitledPane("T2", new Button("B2"));
TitledPane t3 = new TitledPane("T3", new Button("B3"));
Accordion accordion = new Accordion();
accordion.getPanes().addAll(t1, t2, t3);
TableCell tc = new TableCell();
tc.setGraphic(accordion);
return tc;
}
};
and changed this line firstNameCol.setCellFactory(accCellFactory);
and I get
Of course you might want something other than buttons but I just copied the Accordion sample from the javadoc.