Listing all available system fonts in a Choice Box - java

I have a scene with a choice box. the aim is to get all available system fonts to display in the choice box, I kinda feel I'm on the right path as so far I have managed to get 1 to display in the choice box, but why just the 1?
here is the code -
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.SingleSelectionModel;
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
public class ChoiceBoxFonts extends Application
{
ObservableList<String> fontType;
ChoiceBox<String> fonts;
public static void main(String [] args)
{
Application.launch(args);
}
public void start(Stage primaryStage)
{
Pane root = new Pane();
Font.getFamilies().stream().forEach(i ->{
fontType =
FXCollections.observableArrayList(i
);
});
// New choicebox with observable arraylist fontType
fonts = new ChoiceBox<String> (fontType);
//SingleSelectionModel<String> selMod = fonts.getSelectionModel();
root.getChildren().add(fonts);
Scene scene = new Scene(root,200,200);
primaryStage.setScene(scene);
primaryStage.show();
}
}
The goal of the experiment is to be able to select a font from the choice box and change the font of a text object with that selection.
Also, is there a better UI to be able to do such a thing? If there are a bucket load of fonts, that choice box is going to be very long!

You just need
fontType = FXCollections.observableArrayList(Font.getFamilies());
instead of the iteration you have.
If there are a bucket load of fonts, that choice box is going to be very long!
I would probably consider a ListView.

Related

Is there a way to "autofit" elements on a page so they take up the entire canvas

In JavaFX, is there a way to "autofit" elements on a page so they take up the entire thing?
Currently, I'm trying to make the window have two buttons that together take up the entire canvas, but I am not sure how to do that, given that it is possible to stretch the window, etc. I've tried playing around with Button.setPrefSize, but the button size stays the same, it just shows you a window with two outsized buttons, the text of which is not visible.
What I currently have
What I want (but for any window size)
Here's one way (code here but also possible in Scene Builder and FXML):
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
public class TestApplication extends Application {
#Override
public void start(Stage stage) throws Exception {
Button button1 = new Button("Button1");
HBox.setHgrow(button1, Priority.SOMETIMES);
button1.setMaxWidth(Double.MAX_VALUE);
button1.setMaxHeight(Double.MAX_VALUE);
Button button2 = new Button("Button2");
HBox.setHgrow(button2, Priority.SOMETIMES);
button2.setMaxWidth(Double.MAX_VALUE);
button2.setMaxHeight(Double.MAX_VALUE);
HBox hBox = new HBox(button1, button2);
AnchorPane.setLeftAnchor(hBox, 0.0);
AnchorPane.setRightAnchor(hBox, 0.0);
AnchorPane.setTopAnchor(hBox, 0.0);
AnchorPane.setBottomAnchor(hBox, 0.0);
AnchorPane rootContainer = new AnchorPane(hBox);
Scene scene = new Scene(rootContainer, 600, 600);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}

JavaFX container in ScrollPane not showing

I have heard that, to add more controls/JavaFX Nodes to a ScrollPane, one must set the ScrollPane's content to a container, then add all Nodes to said container. However, when trying this, I only get a small, grey bar without any content. How can I fix this? (Trying to make something larger, but even this MWE doesn't work for me... - Working with OpenJDK OpenJFX 11 on Manjaro, if that helps)
Code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(final Stage primaryStage) {
Label test = new Label();
test.setText("Testing JavaFX........");
VBox box = new VBox();
ScrollPane pane = new ScrollPane(box);
pane.setPrefSize(300.0, 300.0);
box.getChildren().add(test);
Scene main = new Scene(pane);
primaryStage.setScene(main);
primaryStage.show();
}
}
Result:

Trying to select programatically in JavaFX is not working

