Controller For FXML based TableView Pagination - javafx

I have a customized TableView defined in an FXML and the table works fine so far. The code is something like the followings:
<FitWidthTableView fx:id="dataDisplayView" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="300.0" prefWidth="380.0" VBox.vgrow="ALWAYS">
<columns>
<TableColumn fx:id="rowColumn" maxWidth="50.0" prefWidth="30.0" sortable="false" style="-fx-alignment: CENTER_RIGHT;" text="Row" />
...
</FitWidthTableView>
Now, I need to add the Pagination due to a huge amount of data (from a DB). It would be great if I can wrap around the TableView tag with the Pagination tag. I find a sample with the approach as the following
<Pagination fx:id="pagination" layoutX="2.0" layoutY="188.0" prefHeight="275.0" prefWidth="912.0">
<fx:define>
<FitWidthTableView fx:id="dataDisplayView" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" prefHeight="300.0" prefWidth="380.0"
VBox.vgrow="ALWAYS">
<columns>
<TableColumn fx:id="rowColumn" maxWidth="50.0" prefWidth="30.0" sortable="false"
style="-fx-alignment: CENTER_RIGHT;" text="Row"/>
...
</columns>
<VBox.margin>
<Insets left="1.0" right="1.0"/>
</VBox.margin>
</FitWidthTableView>
</fx:define>
</Pagination>
while almost all examples of TableView with Pagination are done without FXML.
I, however, don't see the pagination controller code sample which shall do a few things: determine the number of pages, specify the page size, and populate data to the table. Can someone advise on the subject?
My controller is something like the followings:
public class DataViewerController implements Initializable {
#FXML
private Pagination pagination ;
#FXML
private FitWidthTableView<OutputData> dataDisplayView;
#FXML
private TableColumn<OutputData, Integer> rowColumn;
…
#Autowired
private OutputDataRepository outputDataRepository;
#Override // This method is called by the FXMLLoader when initialization is complete
#FXML
public void initialize(URL fxmlFileLocation, ResourceBundle resources) {
…
}
…
}
How to populate data with the above code structure?

As shown here, any Pagination property can be initialized in your FXML:
<Pagination pageCount="8" currentPageIndex="3" …/>
More likely, you'll derive the values based on your actual data. Your implementation of the pageFactory() should set the desired partition on the table and return a table view, as seen here.
I want to keep the TableView in the FXML.
As, #James_D comments, the TableView declaration is irrelevant to the pageFactory(). As a concrete example, start from the complete example cited here and substitute the following FXML declarations in center:
<center>
<Pagination fx:id="pager" currentPageIndex="1"/>
<fx:define>
<TableView fx:id="tableView" prefHeight="60.0">
<columns>
<TableColumn fx:id="itemName" text="Item Name" />
<TableColumn fx:id="pricePerUnit" text="Price Per Unit" />
<TableColumn fx:id="quantity" text="Quantity" />
<TableColumn fx:id="amount" text="Amount" />
</columns>
</TableView>
</fx:define>
</center>
In the controller, inject the pager and initialize() it:
#FXML
Pagination pager;
…
//tableView.setItems(objList);
pager.setPageCount(objList.size());
pager.setPageFactory((Integer pageIndex) -> createPage(pageIndex));
The following factory assigns a single row to the tableView and returns it:
public TableView<TestModel> createPage(int page) {
tableView.getItems().setAll(objList.get(page));
return tableView;
}

Related

How do you get the SimpleMenuButton to display the MenuItem text in JavaFX?

