How do I make a javafx node adapt to it´s parent? - java

Example:
<AnchorPane xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="HomeController">
<children>
<VBox fx:id="vBoxParent" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity">
<children>
<MenuBar fx:id="menubar" prefHeight="30.0" prefWidth="800.0">
...
With this code, the stage opens fullsize, but the menubar isn´t covering all the lenght. What do I have to add?

If you want the MenuBar to take the full size of VBox, you can replace VBox with MenuBar, placing MenuBar directly in AnchorPane, and giving Anchor Pane Constraints to the MenuBar (to be responsive).
If you want to keep VBox for some reason, you can change the MenuBar properties:
set Vgrow to: allways (allways increase the vertical length)
set Max Width to: MAX_VALUE
I recommend you to use SceneBuilder, to easily find functions and preview changes.

Related

JavaFX scaling does not resize the component in parent container

I have a container that needs to display two custom components scaled down by 25% aligning them vertically.
I'm using a VBox loaded from this FXML:
<fx:root type="VBox" fx:id="leaderDisplay" xmlns="https://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="MyController"
prefHeight="720.0" prefWidth="200.0" alignment="CENTER">
</fx:root>
And the component is loaded from this FXML:
<fx:root stylesheets="#css/style.css" type="StackPane"
maxHeight="294.0" maxWidth="195.0"
fx:controller="MyOtherController"
xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1">
<AnchorPane fx:id="cardPane" styleClass="leader-card" prefHeight="294.0" prefWidth="195.0">
<FlowPane fx:id="lcRequirements" layoutX="13.0" layoutY="10.0" />
<Label fx:id="lcVictoryPoints" layoutX="87.0" layoutY="162.0" prefHeight="25.0" prefWidth="20.0" text="0" />
</AnchorPane>
<Pane fx:id="cardBack" styleClass="leader-card-back" maxHeight="294.0" maxWidth="195.0" visible="false" />
</fx:root>
I add the needed components programmatically with this method in the VBox controller:
private void addLeader(LeaderCard newLeader) {
Platform.runLater(() -> {
setStyle("-fx-background-color: grey;");
LeaderCardWidget newWidget = new LeaderCardWidget(newLeader);
System.out.println("Height before: " + newWidget.getMaxHeight());
newWidget.setStyle("-fx-border-color: black;" +
"-fx-border-width: 3");
newWidget.setScaleX(0.75);
newWidget.setScaleY(0.75);
System.out.println("Height after: " + newWidget.getMaxHeight());
leaderDisplay.getChildren().add(newWidget);
leadersAndWidgets.put(newLeader, newWidget);
});
}
The problem is that the components are being scaled down, but the vbox does not display them properly, leaving huge spacing around them (to the right is the same screenshot without scaling for reference):
From the "Visual Bounds versus Layout Bounds" section of the layout documentation:
Node provides the layoutBounds property to define the 'logical'
bounds of the node for layout and boundsInParent to define the visual
bounds once all effects, clipping, and transforms have been applied.
... if a ScaleTransition is used to pulse the size of a button,
that pulse animation will not disturb layout around that button. If an
application wishes to have the effect, clip, or transform factored
into the layout of a node, it should wrap that node in a Group.
In short, transforms, such as scaling, are not factored into the layout calculations of the parent. You can make that happen by wrapping your components in a group. I think you can achieve this in your code with
// leaderDisplay.getChildren().add(newWidget);
leaderDisplay.getChildren().add(new Group(newWidget));

Problem Binding TableView prefWidthProperty to it's Parent Container's prefWidthProperty

