Recently, I used the scene builder to draw a bar chart; however, the legend is not aligned correctly. When I use
barchart.setLegendSide(Side.BOTTOM);
the legend shows vertically as in the picture below while I wanted it to be shown horizontally.
Despite that, if I don't use the scene builder, there is no problem with the chart. Please show me the way to fix this issue.
Main file
package LinkedIn;
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 App extends Application{
#Override
public void start(Stage primaryStage) throws IOException{
Parent root = FXMLLoader.load(getClass().getResource("/LinkedIn/barchart.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setTitle("LinkedIn");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
FXML file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.chart.BarChart?>
<?import javafx.scene.chart.CategoryAxis?>
<?import javafx.scene.chart.NumberAxis?>
<BarChart fx:id="barchart" animated="false" barGap="10.0" categoryGap="20.0" title="Car Sales by Brands" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="LinkedIn.Controller">
<xAxis>
<CategoryAxis side="BOTTOM" fx:id="xAxis" />
</xAxis>
<yAxis>
<NumberAxis fx:id="yAxis" side="LEFT" />
</yAxis>
<padding>
<Insets bottom="25.0" left="5.0" right="5.0" top="5.0" />
</padding>
</BarChart>
Controller File
package LinkedIn;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Side;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.BorderPane;
public class Controller implements Initializable{
#FXML
private BarChart<String, Number> barchart;
#FXML
CategoryAxis xAxis;
#FXML
NumberAxis yAxis;
void loadData() {
xAxis.setLabel("Brand");
yAxis.setLabel("Value");
XYChart.Series<String, Number> series1 = new XYChart.Series<>();
series1.setName("Bob");
series1.getData().add(new XYChart.Data<String, Number>("Toyota", 200));
series1.getData().add(new XYChart.Data<String, Number>("Ford", 300));
series1.getData().add(new XYChart.Data<String, Number>("Jaguar", 50));
XYChart.Series<String, Number> series2 = new XYChart.Series<>();
series2.setName("Peter");
series2.getData().add(new XYChart.Data<String, Number>("Toyota", 500));
series2.getData().add(new XYChart.Data<String, Number>("Ford", 150));
series2.getData().add(new XYChart.Data<String, Number>("Jaguar", 100));
barchart.getData().add(series1);
barchart.getData().add(series2);
barchart.setLegendSide(Side.BOTTOM);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
loadData();
}
}
Related
I started to learn JavaFX for couple of days. I took a lot of stackoverflow examples, google-it, youtube videos, and all seems good in examples, but mine does not work and I don't know what I'm doing wrong.
So, I make tests only for now, nothing important, it is not an application in real world.
I've built a Custom Control using SceneBuilder, so this is the fxml file for it:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:id="cControl" prefHeight="100.0" prefWidth="100.0"
style="-fx-border-color: #111111; -fx-border-radius: 2; -fx-background-color: linear-gradient(from 50% 0% to 50% 100%, #f0f0f0, orangered); -fx-background-radius: 2;"
xmlns="http://javafx.com/javafx/19"
xmlns:fx="http://javafx.com/fxml/1"
>
<children>
<Button fx:id="btnClickMe" layoutX="12.0" layoutY="67.0" mnemonicParsing="false" onAction="#onClickMeAction" prefHeight="25.0" prefWidth="77.0" text="Button" AnchorPane.bottomAnchor="8.0" />
<Label fx:id="lblTitle" alignment="CENTER" contentDisplay="CENTER" focusTraversable="false" layoutY="1.0" prefHeight="43.0" prefWidth="100.0" text="Label" textAlignment="CENTER" AnchorPane.bottomAnchor="56.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="1.0" />
</children>
</AnchorPane>
The model is this:
PackTestModel.java
package com.myapp.customcontrols;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class PackTestModel {
public PackTestModel(String labelText) {
setLabelText(labelText);
}
public String getLabelText() {
return labelText.get();
}
public StringProperty labelTextProperty() {
return labelText;
}
public void setLabelText(String labelText) {
this.labelText.set(labelText);
}
private final StringProperty labelText = new SimpleStringProperty();
}
This is the controller:
package com.myapp.customcontrols;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import java.net.URL;
import java.util.ResourceBundle;
public class PackTestController implements Initializable {
#FXML
private Button btnClickMe;
#FXML
private Label lblTitle;
private final PackTestModel packTestModel;
public PackTestController(PackTestModel ptm) {
packTestModel = ptm;
}
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
lblTitle.textProperty().bind(packTestModel.labelTextProperty());
}
}
This is the code for my CustomControl class:
package com.myapp.customcontrols;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.layout.AnchorPane;
import java.io.IOException;
public class PackTestCC extends AnchorPane {
private PackTestController packTestController;
public PackTestCC(PackTestModel model) throws IOException {
super();
FXMLLoader loader = new FXMLLoader(getClass().getResource("PackTest.fxml"));
packTestController = new PackTestController(model);
loader.setController(packTestController);
try {
Node n = loader.load();
this.getChildren().add(n);
}catch (RuntimeException e){}
}
}
And my main application Main.java file looks like this:
package com.myapp;
import com.myapp.customcontrols.PackTestCC;
import com.myapp.customcontrols.PackTestModel;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URISyntaxException;
public class Main extends Application {
private MainController2 mainController;
#Override
public void start(Stage stage) throws IOException, URISyntaxException {
Font.loadFont(getClass().getResourceAsStream("Fonts/DINOTBold.otf"), 16);
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("main-view2.fxml"));
mainController = new MainController2();
fxmlLoader.setController(mainController);
Parent n = fxmlLoader.load();
Scene scene = new Scene(n, 800, 600);
mainController.getAnchorPane().getChildren().add(new PackTestCC(new PackTestModel("This is for test")));
stage.setScene(scene);
stage.setMinWidth(800);
stage.setMinHeight(600);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
main-vew2.fxml is very simple, as long as it is for tests:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane
fx:id="anchorPane" prefHeight="300.0" prefWidth="300.0"
style="-fx-border-color: #111111; -fx-border-insets: 5;"
xmlns="http://javafx.com/javafx/19"
xmlns:fx="http://javafx.com/fxml/1" />
and this is MainController2 class:
package com.myapp;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.AnchorPane;
import java.net.URL;
import java.util.ResourceBundle;
public class MainController2 implements Initializable {
#FXML
private AnchorPane anchorPane;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
public AnchorPane getAnchorPane() {
return anchorPane;
}
}
The Custom Control must look like this, according to SceneBuilder UI:
but, when I run my application, all I see is only the border from main-view2.fxml:
What I'm doing wrong, what I'm missing here?
I know that it's possible to create a CSS file like this one and set it in my scene.
.chart-line-symbol {
-fx-scale-x: 0.5;
-fx-scale-y: 0.5;
}
But that's not what I need. If I do this, the point size will be always the same.
How can I change the chart symbol size dynamicaly, using the value obtained from the TextField?
ChangeSymbolSize.java
package changesymbolsize;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class ChangeSymbolSize extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("MainLayout.fxml"));
Scene scene = new Scene(root);
stage.setTitle("Changing the symbol size");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
MainLayout.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.FlowPane?>
<AnchorPane id="AnchorPane" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="changesymbolsize.MainLayoutController">
<children>
<SplitPane dividerPositions="0.25" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane>
<children>
<TextField fx:id="txt_pointSize" layoutX="14.0" layoutY="31.0" onAction="#setPointSize" prefWidth="60.0" AnchorPane.leftAnchor="14.0" AnchorPane.topAnchor="31.0" />
<Label layoutX="14.0" layoutY="14.0" text="Point Size" AnchorPane.leftAnchor="14.0" AnchorPane.topAnchor="14.0" />
<Button layoutX="74.0" layoutY="31.0" mnemonicParsing="false" onAction="#setPointSize" text="OK" />
</children>
</AnchorPane>
<FlowPane fx:id="pane_chart" />
</items>
</SplitPane>
</children>
</AnchorPane>
MainLayoutController.java
package changesymbolsize;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.FlowPane;
public class MainLayoutController implements Initializable {
#FXML
private Label label;
#FXML
private TextField txt_pointSize;
#FXML
private FlowPane pane_chart;
LineChart<Number, Number> lineChart;
#FXML
private void setPointSize(ActionEvent event) {
System.out.println("We should be able to change the symbol size");
System.out.println("using the value from the TextField");
double size = Double.parseDouble(txt_pointSize.getText());
// But how?
}
#Override
public void initialize(URL url, ResourceBundle rb) {
pane_chart.getChildren().add(getExampleChart());
}
Node getExampleChart(){
NumberAxis xAxis = new NumberAxis();
NumberAxis yAxis = new NumberAxis();
lineChart = new LineChart<Number, Number>(xAxis, yAxis);
int a = 6;
int b = 2;
lineChart.setTitle("f(x) = " + a + " x + " + b);
XYChart.Series series = new XYChart.Series();
series.setName("Example 1");
for (int x = 0; x <= 100; x++) {
double y = (a * x) + b;
series.getData().add(new XYChart.Data(x, y));
}
lineChart.getData().add(series);
lineChart.setCreateSymbols(true);
return lineChart;
}
}
I'm new to JavaFX and to CSS. So I don't know if what I want to do is easy or not, but I'm having trouble figuring out how to do this.
You can get the Nodes using
for (XYChart.Series < Number, Number > series: lineChart.getData()) {
//for all series, take date, each data has Node (symbol) for representing point
for (XYChart.Data < Number, Number > data: series.getData()) {
Node node = data.getNode();
node.setScaleX(Double.parseDouble(newValue));
node.setScaleY(Double.parseDouble(newValue));
}
}
Full Code:
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author Sedrick
*/
public class Chart extends Application {
#Override
public void start(Stage stage) {
//set Axis
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
//chart
final ScatterChart < Number, Number > lineChart = new ScatterChart(xAxis, yAxis);
//prepare series
XYChart.Series series1 = new XYChart.Series();
series1.getData().add(new XYChart.Data(1, 2));
series1.getData().add(new XYChart.Data(2, 2));
series1.getData().add(new XYChart.Data(3, 1));
series1.getData().add(new XYChart.Data(3, 3));
series1.getData().add(new XYChart.Data(5, 2));
HBox hbox = new HBox();
//add series to chart
lineChart.getData().addAll(series1);
TextField textField = new TextField();
textField.textProperty().addListener((observable, oldValue, newValue) -> {
if (newValue.matches("[0-9]*")) {
//take all series
for (XYChart.Series < Number, Number > series: lineChart.getData()) {
//for all series, take date, each data has Node (symbol) for representing point
for (XYChart.Data < Number, Number > data: series.getData()) {
Node node = data.getNode();
node.setScaleX(Double.parseDouble(newValue));
node.setScaleY(Double.parseDouble(newValue));
}
}
}
});
hbox.getChildren().addAll(lineChart, textField);
Scene scene = new Scene(hbox, 800, 600);
//scene.getStylesheets().add(getClass().getResource("/resources/chart.css").toExternalForm());
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I am having a JFXNodeList
<JFXNodesList fx:id="algorithmList" layoutX="285.0" layoutY="215.0" prefHeight="1.0" prefWidth="10.0" />
How can I close (blend the JFXNodeList), from my controller java code, if a user click one button ?
Environment:
JavaFX , Java 8, jfoenix:8.0.3
To close (collapse) JFXNodeList you can use this method:
nodesList.animateList(false);
Complete example:
// src/toumi_jfoenix/Controller.java:
package toumi_jfoenix;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXNodesList;
import javafx.fxml.FXML;
import javafx.scene.control.Tooltip;
public class Controller {
#FXML
public JFXNodesList nodesList;
#FXML
private void initialize() {
JFXButton btnMenu = new JFXButton("Menu");
JFXButton btnOption1 = new JFXButton("Option 1");
JFXButton btnOption2 = new JFXButton("Option 2");
JFXButton btnCollapse = new JFXButton("<<");
btnCollapse.setTooltip(new Tooltip("Collapse menu"));
btnCollapse.setOnAction(e->nodesList.animateList(false));
nodesList.addAnimatedNode(btnMenu);
nodesList.addAnimatedNode(btnOption1);
nodesList.addAnimatedNode(btnOption2);
nodesList.addAnimatedNode(btnCollapse);
}
}
// src/toumi_jfoenix/sample.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.Pane?>
<?import com.jfoenix.controls.JFXNodesList?>
<Pane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="toumi_jfoenix.Controller">
<JFXNodesList fx:id="nodesList" layoutX="20.0" layoutY="10.0" rotate="-90" spacing="50"/>
</Pane>
// src/toumi_jfoenix/Main.java:
package toumi_jfoenix;
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 {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root, 430, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Main.class
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
// BorderPane root = new BorderPane();
Parent root = FXMLLoader.load(getClass().getResource("/application/MainWindow.fxml"));
Scene scene = new Scene(root, 400, 400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
package application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class MainWindowController {
public void buttonAction(ActionEvent event) {
Stage dialog = new Stage();
dialog.initStyle(StageStyle.TRANSPARENT);
Scene scene = new Scene(new Group(new Text(260, 260, "Hello World!")));
// its Just for checking I want add .fxml here how can I do?
dialog.setScene(scene);
dialog.show();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="400.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainWindowController">
<children>
<Button fx:id="bt1" layoutX="154.0" layoutY="188.0" mnemonicParsing="false" onAction="#buttonAction" text="Login" />
</children>
</AnchorPane>
When I am clicking a login button one dialog is open which contain a form.
How I do this? And my dialog contain only close button on title bar, when my dialog is open then I am not doing any action in my main MAinWindow. It just displays without focus. How can I do this?
I am a newbie in JavaFX so I decided to make a simple web browser and it works fine but only with a predefined URL (http://google.com in this example). I did the following: created BrowserTop.fxml (which includes a TextField for URL and a button for getting this URL) and Browser.fxml which includes plain WebView. So, my problem is that I can't understand how can I pass a String URL to WebView (which uses Browser.fxml) by clicking the button in BrowserTop.fxml?
Browser.java
package browser;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class Browser extends Application {
private Stage stage;
private BorderPane rootLayout;
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
initBrowserTop();
initBrowserMain();
}
public void initBrowserTop() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Browser.class.getResource("BrowserTop.fxml"));
rootLayout = (BorderPane) loader.load();
Scene scene = new Scene(rootLayout);
stage.setScene(scene);
stage.show();
}
public void initBrowserMain() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Browser.class.getResource("Browser.fxml"));
WebView browserWebView = (WebView) loader.load();
WebEngine myWebEngine = browserWebView.getEngine();
myWebEngine.load("http://google.com");
rootLayout.setCenter(browserWebView);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
BrowserTop.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHe
ight="728.0" prefWidth="1024.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="browser.BrowserTopController">
<top>
<AnchorPane>
<children>
<TextField fx:id="txtURL" layoutX="52.0" prefHeight="25.0" prefWidth="584.0" AnchorPane.leftAnchor="52.0" AnchorPane.rightAnchor="0.0" BorderPane.alignment="CENTER" />
<Button fx:id="btnGo" mnemonicParsing="false" onAction="#handleButtonAction" prefHeight="25.0" prefWidth="53.0" text="Go" AnchorPane.leftAnchor="0.0" />
</children>
</AnchorPane>
</top>
</BorderPane>
BrowserTopController.java
package browser;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
public class BrowserTopController implements Initializable {
#FXML TextField txtURL;
#FXML
public void handleButtonAction(ActionEvent event){
//something should be here
}
/**
* Initializes the controller class.
* #param url
* #param rb
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
I have actually used the techniques referred above by #James_D before. I made your code work by doing this:
package browser;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class Browser extends Application {
private Stage stage;
private BorderPane rootLayout;
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Browser.class.getResource("BrowserTop.fxml"));
rootLayout = (BorderPane) loader.load();
BrowserTopController browserTopController = (BrowserTopController) loader.getController();
WebView browserWebView = new WebView();
WebEngine myWebEngine = browserWebView.getEngine();
browserTopController.btnGo.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
myWebEngine.load(browserTopController.txtURL.getText());
}
});
rootLayout.setCenter(browserWebView);
Scene scene = new Scene(rootLayout);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
You also have to add
#FXML Button btnGo;
to your fxml document.