I am building an inventory management system for work and am having a lot of trouble getting the SplitMenuButton to display the MenuItem when I click on the item. I can not find much information on the 'SplitMenuButton' on the internet and have tried just MenuButton as well with no luck. For example, the default text is 'Department' and I would like it to display 'Aseptic' when that menu item is selected or 'Facilities' when that menu item is selected.
I have tried to create a new instance of SplitMenuButton and setText("Aseptic") when the #buildDataAseptic method is run, but this still didn't work.
My fxml code is:
<SplitMenuButton mnemonicParsing="false" prefHeight="25.0" prefWidth="217.0" text="Department" textAlignment="CENTER">
<items>
<MenuItem fx:id="asepticMenuItem" mnemonicParsing="false" onAction="#buildDataAseptic" text="Aseptic" />
<MenuItem fx:id="generalMenuItem" mnemonicParsing="false" onAction="#buildDataGeneral" text="General" />
<MenuItem fx:id="facilitiesMenuItem" mnemonicParsing="false" onAction="#buildDataFacilities" text="Facilities" />
</items>
</SplitMenuButton>
any help is greatly appreacitead, thanks!
As others have pointed out, ComboBox is a much better choice for your use case.
Here is a self contained example. First the FXML:
<?import javafx.scene.control.ComboBox?>
<?import javafx.collections.FXCollections?>
<?import java.lang.String?>
<ComboBox xmlns:fx="http://javafx.com/javafx/null">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Aseptic" />
<String fx:value="General" />
<String fx:value="Facilities" />
</FXCollections>
</items>
</ComboBox>
And the application with comments:
package sample;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.stage.Stage;
public class Main extends Application {
public void start(Stage primaryStage) throws Exception {
ComboBox<String> comboBox = FXMLLoader.load(getClass().getResource("test.fxml"));
// Create an observable property for the selection
SimpleStringProperty selected = new SimpleStringProperty();
// Bind the property to the comboBox
selected.bindBidirectional(comboBox.valueProperty());
// Set initial value
selected.set("Facilities");
// React to changes
selected.addListener((observable, oldValue, newValue) -> {
// newValue contains the new selection, update database
System.out.println(newValue);
});
primaryStage.setScene(new Scene(comboBox));
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
General advice: Don't hang on to the SplitMenuButton just because you've spent a lot of time on it. Think of this as a learning experience. If you don't learn to let go and refactor, you'll never create good software :)

Execute action when combobox item is selected FXML

I'm trying to create a drop down menu (using ComboBox) with FXML and JavaFX controllers.
This is what I already have:
<ComboBox fx:id="menuSettings" layoutX="14.0" layoutY="27.0" prefHeight="27.0" prefWidth="27.0" style="-fx-background-color: white;">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Menu" />
<String fx:value="Settings" />
<String fx:value="Exit" />
</FXCollections>
</items>
</ComboBox>
How can I show a new scene using Action listeners when the ComboBox option is selected?
Thanks in advance!
There are two ways that come to mind on how you could do this.
The first would be to add the onAction="#yourMethod" to your <ComboBox ... > tag. You could then add some code to your controller...
#FXML public void yourMethod() {
//Show the scene here
}
...which would be run when the user selected an item.
The other thing that you could do would be to add a ChangeListener to your ComboBox:
#FXML public void initialize() {
yourComboBox.valueProperty().addListener(new ChangeListener<String>() {
#Override public void changed(ObservableValue value, String old, String new) {
//Show your scene here
}
});
}
Both of these work I think, it's just a matter of preference to do it in code or FXML.
I hope this was helpful, and good luck with your project!
(If this did not answer your question, please let me know and I will do my best to revise my answer)

JavaFX controller injection does not work

