I am trying to add GUIs, created from individual files and add them into my main code.
While it seems to be working, kind of, however, it is missing some elements. For example, in my GridPane, there are a label and a text, both of which are missing. Likewise, for my treeview, there is a treeitem within, however, that is missing as well.
What I am trying to attempt is to reduce the amount of code in the main field and as well as to call relevant events between the Guis, eg. if I select something in the TreeView, that selected TreeItem information will be populated in the GridPane.
Client.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Client extends Application
{
private treeviewGui tvGui;
private gridpaneGui inputFieldsGui;
public void init()
{
tvGui = new treeviewGui();
inputFieldsGui = new gridpaneGui();
}
#Override
public void start(Stage topView)
{
topView.setTitle("Test Application");
HBox mainLayout = new HBox(10);
mainLayout.getChildren().addAll(tvGui, inputFieldsGui);
Scene scene = new Scene(mainLayout);
topView.centerOnScreen();
topView.setScene(scene);
topView.show();
}
public static void main(String[] argv)
{
launch(argv);
}
}
treeviewGui.java
import javafx.scene.control.*;
public class treeviewGui extends TreeView
{
private TreeView treeview;
public treeviewGui()
{
treeview = new TreeView();
preload();
}
private void preload()
{
TreeItem<String> newTI = new TreeItem<>("blah");
treeview.setRoot(newTI);
}
}
gridPane.java
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.geometry.Pos;
import javafx.scene.text.Text;
public class gridpaneGui extends GridPane
{
private GridPane gridPane;
public Text fnameTxt;
public gridpaneGui()
{
gridPane = new GridPane();
gridPane.setAlignment(Pos.CENTER);
gridPane.setHgap(5);
gridPane.setVgap(5);
// First Name
Label fnameLbl = new Label("First Name");
fnameTxt = new Text("-");
gridPane.addRow(0, fnameLbl, fnameTxt);
}
public void setFname(String nameStr)
{
fnameTxt.setText(nameStr);
}
}
Related
I want to ask if it is possible to make a chip in JFXChipView editable once it has been set.
You can create your own JFXChip and implement a behavior to enable editing. First, you need to have an editable label. I looked up online and I found this post: JavaFX custom control - editable label. Then, you can extend JFXChip to use that EditableLabel:
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXChip;
import com.jfoenix.controls.JFXChipView;
import com.jfoenix.svg.SVGGlyph;
import javafx.beans.binding.Bindings;
import javafx.beans.property.Property;
import javafx.scene.layout.HBox;
public class EditableChip<T> extends JFXChip<Property<T>> {
protected final HBox root;
public EditableChip(JFXChipView<Property<T>> view, Property<T> item) {
super(view, item);
JFXButton closeButton = new JFXButton(null, new SVGGlyph());
closeButton.getStyleClass().add("close-button");
closeButton.setOnAction(event -> {
view.getChips().remove(item);
event.consume();
});
// Create the label with an initial value from the item
String initialValue = view.getConverter().toString(item);
EditableLabel label = new EditableLabel(initialValue);
label.setMaxWidth(100);
// Bind the item to the text in the label
item.bind(Bindings.createObjectBinding(() -> view.getConverter().fromString(label.getText()).getValue(), label.textProperty()));
root = new HBox(label, closeButton);
getChildren().setAll(root);
}
}
Note: I am using Property<T> instead of using the desired class T because JFXChipView stores the item the first time you add it. And in that case, you're going to get the values as you entered them the first time when calling JFXChipView#getChips().
Sample application:
import com.jfoenix.controls.JFXChipView;
import javafx.application.Application;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class EditableChipViewApp extends Application {
#Override
public void start(Stage primaryStage) {
JFXChipView<Property<String>> chipView = new JFXChipView<>();
chipView.setChipFactory(EditableChip::new);
chipView.setConverter(new StringConverter<Property<String>>() {
#Override
public String toString(Property<String> object) {
return object == null ? null : object.getValue();
}
#Override
public Property<String> fromString(String string) {
return new SimpleStringProperty(string);
}
});
VBox container = new VBox(chipView);
Scene scene = new Scene(container, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Result:
This is how you get the actual values of the chips:
List<String> chipsValues = chipView.getChips().stream().map(Property::getValue).collect(Collectors.toList());
I have a JavaFX list using flowless project. But I get a strange border (I have not enabled any border and forced the border to have width=0px) that is present and has a gradient effect:
When I set the cell background-inset to -1, the border is gone, so I believe this issue is related to the background. Although this is not a solution because if I enable the border (which I want to), the gradient effect is still present.
Does anyone knows how I can get rid of this border?
I use JavaFX 8 with latest 201 release.
EDIT: I made the following example show casing the issue:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.stage.Stage;
import org.fxmisc.flowless.Cell;
import org.fxmisc.flowless.VirtualFlow;
import org.fxmisc.flowless.VirtualizedScrollPane;
public class Main extends Application {
private ObservableList<Line> logLines;
private VirtualFlow<Line, Cell<Line, LineCell>> listView;
private VirtualizedScrollPane<VirtualFlow> listScrollPane;
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
logLines = FXCollections.observableArrayList();
for(int i=1; i < 50; i++) {
logLines.add(new Line("Line "+i));
}
listView = VirtualFlow.createVertical(logLines, (line) -> Cell.wrapNode(new LineCell(line)));
listScrollPane = new VirtualizedScrollPane<>(listView);
Scene scene = new Scene(listScrollPane, 200, 600, Color.BLACK);
primaryStage.setScene(scene);
primaryStage.show();
}
private class Line {
private String text;
public Line(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
private class LineCell extends TextFlow {
public LineCell(Line line) {
super();
Text t = new Text(line.getText());
t.setFill(Color.BLACK);
super.setStyle("-fx-background-color: green;");
super.getChildren().add(t);
}
}
}
Thanks!
I have found a solution to this issue. Instead of LineCell extending TextFlow, it now extends StackPane and I add the TextFlow to the Stackpane.
private class LineCell extends StackPane {
public LineCell(Line line) {
super();
Text t = new Text(line.getText());
t.setFill(Color.BLACK);
TextFlow tf = new TextFlow(t);
super.setStyle("-fx-background-color: green;");
super.getChildren().add(tf);
}
}
I am still pretty new to java and i am still learning. I have never used images before so it is possible if I can have help add a image. I am not that sure what needs to be done in order to add one. Thank you
enter image description here
here is the code:
import javafx.application.Application;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
class User {
private StringProperty order = new SimpleStringProperty();
public String getOrder() {
return order.get();
}
public void setOrder(String order) {
this.order.set(order);
}
public StringProperty orderProperty() {
return order;
}
}
public class pizza extends Application {
private User user = new User();
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("Pizza System");
Button btn = new Button();
btn.setText("place order");
BorderPane pane = new BorderPane();
pane.setBottom(btn);
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
btn.setText("Order has been placed. Please wait at least 30 minutes.");
}
});
RadioButton tomatoButton = new RadioButton("Tomato");
RadioButton pepperButton = new RadioButton("Pepper");
RadioButton mushroomButton = new RadioButton("Mushrooms");
ChoiceBox<String> pizzaType = new ChoiceBox<String>();
pizzaType.getItems().addAll("", "Small", "Medium", "Large");
pizzaType.getSelectionModel().selectFirst();
HBox topHBox = new HBox(15.0, tomatoButton, pepperButton, mushroomButton, pizzaType);
// create custom Binding that binds selection of radio buttons and choice box
StringBinding orderBinding = createOrderBinding(tomatoButton.selectedProperty(), pepperButton.selectedProperty(), mushroomButton.selectedProperty(), pizzaType.getSelectionModel().selectedItemProperty());
// bind orderBinding to orderProperty of User
user.orderProperty().bind(orderBinding);
TextArea orderArea = new TextArea();
// bind orderProperty of User to textProperty of TextArea
orderArea.textProperty().bindBidirectional(user.orderProperty());
BorderPane root = new BorderPane();
root.setTop(topHBox);
root.setCenter(orderArea);
root.setBottom(btn);
Scene scene = new Scene(root, 400, 300);
stage.setScene(scene);
stage.show();
}
public StringBinding createOrderBinding(BooleanProperty tomato, BooleanProperty pepper, BooleanProperty mushroom, ReadOnlyObjectProperty<String> selectedPizzaType) {
StringBinding binding = new StringBinding() {
{
// bind 4 provided properties.
super.bind(tomato, pepper, mushroom, selectedPizzaType);
}
#Override
protected String computeValue() {
StringBuilder sb = new StringBuilder("Pizza content:\n");
if (tomato.get())
sb.append("\tTomato\n");
if (pepper.get())
sb.append("\tPepper\n");
if (mushroom.get())
sb.append("\tMushroom\n");
sb.append("Pizza type:\n").append("\t" + selectedPizzaType.get());
return sb.toString();
}
};
return binding;
}
public static void main(String[] args) {
Application.launch(args);
}
}
JavaFX uses an Image to load the image file and it has a node called ImageView to place that image on the screen graph.
Considering that the image is present at the same location as your class file, you can use this:
// Load Image
Image image = new Image(getClass().getResource("image.jpg").toExternalForm());
// Set the Image on the ImageView
ImageView imageView = new ImageView(image);
// specify a size
imageView.setFitWidth(200);
imageView.setFitHeight(200);
// Place ImageView in a container
root.setRight(imageView);
I try to create a label on click for my PieChart, but unfortunately my label is never visible.
I found a similar topic on StackOverFlow : Label not showing on mouse event JavaFx
But my application is not as simple. I can't add my Label to the list of children because of my architecture.
(You can found a diagram here : http://i.stack.imgur.com/ZFJaR.png )
Here my code :
PieChartNode.java
package nodeStatsVision.chartFactory;
import java.util.ArrayList;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import nodeStatsVision.beans.ListRepere;
import nodeStatsVision.beans.OptionsChart;
import nodeStatsVision.beans.ValueStat;
/**
*
* #author Zombkey.
*/
public class PieChartNode implements ChartNode {
private ListRepere categories;
private ArrayList<ValueStat> values;
private ObservableList<PieChart.Data> pieChartData;
private Node node;
public PieChartNode(ListRepere categories, ArrayList<ValueStat> values){
this.categories = categories;
this.values = values;
pieChartData = FXCollections.observableArrayList();
node = new PieChart(pieChartData);
Platform.runLater(new Runnable() {
#Override
public void run() {
formatData();
}
});
}
private void formatData() {
final Label caption = new Label("");
caption.setTextFill(Color.DARKORANGE);
caption.setStyle("-fx-font: 24 arial;");
for(ValueStat v : values){
PieChart.Data dataTemp = new PieChart.Data(v.getCategorie().getStringName(),v.getDoubleValue());
pieChartData.add(dataTemp);
dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent e) {
System.out.println("event : "+v.getCategorie().getStringName()+" : "+v.getDoubleValue());
caption.setTranslateX(e.getSceneX());
caption.setTranslateY(e.getSceneY());
caption.setText(String.valueOf(dataTemp.getPieValue()));
caption.setVisible(true);
System.out.println("label "+caption);
}
});
}
}
#Override
public Node getNodeGraph() {
return node;
}
#Override
public void setOptions(OptionsChart optionsChart) {
//To implemente
}
}
Have you a idea about, how add my Label to the scene ?
Thanks !
(Other question, Why the Node of PieChart.Data is on ReadOnly ?)
Zombkey.
PS : Sorry about my english, I'm a French student, I'm still learning :)
Ps 2 : First time on StackOverflow, if I did mistake, tell me it !
Ok ! I found a solution for my case !
Semantically my Label is only for my PieChart. That's why I don't want had it to my SceneGraph.
My ChartFactory return a Node, then display it. So my node have to contain the PieChart AND the Label.
I create a Group with a StackPane. In the StackPane I add my PieChart and my Label. Then my factory return the Group as a Node.
Drop the code !
package nodeStatsVision.chartFactory;
import java.util.ArrayList;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import nodeStatsVision.beans.ListRepere;
import nodeStatsVision.beans.OptionsChart;
import nodeStatsVision.beans.ValueStat;
/**
*
* #author Zombkey.
*/
public class PieChartNode implements ChartNode {
private ListRepere categories;
private ArrayList<ValueStat> values;
private ObservableList<PieChart.Data> pieChartData;
private Group group;
private Node node;
private final Label caption;
public PieChartNode(ListRepere categories, ArrayList<ValueStat> values){
this.categories = categories;
this.values = values;
group = new Group();
StackPane pane = new StackPane();
group.getChildren().add(pane);
pieChartData = FXCollections.observableArrayList();
node = new PieChart(pieChartData);
pane.getChildren().add(node);
caption = new Label("");
caption.setVisible(false);
caption.getStyleClass().addAll("chart-line-symbol", "chart-series-line");
caption.setStyle("-fx-font-size: 12; -fx-font-weight: bold;");
caption.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
pane.getChildren().add(caption);
Platform.runLater(new Runnable() {
#Override
public void run() {
formatData();
}
});
}
private void formatData() {
for(ValueStat v : values){
PieChart.Data dataTemp = new PieChart.Data(v.getCategorie().getStringName(),v.getDoubleValue());
pieChartData.add(dataTemp);
dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_ENTERED,
new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent e) {
caption.setTranslateX(e.getX());
caption.setTranslateY(e.getY());
caption.setText(String.valueOf(dataTemp.getPieValue()));
caption.setVisible(true);
}
});
dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_EXITED,
new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent e) {
caption.setVisible(false);
}
});
}
}
#Override
public Node getNodeGraph() {
return (Node)group;
}
#Override
public void setOptions(OptionsChart optionsChart) {
//To implemente
}
}
Thanks #eckig for your answers !
You create and style your Label named caption but never add it to the SceneGraph.
Somewhere it has to be added to a Parent element, otherwise it will not get displayed.
Your PieChart gets added to a parent element, otherwise it will not be displayed. The same way goes for all other JavaFX Nodes.
As to your second question, read the JavaDocs:
Readonly access to the node that represents the pie slice. You can use this to add mouse event listeners etc.
You could use Tooltip to display a value:
for (final PieChart.Data temp : pieChart.getData()) {
Tooltip tooltip = new Tooltip(String.valueOf(temp.getPieValue()));
Tooltip.install(temp.getNode(), tooltip);
}
I'm trying to reproduce a Pagination Sample from oracle samples, but when I imported the project something strange happened that I can not build and run the project:
The complete code is:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
public class PaginationSample extends Application {
private final Pagination pagination;
private Image[] images = new Image[7];
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));
VBox outerBox = new VBox();
outerBox.setAlignment(Pos.CENTER);
//Images for our pages
for (int i = 0; i < 7; i++) {
images[i] = new Image(PaginationSample.class.getResource("animal" + (i + 1) + ".jpg").toExternalForm(), false);
}
pagination = PaginationBuilder.create().pageCount(7).pageFactory(new Callback<Integer, Node>() {
#Override public Node call(Integer pageIndex) {
return createAnimalPage(pageIndex);
}
}).build();
//Style can be numeric page indicators or bullet indicators
Button styleButton = ButtonBuilder.create().text("Toggle pagination style").onAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent me) {
if (!pagination.getStyleClass().contains(Pagination.STYLE_CLASS_BULLET)) {
pagination.getStyleClass().add(Pagination.STYLE_CLASS_BULLET);
} else {
pagination.getStyleClass().remove(Pagination.STYLE_CLASS_BULLET);
}
}
}).build();
outerBox.getChildren().addAll(pagination, styleButton);
root.getChildren().add(outerBox);
}
//Creates the page content
private VBox createAnimalPage(int pageIndex) {
VBox box = new VBox();
ImageView iv = new ImageView(images[pageIndex]);
box.setAlignment(Pos.CENTER);
Label desc = new Label("PAGE " + (pageIndex + 1));
box.getChildren().addAll(iv, desc);
return box;
}
#Override public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) { launch(args); }
}
But netbeans show me the error "cannot assign a value to final variable pagination" for the following line:
pagination = PaginationBuilder.create().pageCount(7).pageFactory(new Callback<Integer, Node>() {
Someone can explain me what is going wrong??
A final field can be initialized only once. So the best place to initialize it is when its declared
private final Pagination pagination = new Pagination(...);
or it can be done in the constructor, since the constructor is assured to be called once per instance
private final Pagination pagination;
public PaginationSample() {
pagination = new Pagination(...);
}
final field cannot be initialized in a method because a method can be called multiple times once an instance of that class gets created