Assuming that my HBox has a following children:
<HBox fx:id="hBox" xmlns="http://javafx.com/javafx/8.0.102-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.controllers.ChatMessageController">
<children>
<TextFlow>
</TextFlow>
<Label text="|" />
<TextFlow>
</TextFlow>
</children>
</HBox>
This HBox can be resized to any values. How can I make sure, that first TextFlow will always fit the size of its content without wrapping?
In other words - I wish the first TextFlow to have an ultimate priority in accesing HBox space.
You can do
<HBox fx:id="hBox" xmlns="http://javafx.com/javafx/8.0.102-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.controllers.ChatMessageController">
<children>
<TextFlow>
<HBox.hgrow><Priority fx:value="ALWAYS"/></HBox.hgrow>
</TextFlow>
<Label text="|" />
<TextFlow>
<HBox.hgrow><Priority fx:value="ALWAYS"/></HBox.hgrow>
</TextFlow>
</children>
</HBox>
Obviously you will need to add the import
<?import javafx.scene.layout.Priority ?>
Related
I want my Chat Window to be reziable and scrollable, so far everything works except the ChatLog itself.
I need a scroll bar, that's why I put the VBox inside of a ScrollPane (which is child of an AnchorPane), but this way only the ScrollPane is responsive (thanks to Anchor Values). If I unwrap VBox I can set Anchor Values, then it works but I'm loosing my scroll bar.
How can I mantain the scroll bar for ChatLog AND make it responsive (attached on the right side)?
FXML:
<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" style="-fx-background-color: #5b2529;" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.lmu.jungejunkervp.ClientWindowController">
<children>
<ScrollPane fx:id="scrollPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="265.0" prefWidth="592.0" AnchorPane.bottomAnchor="57.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="5.0">
<content>
<VBox fx:id="chatLog" prefHeight="265.0" prefWidth="575.0" />
</content></ScrollPane>
<TextArea fx:id="messageBox" layoutX="5.0" layoutY="349.0" onKeyPressed="#onEnterSend" prefHeight="47.0" prefWidth="536.0" promptText="enter message..." AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="61.0" />
<Button fx:id="sendButton" mnemonicParsing="false" onAction="#setSendButtonAction" onMouseClicked="#setSendButtonAction" prefHeight="47.0" prefWidth="52.0" text="Send" AnchorPane.bottomAnchor="5.0" AnchorPane.rightAnchor="5.0" />
</children>
</AnchorPane>
public void addLabel(String message, Pos position) {
HBox hBox = new HBox();
hBox.setAlignment(position);
hBox.setPadding(new Insets(5, 5, 5, 10));
Text text = new Text(message);
TextFlow textFlow = new TextFlow(text);
textFlow.setStyle("-fx-background-color: rgb(233,233,235);" +
"-fx-background-radius: 20px");
textFlow.setPadding(new Insets(5, 10, 5, 10));
hBox.getChildren().add(textFlow);
Platform.runLater(new Runnable() {
#Override
public void run() {
chatLog.getChildren().add(hBox);
}
});
}
public void setSendButtonAction() {
String message = messageBox.getText().replaceAll("[\n\r]", "");
try {
if (!message.isEmpty()) {
// show message on the sending client window
addLabel(message, Pos.CENTER_RIGHT);
}
}
To answer your actual question, below is what you need add to the ScrollPane (in fxml with your current layout).
fitToHeight="true" fitToWidth="true"
The above code will make your VBox responsive with the ScrollPane.
I also suggest to change your layout to get rid of AnchorPane (will all those hardcoded positions). You can use VBox/HBox in conjuction with vgrow/hgrow policies. The optimized fxml will be as below:
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<VBox style="-fx-background-color: #5b2529;" spacing="5" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.lmu.jungejunkervp.ClientWindowController">
<children>
<ScrollPane fx:id="scrollPane" prefHeight="265.0" prefWidth="592.0" fitToHeight="true" fitToWidth="true" VBox.vgrow="ALWAYS">
<content>
<VBox fx:id="chatLog"/>
</content>
</ScrollPane>
<HBox spacing="5">
<TextArea fx:id="messageBox" onKeyPressed="#onEnterSend" prefHeight="47.0" promptText="enter message..." HBox.hgrow="ALWAYS" />
<Button fx:id="sendButton" mnemonicParsing="false" onAction="#setSendButtonAction" prefHeight="47.0" minWidth="52.0" text="Send"/>
</HBox>
</children>
<padding>
<Insets topRightBottomLeft="5"/>
</padding>
</VBox>
Having said that, I think you need to consider changing your layout to what #jewelsea mentioned in the provided example (using ListView).
I set the font size of upper label to 24px.
I don't know where I can check the real height of element (if it's possible in the Scene builder), but there is the extra space in upper (designated in the image) and lower part of box.
The line spacing is 0.
The parent VBox has no top padding.
All label sizes are computed.
I need the height of label equals to font size.
I mean FontSize = Gray space surrounded by blue markers height.
How to reach it?
I have faced with similar problem HTML/CSS.
There, not simple but working solution for most cases is negative margins and :before and :after pseudo elements.
Now which solutions are exists for JavaFX?
The repro
🌎 Repository
Open the resources/static/TasksOverview.fxml by Scene Builder.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="640.0" prefWidth="320.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox alignment="CENTER_LEFT">
<children>
<CheckBox mnemonicParsing="false" />
<VBox>
<children>
<Label style="-fx-font-size: 24px;" text="Wake up">
<VBox.margin>
<Insets />
</VBox.margin>
</Label>
<Label style="-fx-font-size: 14px;" text="... and fly. I need more text to test multiline mode." wrapText="true" />
</children>
<HBox.margin>
<Insets left="12.0" />
</HBox.margin>
</VBox>
</children>
<padding>
<Insets left="12.0" right="12.0" />
</padding>
</HBox>
<HBox alignment="CENTER_LEFT" layoutX="10.0" layoutY="10.0">
<children>
<CheckBox mnemonicParsing="false" />
<VBox>
<children>
<Label style="-fx-font-size: 24px;" text="Wash face">
<VBox.margin>
<Insets />
</VBox.margin>
</Label>
<Label style="-fx-font-size: 14px;" text="... with cold water." wrapText="true" />
</children>
<HBox.margin>
<Insets left="12.0" />
</HBox.margin>
</VBox>
</children>
<padding>
<Insets left="12.0" right="12.0" />
</padding>
</HBox>
</children>
</VBox>
Labels are "smart" controls that include, within the "skin" code, stuff like some in-built padding, as well as various alignment and spacing options for text and graphics, and support for resizing by dynamically eliding text.
If you want some more control over how text layout happens, then you can use raw Text nodes instead of Labels and then do some of the additional layout yourself if needed. Of course you are going to lose a lot of in-built functionality that way (buyer beware...), but sometimes that might be what you want.
For example, a Text node with the following attributes:
A font size of 24.
No spacing on the top, left or right of the visual area of the text.
A margin spacing of 3 pixels below the visual area of the text when placed in a VBox.
can be defined in FXML as below:
<Text boundsType="VISUAL" text="Visual bounds != Logical bounds">
<font>
<Font size="24.0" />
</font>
<VBox.margin>
<Insets bottom="3.0" />
</VBox.margin>
</Text>
If you use this stuff on a lot of text, then you can set a lot of the values in a style sheet rather than FXML (which would be preferable). I won't describe how to do that here other than to say there is an undocumented -fx-bounds-type css attribute for text.
Sometimes rather than using a Text node, it might be better to just "hack" a Label similar to Matt's answer by using stuff like negative insets (that is usually my preferred option...).
Be careful, esoteric discussion follows, get ready to ignore it ;-)
A key part is setting the boundsType to VISUAL. By default the bounds of the text are usually a bit more than what you actually see, which eases alignment issues, because that means the bounds of the letter "a" and the letter "A" are the same. That kind of bounds is the default and is called LOGICAL bounds. VISUAL bounds makes the bounds of those two letters different, so "a"'s bounds is smaller than "A"'s bounds, which is what allows stuff to not take up any more space than it absolutely needs to.
For example, using Text with VISUAL bounds and instead of a Label, gets rid of two sets of the extra whitespace around the text which appears on your example screen shot. One set of whitespace is allocated by the Label control's internal layout algorithm, another set of whitespace is allocated for the LOGICAL bounds.
Setting bounds to VISUAL is possible within a label by applying an appropriate CSS stylesheet, but if you do that, then the label still won't shrink to fit just the VISUAL bounds because it seems to be coded to work based off of LOGICAL bounds, at least that is what some quick testing I tried seemed to show. So using VISUAL bounds in text in a label just seems to make it display incorrectly (which may even be classified as bug by some people). It might work if you set a graphic with Text inside the label, but if you do that, the label doesn't do much for you and may as well just use a Text node directly (unless you are using a control like a TitledPane which includes a Label in the title, in which case you must use a Label).
Just set add a Negative inset and it will shrink the space above your label for example:
<Insets top="-5.0"/>
Full FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="640.0" prefWidth="320.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox alignment="CENTER_LEFT">
<children>
<CheckBox mnemonicParsing="false" />
<VBox>
<children>
<Label style="-fx-font-size: 24px;" text="Wake up">
<VBox.margin>
<Insets top="-5.0"/>
</VBox.margin>
</Label>
<Label style="-fx-font-size: 14px;" text="... and fly. I need more text to test multiline mode." wrapText="true" />
</children>
<HBox.margin>
<Insets left="12.0" />
</HBox.margin>
</VBox>
</children>
<padding>
<Insets left="12.0" right="12.0" />
</padding>
</HBox>
<HBox alignment="CENTER_LEFT" layoutX="10.0" layoutY="10.0">
<children>
<CheckBox mnemonicParsing="false" />
<VBox>
<children>
<Label style="-fx-font-size: 24px;" text="Wash face">
<VBox.margin>
<Insets />
</VBox.margin>
</Label>
<Label style="-fx-font-size: 14px;" text="... with cold water." wrapText="true" />
</children>
<HBox.margin>
<Insets left="12.0" />
</HBox.margin>
</VBox>
</children>
<padding>
<Insets left="12.0" right="12.0" />
</padding>
</HBox>
</children>
</VBox>
How do I make textarea get user input from the textfield ? How to i control these buttons from the controller and is there any possible way that i can make the textfield act as textarea when the user submit , the user may edit it when click on the textarea to edit?
<?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" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxnote.Note2Controller">
<top>
<AnchorPane prefHeight="56.0" prefWidth="600.0" BorderPane.alignment="CENTER">
<children>
<Button fx:id="btn2" layoutX="555.0" layoutY="10.0" mnemonicParsing="false" onMouseClicked="#test" text="x" />
</children>
</AnchorPane>
</top>
<center>
<TextArea prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets left="10.0" right="10.0" />
</BorderPane.margin></TextArea>
</center>
<padding>
<Insets bottom="20.0" />
</padding>
<bottom>
<VBox prefHeight="149.0" prefWidth="600.0" BorderPane.alignment="CENTER">
<children>
<TextField prefHeight="111.0" prefWidth="600.0">
<VBox.margin>
<Insets />
</VBox.margin>
</TextField>
<AnchorPane prefHeight="38.0" prefWidth="580.0">
<children>
<Button fx:id="btsub" layoutX="434.0" layoutY="21.0" mnemonicParsing="false" text="submit" />
<Button fx:id="btcl" layoutX="518.0" layoutY="21.0" mnemonicParsing="false" text="clear" />
</children>
</AnchorPane>
</children>
<BorderPane.margin>
<Insets left="10.0" right="10.0" />
</BorderPane.margin>
</VBox>
</bottom>
</BorderPane>
To add actions in the controller for the buttons:
Add the controller class in SceneBuilder
To specify the controller's class check the right side of the SceneBuilder under the tab "Controller" is a text field named "Controller class". Also notice there is a list with all the node that have an "fx-id".
Add fx:id to all the nodes you need in controller
For any component that you need to work with in the controller add an fx:id. For actions check add a method name in the tab "Code" of any component. For example if you want an action for the button "Submit" add the name of the method there in the field "On Action" named "submitPushed"
In the controller's class add all the Nodes with fx:id
For every node you attributed with an fx:id you need to add it as a property in the controller class with the annotation #FXML. For a TextField with the fx:id textSubmit you will ad a property in the controller
#FXML TextField textSubmit
In the controller class define the methods for the actions
For the button named "Submit" with the action "submitPushed" you need to declare the method of the action
#FXML submitPushed(ActionEvent event){
//add code here for what the button should do
}
If you want to add the TextField's content to the TextArea when the button Submit is pushed
#FXML submitPushed(ActionEvent event){
String content=textField.getText();
String contentTextArea = textArea.getText();
textArea.setText(contentTextArea+"\n"+content);
}
I have two hboxes nested in a vbox and I want the height of all of them to be equally distributed within the vbox. I tried üsing computed in Scene Builder 8 but that's not getting me anywhere! Here's part of the code where I want the hboxes to be distributed evenly:
<VBox prefHeight="269.0" prefWidth="1064.0"
BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</BorderPane.margin>
<children>
<HBox prefHeight="100.0" prefWidth="200.0" />
<HBox prefHeight="100.0" prefWidth="200.0" />
</children>
</VBox>
You can add the VGrow property to the HBox and set it to ALWAYS. This will result in both the HBox always filling up the available space.
<children>
<HBox prefHeight="100.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
<HBox prefHeight="100.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
</children>
I am having a problem with my JavaFX TextArea. I use the FXCanvas to embed an few JavaFX controls into an SWT composite. Everything works fine except for the TextArea which doesn't allow me to highlight text by dragging. Double click and "right click"/"select all" work fine, so text selection does work.
My objects are defined in an FXML file, you cannot do anything simpler:
<Accordion fx:id="accordion" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.kratos.birt.report.data.oda.kairosdb.ui.FXMLController">
<panes>
<TitledPane fx:id="builderPane" text="Query Builder">
...
</TitledPane>
<TitledPane fx:id="jsonPane" text="Raw Query">
<content>
<VBox>
<children>
<Label text="Enter your query:">
<VBox.margin>
<Insets bottom="5.0" />
</VBox.margin>
</Label>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" VBox.vgrow="ALWAYS">
<children>
<TextArea fx:id="queryArea" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</children>
</VBox>
</content>
</TitledPane>
</panes>
</Accordion>
I don't do any modification on it in the code, except for setting some text. The dragging selection doesn't work either if the TextArea isn't in the Accordion container.
The solution I found was to downgrade the version of the JRE (and thus the version of JavaFX) from 8 to 7.