I am in the process of teaching myself JavaFX. Coming from the Swing world there are a lot of similarities between the 2. Especially event processing. Part of my process is to try and mimic an existing application as closely as possible. One of the things I am doing is creating a dialog that will allow the user to select a font to use. There is a text field for them to type in the font name and a list where they can scroll and select one. When they start typing the list will automatically scroll to through the list to start matching what the user is typing. I am also trying to populate the text field with the currently matched font name and then highlight the portion that the user has not typed yet so they can continue to type until the correct match is found.
For example if the user types the letter 't' on Windows the first font found is Tahoma. So the text field will be set to Tahoma and the carat will be positioned right after the 'T' and the 'ahoma' will be highlighted. What happens instead is that the field is populated with Tahoma and the carat is positioned at the end and nothing is highlighted. So it is like it is ignoring the 2 lines of code for positioning and highlighting or the event processor is causing my calls to JavaFX libraries to be run out of order.
I think this may be a bug with JavaFX but it could also be my misunderstanding of the event system. Please let me know which one and why.
Here is a complete sample code showing the problem. Just start typing in the text field to try it out.
package test;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class TestTyping extends Application {
ChangeListener<String> textChange;
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
TextField text = new TextField();
root.setTop(text);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
textChange = (observable, oldValue, newValue) -> {
text.textProperty().removeListener(textChange);
for (String family : Font.getFamilies()) {
if (family.equalsIgnoreCase(newValue) || family.toLowerCase().startsWith(newValue.toLowerCase())) {
text.setText(family);
text.positionCaret(newValue.length());
text.selectEnd();
break;
}
}
text.textProperty().addListener(textChange);
};
text.textProperty().addListener(textChange);
}
public static void main(String... args) {
launch(args);
}
}
Wrap caret position and select end into Platform.runLater. The problem is in events order. I don't know correct details about this issue so I will not provide you a detailed answer, only solution.
Platform.runLater(()-> {
text.positionCaret(newValue.length());
text.selectEnd();
});
Here's an alternative approach entirely, which uses a TextFormatter to modify changes to the text. The advantage here is that it doesn't rely on the "timing" of various property changes with respect to event handling, which is not documented and thus could possibly change in later JavaFX versions. It also avoids the slightly ugly "remove the listener and add it back" idiom.
import java.util.function.UnaryOperator;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TextFormatter.Change;
import javafx.scene.layout.BorderPane;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class TestTyping extends Application {
ChangeListener<String> textChange;
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
TextField text = new TextField();
root.setTop(text);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
UnaryOperator<Change> filter = c -> {
// for delete, move the caret, or change selection, don't modify anything...
if (c.getText().isEmpty()) {
return c ;
}
for (String family : Font.getFamilies()) {
if (family.toLowerCase().startsWith(c.getControlNewText().toLowerCase())) {
c.setText(family.substring(c.getRangeStart(), family.length()));
c.setAnchor(c.getControlNewText().length());
break ;
}
}
return c ;
};
text.setTextFormatter(new TextFormatter<String>(filter));
}
public static void main(String... args) {
launch(args);
}
}

JavaFX ScrollPane doesn't fill it's parent pane

I'm trying to learn JavaFX. To do so I've been attempting to make a text editor that includes multiple line text box support, as well as the possibility of having syntax highlighting down the road.
Currently, the biggest problem I've been facing is that the ScrollPane I've been encapsulating all my FlowPanes in won't resize according to the size of the Pane it's in. I've been researching this problem for about half a week now and simply cannot get the ScrollPane to just fill the window it's in. The code below displays a JavaFX stage that has working keyboard input and the ScrollPane is always the same size no matter what. Thanks to all in advance!
Here's my Main:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Launcher extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(new DynamicTextBox(),500,500));
primaryStage.show();
}
}
TextBox class:
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.geometry.Orientation;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import javafx.scene.text.Text;
public class DynamicTextBox extends Pane {
//currentLinePane is made to handle all the direct user inputs
//multiLinePane, while not really used yet will create a new line when the enter key is struck.
private FlowPane currentLinePane, multiLinePane;
private ScrollPane editorScroller;
public DynamicTextBox() {
super();
currentLinePane = new FlowPane(Orientation.HORIZONTAL);
multiLinePane = new FlowPane(Orientation.VERTICAL);
multiLinePane.getChildren().add(currentLinePane);
editorScroller = new ScrollPane(multiLinePane);
editorScroller.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
editorScroller.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
editorScroller.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
configureInput(event);
}
});
super.getChildren().add(editorScroller);
editorScroller.requestFocus();
}
private void configureInput(KeyEvent event) {
currentLinePane.getChildren().add(new Text(event.getText()));
}
}
You're using
ScrollPane.ScrollBarPolicy.AS_NEEDED
which, according to the docs at Oracle, "Indicates that a scroll bar should be shown when required." Instead, use
ScrollPane.ScrollBarPolicy.ALWAYS
alternatively, recall these are constants. you can get the height of the parent using boundsInParent: https://docs.oracle.com/javafx/2/api/javafx/scene/Node.html#boundsInParentProperty
alternatively, you can use getParent() to get the parent and then get its height using computeMinWidth() https://docs.oracle.com/javafx/2/api/javafx/scene/Node.html#getParent()

JavaFX primaryStage remove windows borders? [duplicate]

This question already has an answer here:
JavaFX: Undecorated Window
(1 answer)
Closed 8 years ago.
I am making JavaFX destop application. I want to remove the default windows border and also I want to customize the 3 standard icons of minimize , maximize and close.
The original motivation of this kind of looks or customization is new Kaspersky 2012 User Interface.... I want to design something like that... :)
This example might be a good starting point. All window decoration is removed. A class extending HBox can be used to place custom buttons for standard window operations.
package javafxdemo;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class JavaDemo extends Application {
public static void main(String[] args) {
launch(args);
}
class WindowButtons extends HBox {
public WindowButtons() {
Button closeBtn = new Button("X");
closeBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
Platform.exit();
}
});
this.getChildren().add(closeBtn);
}
}
#Override
public void start(Stage primaryStage) {
//remove window decoration
primaryStage.initStyle(StageStyle.UNDECORATED);
BorderPane borderPane = new BorderPane();
borderPane.setStyle("-fx-background-color: green;");
ToolBar toolBar = new ToolBar();
int height = 25;
toolBar.setPrefHeight(height);
toolBar.setMinHeight(height);
toolBar.setMaxHeight(height);
toolBar.getItems().add(new WindowButtons());
borderPane.setTop(toolBar);
primaryStage.setScene(new Scene(borderPane, 300, 250));
primaryStage.show();
}
}
You can also download the JavaFX Samples where you can find many more useful examples.

Categories