I have two fxml files. I connect them with an include statement:
The "main" fxmlfile looks like that:
<?import javafx.geometry.*?>
// ...
<BorderPane prefHeight="962" prefWidth="1280" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MyMainController">
<center>
<SplitPane dividerPositions="0.63" BorderPane.alignment="CENTER">
<items>
<fx:include source="AnotherFile.fxml" />
// ...
</items>
</SplitPane>
</center>
<top>
// ...
</top>
</BorderPane>
And the second one (= "AnotherFile.fxml") like that:
<?import java.lang.*?>
// ...
<SplitPane dividerPositions="0.15" orientation="VERTICAL" prefHeight="400.0" prefWidth="500.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<items>
// ...
<Label fx:id="oneOfMyLabels" text="myText" GridPane.columnIndex="2" GridPane.rowIndex="1" />
</items>
</SplitPane>
Now, I am using injections in the "main"-controller application.MyMainController:
#FXML
private Label oneOfMyLabels;
If I run the controller I get a java.lang.NullPointerException exception, respectively a java.lang.reflect.InvocationTargetException one. In debugging mode I found out, that the injected Label is null!
Now, my question:
Can't reach the MyMainController from the "main fxml file" the components of the included fxml file?? Do I have to use an own controller on each fxml file, if it is included or not?!
Thanks for your help!!
You need to have a different controller for each FXML file, and the fx:id-annotated elements of each file will be injected into the corresponding controller instance.
When you have included FXML files, you can inject the controller for the included file into the controller for the including file, by setting an fx:id attribute on the fx:include element:
"main" fxml file:
<?import javafx.geometry.*?>
// ...
<BorderPane prefHeight="962" prefWidth="1280" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MyMainController">
<center>
<SplitPane dividerPositions="0.63" BorderPane.alignment="CENTER">
<items>
<fx:include fx:id="another" source="AnotherFile.fxml" />
// ...
</items>
</SplitPane>
</center>
<top>
// ...
</top>
</BorderPane>
and in the "main controller":
public class MyMainController {
#FXML
private AnotherController anotherController ;
// ...
}
(the rule being that the field name is the value of the fx:id attribute with "Controller" appended). Here AnotherController is the controller class for AnotherFile.fxml.
Now you can, for example, expose the data you need to access in the "included controller":
public class AnotherController {
#FXML
private Label oneOfMyLabels ;
public StringProperty textProperty() {
return oneOfMyLabels.textProperty();
}
public final String getText() {
return textProperty().get();
}
public final setText(String text) {
textProperty().set(text);
}
// ...
}
and then your main controller can do things like
anotherController.setText(...);
which will of course update the label. This preserves encapsulation, so that if you choose to use another control instead of a label, those changes do not have to propagate outside of the immediate controller.

how to display a calendar controller from a fxml file in javafx

Is that possible to display a calendar controller from scene builder? I am trying to display a calendar which ideally has to be linked to a data property and time slot. Any help?
I'm not using scene builder, but you can manually edit your fxml to add a DatePicker. I created a simple example that shows a date picker and when the date is chosen it displays it in a Text field below.
The fxml looks like:
<GridPane fx:controller="datepicker.DatePickerController" xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<padding>
<Insets top="25" right="25" bottom="10" left="25" />
</padding>
<DatePicker fx:id="datepicker" GridPane.columnIndex="0" GridPane.rowIndex="0" onAction="#handleDatePickerAction"></DatePicker>
<Text fx:id="actiontarget" GridPane.columnIndex="0" GridPane.rowIndex="1" />
</GridPane>
And the controller looks like:
public class DatePickerController
{
#FXML
private Text actiontarget;
#FXML
private DatePicker datepicker;
#FXML
protected void handleDatePickerAction(ActionEvent event)
{
actiontarget.setText(datepicker.getValue().toString());
}
}

Prefill ListView in an application with FXML

I have JavaFX application using FXML to build its GUI.
When this application is launched, I need to have ListView, which has some values loaded, for example, from database. So, how can I do this?
I know how to make application, which loads items to ListView after user clicks a button, or something like this ("onAction" attribute in FXML). But this does not suites me as I need items to be loaded automaticaly to the ListView.
This fills my choicebox with the five predetermined baud rates. I assume if you try to add items from your controller, the list only shows those values (untested).
<ChoiceBox fx:id="baudRates" layoutX="234.0" layoutY="72.0">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="4800" />
<String fx:value="9600" />
<String fx:value="19200" />
<String fx:value="57600" />
<String fx:value="115200" />
</FXCollections>
</items>
</ChoiceBox>
You also need to include the following import statement in your FXML:
<?import javafx.collections.*?>
If you have fxml with Controller, like next:
<AnchorPane xmlns:fx="http://javafx.com/fxml" fx:controller="test.Sample">
<children>
<ListView fx:id="listView"/>
</children>
</AnchorPane>
you can just implement Initializable in your Controller:
public class Sample implements Initializable {
#FXML
private ListView listView;
#Override
public void initialize(URL url, ResourceBundle rb) {
// change next line to DB load
List<String> values = Arrays.asList("one", "two", "three");
listView.setItems(FXCollections.observableList(values));
}
}

Resources