Relevant FXML :
<ScrollPane fx:id="scrollpane_var" hbarPolicy="NEVER" prefHeight="200.0" prefWidth="200.0" GridPane.columnSpan="3" GridPane.rowIndex="2" GridPane.rowSpan="5">
<content>
<TableView fx:id="tableview_var" prefHeight="169.0" prefWidth="292.0">
<columns>
<TableColumn prefWidth="69.0" text="Quantité" />
<TableColumn prefWidth="161.0" text="Nom" />
<TableColumn prefWidth="56.0" text="Prix" />
</columns>
</TableView>
</content>
</ScrollPane>
Controller class Code :
public class Lancer {
#FXML // fx:id="scrollpane_var
private ScrollPane scrollpane_var; // Value injected by FXMLLoader
#FXML // fx:id="tableview_var"
private TableView<String> tableview_var; // Value injected by FXMLLoaderte void initialize()
public void initialize() {
tableview_var.prefWidthProperty().bind(scrollpane_var.prefWidthProperty());
}
Visual Representation :
Click to see Scenebuilder screenshot
as the title says i'm trying to bind a TableView's width to it's Parent container and the documentation is a bit confusing as i am very new to GUI Applications .
This line of code is the furthest i've gottent and i dont know why it's not working :
public void initialize() {
tableview_var.prefWidthProperty().bind(scrollpane_var.prefWidthProperty());
}
A TableView manages its own scrolling, so you should not be putting it inside a ScrollPane at all. Just omit the scroll pane from the layout entirely.
In general, if you want the content of a scroll pane to fit the available width of the scroll pane, you would use the fitToWidth property, instead of trying to use a binding. In general, binding the pref width like this is a bad idea; if the layout or container you are using doesn't provide the functionality you need, and it almost always will, you should subclass Pane and override layoutChildren() and other methods. Here, the TableView already provides scrolling, and in more general cases, the ScrollPane allows you to specify the content should fit the width of the scroll pane.
<ScrollPane ... fitToWidth="true>
<!-- ... -->
</ScrollPane>
But again, here the scroll pane is redundant.

JavaFX Autosizing two or more VBoxes side-by-side in an HBox [duplicate]

I am looking for a way to say set a maxWidth size to 80% in FXML.
Much like in web development.
<VBox fx:id="testVB" prefWidth="600">
But this does not:
<VBox fx:id="testVB" prefWidth="80%">
I know that in Straight JavaFX2 non-fxml you can create insets? What is the best way to do this outside of code in FMXL?
Thanks!
Riley
I'm not sure you can. You need to use the GridPane layout component. In this component, you can specify rows and columns constraints, and in these constraints you can specify a width as a percentage. For example:
<GridPane>
<children>
<TitledPane text="testGridPane" GridPane.columnIndex="0" GridPane.rowIndex="0" />
</children>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="80.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="20.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
This code defines a GridPane with a first column with a width of 80%. The TitledPane is set in the first cell of the first column of this GridPane, and can (because you need to be sure that the width constraints of the TitledPane match your needs) occupy 80% of the width of the GridPane.
Please note that I removed all information not relevant to your question. By the way, Oracle's Scene Builder tool is very useful to define complex FXML layout.
It seems like many answers have already been provided and they should work. However, there is a way to set percentages:
<fx:define>
<Screen fx:factory="getPrimary" fx:id="screen" />
</fx:define>
This would help you detect the dimensions of the current screen, the application is being displayed on. Now that we have the display dimensions, we can play with it in FXML as follows:
<HBox fx:id="hroot" prefHeight="${screen.visualBounds.height}" prefWidth="${screen.visualBounds.width}"> Your FXML elements inside the root... </HBox>
Note that I use visualBounds, since this would get me the available space on the screen, since I don't want an overlap with the taskbar in Windows for example. For fullscreen applications, you would just use 'bounds'.
Now, to come to your point of using percentages, you can actually play with the value of the prefheight and prefWidth. You can put calculations inside the ${}.
Optionally:
If you want to have all your elements use relative sizes, just refer to them, using their ID and width or height property, and make your calculation.
<VBox fx:id="VBSidebar" prefWidth="${hroot.width*0.15}" prefHeight="${hroot.height}"> more elements.. </VBox>
Hope this helps!
You can simulate it - basic example that simulates 50% for two cols in an HBox. You can add dummy panes to get thirds, etc.
HBox {
VBox {
static hgrow : "ALWAYS",
Label {
text : "Privacy",
alignment : "CENTER",
styleClass : ["h2", "heading"]
}
},
VBox {
static hgrow : "ALWAYS",
Label {
text : "Messages",
alignment : "CENTER",
styleClass : ["h2", "heading"]
},
Label {text:""}
}
}

How to insert an object of a .jar file into Scene Builder?

I am writing a simulation software for my Masters and it consists on a "Graph container" where you can link nodes to generate equations according to what I link. These equations will, then, enable me to simulate my model. I am using Java 8 and JavaFX for that, with Scene Builder and FXML.
Searching on the web, I found the Graph-Editor (https://github.com/tesis-dynaware/graph-editor), which will help me a lot with what I need. Following the Tutorial on the project's site, I could reproduce it and it is running. But on my software I do not need to create a new window as the tutorial does to use the graphs - instead, I want to have a TabPane that enables me to create as many models as I need, like a text editor, and if I want I can save it on XML, etc...
My problem is: I tried to put the graphs from the tutorial inside the Tab they do on the tutorial (with the getView method) and it is not working. I tried it in two different ways, which result in an empty Tab, with no nodes and no error on the console.
First try
I tried putting into a Pane and set the GraphEditor inside the Pane.
My java code:
private GraphEditor graphEditor = new DefaultGraphEditor();
#FXML
private Pane graphEditorPane;
#FXML
public void initialize(){
graphEditorPane = new Pane(graphEditor.getView());
GModel model = GraphFactory.eINSTANCE.createGModel();
graphEditor.setModel(model);
addNodes(model);
}
My FXML code:
<TabPane tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<tabs>
<Tab text="Modelo 1">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0">
<children>
<Pane fx:id="graphEditorPane" prefHeight="571.0" prefWidth="1000.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</content>
</Tab>
</tabs>
</TabPane>
Second way
I have seen their demo source code and what I understood was that they created an instance of their GraphEditorContainer object and then their FXML file has that GraphEditorContainer, but mine doesn't work that way. Maybe I got what they did wrong (I am a beginner in Java and JavaFX).
My java code:
private GraphEditor graphEditor = new DefaultGraphEditor();
#FXML
private GraphEditorContainer graphEditorContainer;
#FXML
public void initialize(){
graphEditorContainer = new GraphEditorContainer();
GModel model = GraphFactory.eINSTANCE.createGModel();
graphEditor.setModel(model);
graphEditorContainer.setGraphEditor(graphEditor);
addNodes(model);
}
My FXML code:
<?import de.tesis.dynaware.grapheditor.GraphEditorContainer?>
<TabPane tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<tabs>
<Tab text="Modelo 1">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0">
<children>
<GraphEditorContainer fx:id="graphEditorContainer" minWidth="0" minHeight="0" maxWidth="+Infinity" maxHeight="+Infinity"/>
</children>
</AnchorPane>
</content>
</Tab>
</tabs>
</TabPane>
I could put the code that opens the window and draws the nodes in the handleNew function (code below), but not in the Tab.
Stage secondaryStage = new Stage();
GraphEditor graphEditor = new DefaultGraphEditor();
Scene scene = new Scene(graphEditor.getView(), 800, 600);
secondaryStage.setScene(scene);
secondaryStage.show();
GModel model = GraphFactory.eINSTANCE.createGModel();
graphEditor.setModel(model);
addNodes(model);
If it's possible could you help me?
Thank You
Error on console:
javafx.fxml.LoadException: GraphEditorContainer is not a valid type.
simply means that you didn't put the import for GraphEditorContainer in the FXML file. Something like
<? import com.somecompany.somepackage.GraphEditorContainer ?>
near the top of the FXML file (with the other imports), obviously edited for the correct package name.
In the controller, it is always a mistake to initialize #FXML-annotated fields, for obvious reasons, so replace
#FXML
private GraphEditorContainer graphEditorContainer = new GraphEditorContainer();
with
#FXML
private GraphEditorContainer graphEditorContainer ;
Using custom (or 3rd party) controls in SceneBuilder is covered in Adding a custom component to SceneBuilder 2.0

JavaFX- Freeze some columns in a table [duplicate]

The idea is: on a TableView of N columns to have the first M columns always visible even when you use the horizontal scroller.
The only thing near my requirement is this Binding two tableviews together such that they scroll in sync.
The idea to put side by side two tables is not the best by my point of view because
1) The sort of the column is partially indipendent between the two tables: if you use the same observableList the rows are sorted in both tables but it is not possible the sort on multiple columns where at least one column is not on the same table
2) There is no syncronous scroll with the mouse wheel or with the arrows keys
I know that, probably, I can cope with problems like these using EventHandlers and Listeners but I am hoping it is possible to use only one table.
So, the question is: are there any configurable properties on TableView or TableColumns to have the behaviour I am looking for?
I am able to freeze columns in javafx table view. We need to create our custom table column class where in we will have two methods setFixed and isFixed which will be used to make some column as fixed.
Apart from this you need to create your own
TableViewskin
TableHeaderRow - basically in this class you need to override the getRootHeader() method
NestedTableColumnHeader - In this class override layoutChildren() method and add new method to layout the fixedColumns
VirtualFlow
TableView - override createDefaultSkin() , add new booleanProperty showColumnHeaderand one ObservableArrayList for fixedTableColumn
TableRow - Override createDefaultSkin()
TableRowSkinBase - override layoutChildren() method to handle fixed columns.
There is currently no such feature. In fact, even manipulating the scroll bar and responding to scrollbar events are problematic. Two options I can think of:
Option #1 - Multiple Table
Create a new layout which contains the two tables and two scroll bars like in the FXML snippet below:
<BorderPane prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<bottom>
<ScrollBar fx:id="hScroll" />
</bottom>
<center>
<HBox fx:id="varTable" prefHeight="100.0" prefWidth="200.0">
<children>
<TableView fx:id="fixedTable" prefHeight="200.0" prefWidth="200.0">
<columns>
<TableColumn prefWidth="75.0" text="Column X" />
<TableColumn prefWidth="75.0" text="Column X" />
</columns>
</TableView>
<TableView prefHeight="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS">
<columns>
<TableColumn prefWidth="75.0" text="Column X" />
<TableColumn prefWidth="75.0" text="Column X" />
</columns>
</TableView>
</children>
</HBox>
</center>
<right>
<ScrollBar fx:id="vScroll" orientation="VERTICAL" />
</right>
</BorderPane>
Note the second tabe has HBox.hgrow="ALWAYS" set.
Write a function to locate the scroll bar in a TableView:
private static final ScrollBar getScrollBar(final TableView<?> tableView) {
for (final VirtualFlow virtualFlow: Nodes.filter(Nodes.descendents(tableView, 2), VirtualFlow.class)) {
for (final Node subNode: virtualFlow.getChildrenUnmodifiable()) {
if (subNode instanceof ScrollBar && ((ScrollBar)subNode).getOrientation() == Orientation.VERTICAL) {
return (ScrollBar)subNode;
}
}
}
return null;
}
Use this to locate the two vertical scroll bars and bind their properties (like min, max, value etc.) to your own vertical scroll bar and then hide the original scroll bars. You will also need to set managed=false so that they do not take up space in the layout.
Locate and hide the horizontal scroll bars and bind the properties of the 'moving' table horizontal scroll bar to your own horizontal scroll bar.
We are succesfully using this technique to link two tables with a single scroll bar while waiting for this Jira to be fixed.
Option #2 - Write your own TableViewSkin
Download the JavaFx source to see what they do with the skin and then you can either write a complete custom skin or write a skin that wraps two regular skins and implement in a similar way to Option #1 above
So, the question is: are there any configurable properties on TableView or TableColumns to have the behaviour I am looking for?
Apparently not, but there is a feature request for this behavior on the JavaFX Jira (you'll need to register to view it):
https://javafx-jira.kenai.com/browse/RT-19454
I suggest you vote for it. :^)
JavaFX doesn't have this functionality. Check out ControlsFX's SpreadsheetView.
Code worked with javafx 11
import javafx.application.Platform;
import javafx.scene.AccessibleAttribute;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.TableCell;
import javafx.scene.layout.Region;
public class LockedTableCell<T, S> extends TableCell<T, S> {
{
Platform.runLater(() -> {
try {
ScrollBar scrollBar = (ScrollBar) getTableView()
.queryAccessibleAttribute(AccessibleAttribute.HORIZONTAL_SCROLLBAR);
// set fx:id of TableColumn and get region of column header by #id
Region headerNode = (Region) getTableView().lookup("#" + getTableColumn().getId());
scrollBar.valueProperty().addListener((ob, o, n) -> {
double doubleValue = n.doubleValue();
// move header and cell with translateX & bring it front
headerNode.setTranslateX(doubleValue);
headerNode.toFront();
this.setTranslateX(doubleValue);
this.toFront();
});
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
Using it (with first M columns)
tableColumnInstance1.setCellFactory(param -> new LockedTableCell<>() {...});
tableColumnInstance2.setCellFactory(param -> new LockedTableCell<>() {...});
...
tableColumnInstanceM.setCellFactory(param -> new LockedTableCell<>() {...});

Categories

Resources