I got a SegmentedButton which contains 3 "glyph only" ToggleButtons like this:
<SegmentedButton maxWidth="Infinity" prefWidth="Infinity">
<buttons>
<fx:define>
<ToggleGroup fx:id="albumViewToggleGroup"/>
</fx:define>
<ToggleButton maxWidth="Infinity" fx:id="tagCloudToggle" mnemonicParsing="false" selected="true" toggleGroup="$albumViewToggleGroup">
<graphic>
<Glyph fontFamily="FontAwesome" icon="TAGS"></Glyph>
</graphic>
</ToggleButton>
<ToggleButton maxWidth="Infinity" fx:id="gridFlowToggle" mnemonicParsing="false" toggleGroup="$albumViewToggleGroup" >
<graphic>
<Glyph fontFamily="FontAwesome" icon="TH"></Glyph>
</graphic>
</ToggleButton>
<ToggleButton maxWidth="Infinity" fx:id="coverFlowToggle" mnemonicParsing="false" toggleGroup="$albumViewToggleGroup">
<graphic>
<Glyph fontFamily="FontAwesome" icon="ELLIPSIS_H"></Glyph>
</graphic>
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</ToggleButton>
</buttons>
</SegmentedButton>
The SegmenedtButton consumes the full width (represented by the red line), though the ToggleButtons are not. I checked this by setting a background color.
I would like that the ToggleButtons are stretched so that they are each 1/3 of the width of the SegmentedButton. How can i achive this?
According to the documentatiom mathematical operators can be used in fxml bindings.
So something like this can be used:
<SegmentedButton fx:id="segButton" maxWidth="1.7976931348623157E308" >
<buttons>
<ToggleButton fx:id="option1" maxWidth="1.7976931348623157E308" prefWidth="${segButton.width / 4}" text="K3" />
<ToggleButton fx:id="option1" maxWidth="1.7976931348623157E308" prefWidth="${segButton.width / 4}" text="K2" />
<ToggleButton fx:id="option1" maxWidth="1.7976931348623157E308" prefWidth="${segButton.width / 4}" text="K1" />
<ToggleButton fx:id="option1" maxWidth="1.7976931348623157E308" prefWidth="${segButton.width / 4}" text="K1,1" />
</buttons>
</SegmentedButton>
Probably no longer needed, but should hopefully be useful for anyone who winds up googling this.
I doubt that you still need help with this problem, but for anyone like me, who googled the problem and got here, here's how I solved it:
button1.prefWidthProperty().bind(segmentedButtons.widthProperty().divide(2));
button2.prefWidthProperty().bind(segmentedButtons.widthProperty().divide(2));
segmentedButtons.getButtons().addAll(button1, button2);
segmentedButtons.setMaxWidth(Double.MAX_VALUE);
So basically, for every ToggleButton that you add to SegmentedButton you bind preferred width to the actual width of SegmentedButton divided by the number of buttons. Since it's binding, the width will adjust on resizing the window, so you need to do it only once on creation. And if you want, you can divide width in some other way to make some buttons bigger and some smaller.
Related
Is it possible to remove the space between the bars in a bar chart in JavaFX? Where is the option?
barGap and/ or categoryGap does this:
<BarChart fx:id="chart" barGap="0" categoryGap="0" animated="false" maxWidth="Infinity"
HBox.hgrow="ALWAYS" maxHeight="100" prefHeight="60" minHeight="40">
<xAxis>
<CategoryAxis fx:id="xAxis" tickLabelsVisible="false" />
</xAxis>
<yAxis>
<NumberAxis fx:id="yAxis" tickLabelsVisible="false" />
</yAxis>
</BarChart>
I am building a UI using Java FX scene builder and I want a button in a toolbar to float towards the right side of the toolbar. I have tried changing the node orientation of the parent(toolbar) and also the button but both seem to be ignored.
Add a pane with no content which always grows to fit available space between the left aligned tools in the bar and right aligned ones.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<ToolBar prefHeight="40.0" prefWidth="318.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
<Button text="Apples" />
<Button text="Oranges" />
<Pane HBox.hgrow="ALWAYS" />
<Button text="Help" />
</ToolBar>
(Verified in Scene Builder 11.0.0)
One option: Use two ToolBar containers wrapped with an HBox container. Put the Help button in the right ToolBar. Put the left-aligned buttons in the left toolbar. For the left ToolBar, set the HGrow to ALWAYS. For the Right ToolBar, set HGrow to NEVER. For each ToolBar, set all Sizes to USE_COMPUTED_SIZE.
Here is the relevant fxml:
<HBox VBox.vgrow="NEVER">
<children>
<ToolBar HBox.hgrow="ALWAYS">
<items>
<Button text="Apples" />
<Button text="Oranges" />
</items>
</ToolBar>
<ToolBar HBox.hgrow="NEVER">
<items>
<Button text="Help" />
</items>
</ToolBar>
</children>
</HBox>
This is the hierarchy as displayed in Scene Builder:
This is the display within Scene Builder:
If you could place ur button inside a stack pane then u could make use of Stackpane's alignment property that takes javafx.geometry.Pos - The alignment of the child within the stackpane.For example in ur case:
<StackPane >
<Button translateY="-15" translateX="15" StackPane.alignment="TOP_RIGHT"/>
</StackPane>
BorderPane mainBorderPane = new BorderPane();
BorderPane ToolBorderPane = new BorderPane();
ToolBar tBarLeft=new ToolBar();
ToolBar tBarRight=new ToolBar();
ToolBorderPane.setLeft(tBarLeft);
ToolBorderPane.setRight(tBarRight);
mainBorderPane.setTop(ToolBorderPane);
...
...
for your left aligment items add tBarLeft and
your right aligment items add tBarRight
It can be done with some hack: apply 180 degree rotation around Y-axis for the toolbar and all its buttons.
<ToolBar rotate="-180.0" HBox.hgrow="ALWAYS">
<items>
<Button mnemonicParsing="false" rotate="180.0" text="Button">
<rotationAxis>
<Point3D y="1.0" />
</rotationAxis>
</Button>
</items>
<rotationAxis>
<Point3D y="1.0" />
</rotationAxis>
</ToolBar>
I’m coding with JavaFXML and Gluon Scene Builder 8.0.0 to create a pixel editor app. I have created two .fxml files, one for drawing tools (sample.fxml) and the other for an array of Circle Objects (32 x 32) that represents a pixel array of LEDs (PixelEditor.fxml). Both share the same controller (Controller.java).
I can’t initialize my Circle[][] array in Controller.java when the user clicks on a menu item like 32h x 32w. I used a 4 x4 array to test my code:
public void handleMenuAction(ActionEvent event) throws IOException {
if(event.getSource() == menu32hx32w) {
Stage pixelStage = new Stage();
Parent pixelRoot = FXMLLoader.load(getClass().getResource("PixelEditor.fxml"));
Scene pixelScene = new Scene(pixelRoot);
pixelStage.setTitle("Pixel Array: 32h X 32w");
pixelStage.setScene(pixelScene);
pixelStage.setX(0.0);
pixelStage.setY(0.0);
pixelStage.show();
Circle[][] pixelArray = {
{R0C0, R0C1, R0C2, R0C3},
{R1C0, R1C1, R1C2, R1C3},
{R2C0, R2C1, R2C2, R2C3},
{R3C0, R3C1, R3C2, R3C3},
};
}
}
If I print out the array I get:
pixelArray:
null null null null
null null null null
null null null null
null null null null
When I had only one .fxml containing all the Objects I could initialize the pixelArray. I use fx:id to reference the Circle Objects but placing them in a separate Stage and Scene seems to de-reference them and create a null elements.
What am I not doing?
Previously, with one .fxml file, all I needed to assign values to the Circle Objects was to reference their fx:id in the Controller.java as follows:
#FXML
private Circle
R0C0, R0C1, R0C2, R0C3,
R1C0, R1C1, R1C2, R1C3,
R2C0, R2C1, R2C2, R2C3,
R3C0, R3C1, R3C2, R3C3;
This is what I'm still doing but the assigned properties via the fx:id reference don't seem to connect?
The PixelEditor.fxml is quite large because I have 32x32 = 1024 Circle Objects even though I'm just testing with the first 4x4. The code for the first row looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<Pane fx:id="panePixelLayout" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="776.0" prefWidth="776.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<VBox prefHeight="776.0" prefWidth="776.0" style="-fx-background-color: #000000;">
<children>
<HBox prefHeight="24.0" prefWidth="776.0" style="-fx-background-color: #000000;">
<children>
<Circle fx:id="R0C0" fill="DODGERBLUE" onDragDetected="#onDragDetected" onMouseClicked="#pixelClicked" onMouseDragEntered="#onMouseDragEntered" onMousePressed="#onMousePressed" radius="8.0" stroke="BLACK" strokeType="INSIDE" style="-fx-fill: DARKGREY;">
<HBox.margin>
<Insets left="8.0" top="8.0" />
</HBox.margin>
</Circle>
<Circle fx:id="R0C1" fill="DODGERBLUE" layoutX="22.0" layoutY="22.0" onDragDetected="#onDragDetected" onMouseClicked="#pixelClicked" onMouseDragEntered="#onMouseDragEntered" onMousePressed="#onMousePressed" radius="8.0" stroke="BLACK" strokeType="INSIDE" style="-fx-fill: DARKGREY;">
<HBox.margin>
<Insets left="8.0" top="8.0" />
</HBox.margin>
</Circle>
<Circle fx:id="R0C2" fill="DODGERBLUE" layoutX="22.0" layoutY="22.0" onDragDetected="#onDragDetected" onMouseClicked="#pixelClicked" onMouseDragEntered="#onMouseDragEntered" onMousePressed="#onMousePressed" radius="8.0" stroke="BLACK" strokeType="INSIDE" style="-fx-fill: DARKGREY;">
<HBox.margin>
<Insets left="8.0" top="8.0" />
</HBox.margin>
</Circle>
<Circle fx:id="R0C3" fill="DODGERBLUE" layoutX="42.0" layoutY="22.0" onDragDetected="#onDragDetected" onMouseClicked="#pixelClicked" onMouseDragEntered="#onMouseDragEntered" onMousePressed="#onMousePressed" radius="8.0" stroke="BLACK" strokeType="INSIDE" style="-fx-fill: DARKGREY;">
<HBox.margin>
<Insets left="8.0" top="8.0" />
</HBox.margin>
</Circle>
It looks like you haven't actually set values to any of: R0C0, R0C1, etc. If these variables are set to null when you create the array, they will still be null even if you set them later.
You haven't shown the part of your code where you assign R0C0, but most likely, that is where the problem is.
This question was answered in a related question by jewelsea who provided a most excellent answer at: Have multiple FXML files (created in SceneBuilder), but only one controller. Does each scene load it's own copy of the controller?.
By creating two controllers, I was able to initialize my Circle[][] array but now I will have to pass parameters between two controllers as jewelsea describes via links provided.
I am building a UI using Java FX scene builder and I want a button in a toolbar to float towards the right side of the toolbar. I have tried changing the node orientation of the parent(toolbar) and also the button but both seem to be ignored.
Add a pane with no content which always grows to fit available space between the left aligned tools in the bar and right aligned ones.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<ToolBar prefHeight="40.0" prefWidth="318.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
<Button text="Apples" />
<Button text="Oranges" />
<Pane HBox.hgrow="ALWAYS" />
<Button text="Help" />
</ToolBar>
(Verified in Scene Builder 11.0.0)
One option: Use two ToolBar containers wrapped with an HBox container. Put the Help button in the right ToolBar. Put the left-aligned buttons in the left toolbar. For the left ToolBar, set the HGrow to ALWAYS. For the Right ToolBar, set HGrow to NEVER. For each ToolBar, set all Sizes to USE_COMPUTED_SIZE.
Here is the relevant fxml:
<HBox VBox.vgrow="NEVER">
<children>
<ToolBar HBox.hgrow="ALWAYS">
<items>
<Button text="Apples" />
<Button text="Oranges" />
</items>
</ToolBar>
<ToolBar HBox.hgrow="NEVER">
<items>
<Button text="Help" />
</items>
</ToolBar>
</children>
</HBox>
This is the hierarchy as displayed in Scene Builder:
This is the display within Scene Builder:
If you could place ur button inside a stack pane then u could make use of Stackpane's alignment property that takes javafx.geometry.Pos - The alignment of the child within the stackpane.For example in ur case:
<StackPane >
<Button translateY="-15" translateX="15" StackPane.alignment="TOP_RIGHT"/>
</StackPane>
BorderPane mainBorderPane = new BorderPane();
BorderPane ToolBorderPane = new BorderPane();
ToolBar tBarLeft=new ToolBar();
ToolBar tBarRight=new ToolBar();
ToolBorderPane.setLeft(tBarLeft);
ToolBorderPane.setRight(tBarRight);
mainBorderPane.setTop(ToolBorderPane);
...
...
for your left aligment items add tBarLeft and
your right aligment items add tBarRight
It can be done with some hack: apply 180 degree rotation around Y-axis for the toolbar and all its buttons.
<ToolBar rotate="-180.0" HBox.hgrow="ALWAYS">
<items>
<Button mnemonicParsing="false" rotate="180.0" text="Button">
<rotationAxis>
<Point3D y="1.0" />
</rotationAxis>
</Button>
</items>
<rotationAxis>
<Point3D y="1.0" />
</rotationAxis>
</ToolBar>
I'm programming a app with JavaFX and Scene Builder. I want to create a container and insert an image inside.
But, the container have a size so if the image goes out that limits you can't see this image.
For Example, make a container and make the image too much bigger outside that, but just see what is inside the container.
Is that possible?
Solution
Use an ImageView (which is a node container for an Image). You can set a viewport on the ImageView to have the view render a specific part of an image.
Alternative Implementation
Specify your image in CSS and use combinations of -fx-background-image, -fx-background-repeat, -fx-background-position and -fx-background-size as defined in the JavaFX CSS reference guide.
The rest of this answer deals with just the FXML based solution and not the CSS based solution.
Code Based Sample
Here is a code snippet (adapted from the ImageView javadoc) which demonstrates setting a viewport in code:
Image image = new Image("flower.png");
ImageView view = new ImageView();
view.setImage(image);
Rectangle2D viewportRect = new Rectangle2D(40, 35, 110, 110);
view.setViewport(viewportRect);
FXML Based Sample
Here is some FXML to demonstrate the viewport approach.
<ImageView pickOnBounds="true">
<image>
<Image url="http://icons.iconarchive.com/icons/vincentburton/diaguita-ceramic-bowl/128/Diaguita-Ceramic-Bowl-4-icon.png" />
</image>
<viewport>
<Rectangle2D minX="35.0" minY="55.0" width="55.0" height="40.0" />
</viewport>
</ImageView>
Here is a complete example which you can load up into SceneBuilder. The first ImageView displays an unclipped image, the second ImageView displays a clipped image.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.geometry.Rectangle2D?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<StackPane id="StackPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" style="-fx-background-color: burlywood;" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
<children>
<VBox alignment="CENTER" prefHeight="-1.0" prefWidth="-1.0" spacing="10.0" style="-fx-background-color: cornsilk;">
<children>
<ImageView pickOnBounds="true">
<image>
<Image url="http://icons.iconarchive.com/icons/vincentburton/diaguita-ceramic-bowl/128/Diaguita-Ceramic-Bowl-4-icon.png" />
</image>
</ImageView>
<ImageView pickOnBounds="true">
<image>
<Image url="http://icons.iconarchive.com/icons/vincentburton/diaguita-ceramic-bowl/128/Diaguita-Ceramic-Bowl-4-icon.png" />
</image>
<viewport>
<Rectangle2D height="40.0" minX="35.0" minY="55.0" width="55.0" />
</viewport>
</ImageView>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</StackPane>
On using the FXML Based Sample in SceneBuilder
To generate the FXML, the majority of the work was done in SceneBuilder, but setting the viewport was done by hand editing the FXML saved from SceneBuilder (because SceneBuilder 1.1 does not possess the UI to set the viewport on ImageViews from within the SceneBuilder tool). After hand-editing the FXML to add the viewport, you can reload the FXML in SceneBuilder and SceneBuilder will render the viewport in the hand-edited FXML fine.
Also, SceneBuilder 2 build 14 preview did not display images that are located using the http protocol (SceneBuilder 1.1 did not have an issue with this).
Attribution
Icon used in the answer is licensed CC Attribution-Noncommercial-Share Alike 3.0 with a linkback to the icon author.