I'm creating a UI for a project in javafx. I'm using CSS for the styles, FXML for the structure, and also .java controllers. I'm trying to make my node(s) (i.e. button, borderpane) layout bind to the scene size, so that the window can be resized and the layout stay the same. Normally if the node was defined in a jar file I would use:
button.layoutYProperty().bind((scene.heightProperty().divide(2)));
or something similar, but my nodes are defined within the FXML file.
How can I access the nodes from outside of the FXML file so that I can define the layout or how can I define the layout within the FXML file.
(I am not using and do not intend to use scene builder).
First, you should never need to do things like this. If you use layout panes you should always be able to choose a combination of layout panes and settings that automatically position the nodes as you want them. The solutions outlined below should never really be needed.
In the controller, you typically don't have direct access to the scene, so you need to listen for when the sceneProperty() is initialized on the node and act accordingly:
public class Controller {
#FXML
private Button button ;
public void initialize() {
button.sceneProperty().addListener((obs, oldScene, newScene) -> {
button.layoutYProperty().unbind();
if (newScene != null) {
button.layoutYProperty().bind(newScene.heightProperty().divide(2));
}
});
// ...
}
}
But again, the correct approach here is to choose appropriate layout panes to achieve what you want.
Related
How do I add a JavaFX Pane to a TornadoFX vbox?
All I get is a blank window.
class TradingButtons : View() {
override val root = vbox {
ChartTest()
}
}
class ChartTest(vararg children: Node?) : Pane(*children) {
init {
val xAxis = CategoryAxis()
val yAxis = NumberAxis(1.0, 21.0, 0.1)
val lineChart = LineChart(xAxis, yAxis)
this.children.add(lineChart)
}
}
As per the documentation:
However, to actually show something on screen we want to populate this VBox acting as the root control. Using the initializer block, let's add a JavaFX Button and a Label.
Also take note of the tornadofx.* import. This is important and should be present in all your TornadoFX related files. The reason this is important is that some of the functionality of the framework isn't discoverable by the IDE without the import. This import enabled some advanced extension functions that you really don't want to live without :)
import tornadofx.*
class MyView: View() {
override val root = vbox {
button("Press me")
label("Waiting")
}
}
TornadoFX provides a builder syntax that will streamline your UI code. Instead of creating UI elements and manually adding them to the parent element's children list, the builders allow us to express the UI as a hierarchical structure which enables you to visualize the resulting UI very easily. Note that all builders are written in lowercase, so as to not confuse them with manual instantiation of the UI element classes.
I hope, this may helps.
I've build a Gui using the scene builder application. I've loaded it into my application but I want to add components to a VBox buried in the design. It seems that all i have access to use is the AnchorPanel that is returned from FXMLLoader.load.
Is there any way more elegant then drilling down the children tree's to get to the component i want?
Thanks.
If you need to add to the VBox from some random class:
give an fx:id to the VBox, say "vbox"
create a Controller for the view and associate it to the view in the FXML
in the Controller, add a #FXML VBox vbox; (where vbox it the same as the fx:id)
retrieve the controller from the FXMLLoader and access the VBox: controller.vbox;.
If you just need to add something to the VBox when your view is loaded, follow 1 to 3 above and add the relevant code in the initialize method of the Controller.
I'm starting working with JavaFX and wish to use the new tree view (as you can use multiple icons to represent your data - which is what I wish to take advantage of).
I have created a basic form/scene that has a tree view and one button on it. When this button is pressed I wish to populate the treeview.
Now, all the examples ive looked at are where the form/scene is generated in code and the treeview is bound to that control....how do I have a pre designed form with Scene builder and populate it from external code?
You could use the following code in a controller class. Inside the FXML file you will need to set the FXID to selectionTreeView. Tested in JDK 8u5 and it worked.
#FXML
TreeView selectionTreeView;
#FXML
private void handleButtonAction(ActionEvent event) {
createTree();
}
public void createTree(String... rootItems) {
//create root
TreeItem<String> root = new TreeItem<>("Root");
//root.setExpanded(true);
//create child
TreeItem<String> itemChild = new TreeItem<>("Child");
itemChild.setExpanded(false);
//root is the parent of itemChild
root.getChildren().add(itemChild);
selectionTreeView.setRoot(root);
}
Set the class name (including package) on the root node of your control in scene builder. If you click on, then go to the code tab on the right it is the top field.
Now set an ID on the TreeView in your control.
Now in the controller object add a TreeView field, the variable name should be the same as what you set the TreeView ID as in scene builder. Annotate with field with #FXML.
Now when the FXML is loaded, the controller is created and the TreeView field is set.
I placed a ChoiceBox inside an fxml with JavaFX Scene Builder.
The FXML has a controller assigned to it.
My question is: Which event do I need to register if I want to know about changed values?
onInputMethodTextChanged="#languageSelectionModified"
this does not work with the following code
public void languageSelectionModified(Event event) {
ChoiceBox<String> box = (ChoiceBox<String>) event.getSource();
System.out.println(box.getValue());
}
and this only works for the initial click (i.e. opening the list, not when selecting an item):
onMouseClicked="#languageSelectionModified"
Although the Mouse-Events would never be a good choise because of situations where the touch or keyboard is the input-method, it still proves that the System.out can be reached.
I have absolutly no idea where those things are documentated (in the default Java-API they are not)
Add a listener to your #FXML injected choicebox in your controller:
choicebox.getSelectionModel().selectedItemProperty().addListener(choiceboxSelectionChangeListener);
You can also bind to the selected item:
label.textProperty().bind(choicebox.getSelectionModel().selectedItemProperty());
Here is an example of hooking up a listener in a controller for a ComboBox defined in FXML. Logic for a ChoiceBox is pretty much identical.
You can also use FXML onAction attribute:
<ChoiceBox onAction="#languageSelectionModified" />
I am learning to design a GUI in GWT
I have RootPanel where i have put all the widgets.
In one panel i have put tree Widget where the treeItems are added on the success of RPC call on the selectionHandler
What I want to do:
When click on treemItem , All the other treeItem and the widgets on the same and different panel should not be selected. Like there is a processing going on so no other things are allowed to do.
Please suggest some idea or sample code or example.
If I correctly understand you, you want to disable user clicking some widgets until specific callback finishes. In order to do that you should have a custom panel with bigger z-index and opacity. For example, something like DialogBox's setGlassEnabled(true) method and try using that technique in your callbacks. When asynchronous request starts show that panel in onSuccess and onFailure you should hide it. By the way, my-gwt has LoadingPanel class which implements such feature. And also another mask live demo in GWT-Ext.
This statement is redundant and unnecessary:
"When click on treemItem , All the other treeItem and the widgets on
the same and different panel should not be selected."
Of course, when you click on a tree node, that is the only node you want activated. No other node would have any activity. That is by convention.
And I really don't know what this statement is all about:
"Like there is a processing going on so no other things are allowed to
do."
Your question should simply be:
How do I add child nodes to a tree Widget, where child nodes are added
only when I click on the node? When I click on a node, if it has no
child nodes, an RPC would be triggered to fetch the nodes. How should
my RPC results update the node? After I click on a node, it should be
highlighted. There should be only one highlighted/selected node on the whole tree.
Extend HorizontalPanel to contain an icon and a title.
It should implement IsTreeItem.
It should implement ClickHandler so that it can be added as clickhandlers to the icon and title label.
public class Node
extends HorizontalPanel
implements ClickHandler, IsTreeItem{
Image img;
Label label;
MyData data;
TreeItem nodeWrapper;
The constructor eats in a MyData record, instantiates the icon image and title label, and associates itself as the clickhandler for the icon and label:
public Node(MyData data){
this.nodeWrapper = new TreeItem(this);
this.img = new Image(data.getIconUrl());
this.label = new Label(data.getTitle());
this.data = data;
this.add(img);
this.add(this.label);
// ensure onclick is triggered either by clicking img or label.
this.img.addClickHandler(this);
this.label.addClickHandler(this);
}
Implementing IsTreeItem requires the node to be able to substantiate itself with a TreeItem:
public TreeItem asTreeItem(){
return this.nodeWrapper;
}
The clickhandling will fetch the list of child records and iteratively create new nodes from the child records and attach them to the current node. This is where the RPC callback action takes place.
public void onClick(ClickEvent e){
this.displayRightPanel(this.data);
if(this.nodeWrapper.getChildCount()==0)
fetchNodeData(
this.nodeWrapper,
this.data.getId(),
new AsyncCallBack<List<MyData>>(){
public void onSuccess(List<MyData> nodeDataList){
for(MyData nodeData : nodeDataList){
Node.this.nodeWrapper.addItem(new Node(nodeData));
}
}
public void onFailure(Throwable sorry){
doWhatever();
}
}
);
}
define other relevant methods before closing the class definition:
//blah ... blah ... blah...
}
Since this is not a tutorial on RPC, you should find out how to write the RPC part. You need to define MyData which is a shared POJO between GWT client and RPC servlet. RPC servlet must return a list of MyData. You need to be educated on at least the 2nd Normal Form of database normalisation to understand why you need a getId() method.
public Interface MyData{
String getIconURL();
String getTitle();
String getId();
// among others ...
}
It is presumed that you have a splitpanel. The left side would be the tree widget and the right panel is some sort of display. So that onclick, besides triggering RPC fetch, would also call displayRightPanel(data), and it is left to you how you wish to display that data.
You would create a first root node and associate it as the root of the tree, and the rest of the tree would be populated by user clicking. So the root node would require you to concoct a MyData record that will supply the iconUrl, title, and some root data.
The tree widget will manage the highlighting of its members and ensure only one member is highlighted.