How can I access the icon.png file without specifing the whole path "main/res/images/icon.png" in ClassLoader.getSystemResource()? I wanted something like images/icon.png.
This is the project explorer
Main.java:
package main.java.OOP20.alt.sim.View;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.image.Image;
import java.awt.*;
public class Main extends Application {
public static final double PROPORTION = 1.5;
#Override
public void start(final Stage primaryStage) throws Exception {
final Dimension dimension = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
final double width = dimension.getWidth() / PROPORTION;
final double height = dimension.getHeight() / PROPORTION;
final Parent root=FXMLLoader.load(
ClassLoader.getSystemResource("main/res/layouts/sample.fxml")
);
primaryStage.setTitle("Title");
primaryStage.setScene(new Scene(root, width, height));
primaryStage.getIcons().add(
new Image(ClassLoader.getSystemResource("main/res/images/icon.png").toString())
);
primaryStage.show();
}
public static void main(final String[] args) {
launch(args);
}
}
You can get url of both fxml or png files with using Class<T>#getResource(). You should use following solutions:
For fxml file:
Parent root = FXMLLoader.load(getClass().getResource("/layouts/sample.fxml"));
For png file:
primaryStage.getIcons().add(new Image(getClass().getResource("/images/icon.png").toString()));
Note: If you want to load any external resources (fxml, png etc) from resource folder within static methods, you must use Main.class.getClass() instead of getClass(). It guarantees the resource will be loaded relative to that class, and never relative to a subclass.
I'm trying to write the path in the main class to load a FXML file MenuFXML.fxml but I can't figure out the correct way to do so. The FXML file is in the package com.developer.fxml and the main class is in com.developer.
I've already tried the path /com/developer/fxml/MenuFXML.fxml and /fxml/MenuFXML.fxml but neither of them work.
package com.developer;
import com.developer.exit.ExitApplication;
import com.developer.util.css.AddCSS;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
private Stage stage;
private Scene scene;
private final String title = "Stock Program 2.0";
private Parent root;
private final AddCSS addcss = new AddCSS();
#Override
public void start(Stage primaryStage) throws IOException {
stage = primaryStage;
stage.setTitle(title);
stage.setOnCloseRequest(e -> {
e.consume();
ExitApplication ep = new ExitApplication();
ep.closeProgram(stage);
});
//The part that I can't get to work
root = FXMLLoader.load(getClass().getResource("/fxml/MenuFXML.fxml"));
scene = new Scene(root);
addcss.setStylesheet(scene);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
so I'm writing a javafx app and I need to be able to select the cells from the list view (for copy paste purposes) but I don't want to make it editable, I mean, the content cannot be changed unless I want to (allowing it through a button, for example).
So I have the following code:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
List<String> contacts = new ArrayList<>(Arrays.asList("968787522","3424234234","2343234324"));
ListView<String> contactsList = new ListView();
contactsList.setItems(FXCollections.observableArrayList(contacts));
//this gives me the ability to edit the row as text field but I want this text field to not be editable
contactsList.setCellFactory(TextFieldListCell.forListView());
StackPane pane = new StackPane();
pane.getChildren().add(contactsList);
primaryStage.setScene(new Scene(pane, 300, 275));
primaryStage.show(); }
public static void main(String[] args) {
launch(args);
}
}
and if I set 'contactsList' as not editable, I'm not able to edit, neither select.
As you can see (image bellow),I'm editing the cell, but I want to be able to select the text(not the item), but I don't want to be able to delete characters (text selectable but not editable).
so after breaking my head off, lots of research and API reading, I came up with a solution. This does EXACTLY what I wanted to do. Here is the demo if someone needs it ;)
So the idea is, each time we want to select the content of a row we need to select the row, get the textField and set the editing to true or false, (every time).
So in the demo that I made, I placed a button so you can toggle the editing to true or false to be sure that's is working, and how is working.
Cheers.
I commented some of the code for better understanding, if you have any questions about this just let me know.
package sample;
import com.sun.javafx.scene.control.skin.VirtualFlow;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main extends Application {
private boolean editable = false;
public static IndexedCell getCell(final Control control, final int index) {
return getVirtualFlow(control).getCell(index);
}
public static VirtualFlow<?> getVirtualFlow(Control control) {
Group group = new Group();
Scene scene = new Scene(group);
Stage stage = new Stage();
if(control.getScene() == null) {
group.getChildren().setAll(control);
stage.setScene(scene);
stage.show();
}
VirtualFlow<?>flow = (VirtualFlow<?>) control.lookup("#virtual-flow");
return flow;
}
public void setEditable(ListView contactsList){
//this needs to be done since we need to run our code after the text field was rendered
//so we need to invoke our code after this happens, if not it will throw a null pointer...
Platform.runLater(() -> {
//this is one of the most important guys because javafx api says that
//TextFieldListCell.forListView() allows editing of the cell content when the cell is double-clicked,
// or when {#link ListView#edit(int)} is called.
int rowIndex = contactsList.getSelectionModel().getSelectedIndex();
contactsList.edit(rowIndex);
ListCell rootCell = (ListCell) getCell(contactsList, rowIndex);
TextField textField = (TextField) rootCell.getGraphic();
textField.setEditable(editable);
});
}
#Override
public void start(Stage primaryStage) throws Exception{
List<String> contacts = new ArrayList<>(Arrays.asList("968787522","3424234234","2343234324"));
ListView<String> contactsList = new ListView();
contactsList.setItems(FXCollections.observableArrayList(contacts));
contactsList.setEditable(true);
//this gives me the ability to edit the row as text field but I want this text field to not be editable
contactsList.setCellFactory(TextFieldListCell.forListView());
contactsList.setOnEditStart(e -> {
setEditable(contactsList);
});
StackPane pane = new StackPane();
Button editBtn = new Button("Toggle edit");
editBtn.setOnAction(event -> {
editable = !editable;
editBtn.setText("Editing = " + editable);
//to cancel any editing that might be occuring
contactsList.getSelectionModel().clearSelection();
});
pane.getChildren().addAll(contactsList,editBtn);
primaryStage.setScene(new Scene(pane, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If I understand you correctly, it is not necessary to set the listview to 'not editable', as the default behaviour should suffice for your purpose. Take a look at this code, for example:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class NewFXMain extends Application {
#Override
public void start(Stage primaryStage) {
ListView listView = new ListView();
listView.getItems().addAll("one","two","three","four");
listView.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println(listView.getSelectionModel().getSelectedItem());
}
});
StackPane root = new StackPane();
root.getChildren().add(listView);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("ListView Example");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I changed nothing about the editable-property of the ListView, but I can select every item, without being able to edit it (in the sense of changing its value). You can easily add an EventHandler to the ListView to perform whatever operation you want to perform. You could also add an EventHandler to every cell of the ListView by manipulating the CellFactory, as shown in this answer: How to handle ListView item clicked action?
Here's what works for me:
TableView<DataBean> table = new TableView<>();
table.setItems(...); // list of some DataBean objects with dataBeanField proprty
table.setEditable(true);
TableColumn<DataBean, String> column = new TableColumn<>("SomeData");
column.setCellValueFactory(new PropertyValueFactory<DataBean, String>("dataBeanField"));
column.setCellFactory(new Callback<TableColumn<DataBean, String>, TableCell<DataBean, String>>() {
#Override
public TableCell<DataBean, String> call(TableColumn<DataBean, String> param) {
return new TextFieldTableCell<>(new DefaultStringConverter() {
private String defaultValue = "";
#Override
public String fromString(String newValue) {
return super.fromString(defaultValue);
}
#Override
public String toString(String value) {
return defaultValue = super.toString(value);
}
});
}
});
I first noticed this by having a huge memory leak caused by resizing javafx.scene.control.Pagination.
I created a sample app to show the behavior. Every click on any button causes more memory to be consumed. I suppose that the correct way to deal with this is to remove any listeners on the ToggleButtons before clearing them but PaginationSkin isn't doing that.
Have I missed something or is this a real bug in the Pagination code?
Are there any workarounds?
The same behavior is seen it both 8u40 and 8u45. I haven't tried any older versions yet.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class ToggleGroupLeak extends Application {
private HBox hbox;
private ToggleGroup toggleGroup;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
toggleGroup = new ToggleGroup();
hbox = new HBox();
redo();
root.getChildren().add(hbox);
primaryStage.setScene(new Scene(root, 700, 100));
primaryStage.show();
}
private void redo() {
hbox.getChildren().clear();
toggleGroup.getToggles().clear();
for (int i = 0; i < 20; i++) {
addButton(i);
}
}
private void addButton(final int i) {
ToggleButton btn = new ToggleButton("" + i);
btn.setToggleGroup(toggleGroup);
btn.setOnAction(e -> redo());
hbox.getChildren().add(btn);
}
}
Concretely, usage of Pagination in an AnchorPane seems to cause the same leak by resizing the control.
FXML
<Pagination fx:id="pagination" visible="true" AnchorPane.topAnchor="3.0" AnchorPane.leftAnchor="12.0" AnchorPane.rightAnchor="130.0"/>
Java
#FXML
protected Pagination pagination;
// Init method run once
pagination.setMaxPageIndicatorCount(100);
pagination.currentPageIndexProperty().addListener((observable, oldPageIndex, newPageIndex) -> {
if (!oldPageIndex.equals(newPageIndex)) {
if (searchParams.getPage() == newPageIndex.intValue()) {
return;
}
searchParams.setPage(newPageIndex.intValue());
// Code that inits the new page
}
});
EDIT: Added pagination specific code
I have an app in JavaFX that is getting a bit large, and I want to keep the code readable.
I have a LineChart that I want to have zoom functionality built in, that occurs on a mouseclick. I know I need to register a mouse listener to the chart. What I cannot figure out from Oracle examples, ie as written here:
http://docs.oracle.com/javafx/2/events/handlers.htm
is how to NOT have my handler defined inline to the registering. In other words, I want the body of the handler (which is many lines of code) to be in another class. Can I do that? And if so, how do I register the handler to my chart in my main Javafx controller code?
Place your handler in a new class which implements the the Mouse EventHandler and register an instance of your class with your target node via the node's setOnClicked method.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
* JavaFX sample for registering a click handler defined in a separate class.
* http://stackoverflow.com/questions/12326180/registering-mouse-handler-but-handler-not-inline-in-javafx
*/
public class ClickHandlerSample extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(final Stage stage) throws Exception {
stage.setTitle("Left click to zoom in, right click to zoom out");
ImageView imageView = new ImageView("http://upload.wikimedia.org/wikipedia/commons/b/b7/Idylls_of_the_King_3.jpg");
imageView.setPreserveRatio(true);
imageView.setFitWidth(150);
imageView.setOnMouseClicked(new ClickToZoomHandler());
final StackPane layout = new StackPane();
layout.getChildren().addAll(imageView);
layout.setStyle("-fx-background-color: cornsilk;");
stage.setScene(new Scene(layout, 400, 500));
stage.show();
}
private static class ClickToZoomHandler implements EventHandler<MouseEvent> {
#Override public void handle(final MouseEvent event) {
if (event.getSource() instanceof Node) {
final Node n = (Node) event.getSource();
switch (event.getButton()) {
case PRIMARY:
n.setScaleX(n.getScaleX()*1.1);
n.setScaleY(n.getScaleY()*1.1);
break;
case SECONDARY:
n.setScaleX(n.getScaleX()/1.1);
n.setScaleY(n.getScaleY()/1.1);
break;
}
}
}
}
}