I'm making an app with JavaFX and Scene Builder.
-I have one combo box for selecting font size (id - size)
-I have one combo box for selecting font family (id - font selector)
-I have a label (id - front label)
Problem #1: When I I click on Combobox with fThe drop-down. Drop-down list appears only after a second. It seems like it works slow
Problem #2: When I click on combobox with font family and choose some font it doesn't apply to the label, but font family applies when I click on combobox and choose font second time. In this case, I should pick a font two times in a row to apply a font to my label
Problem a #3(Main problem): I have conflict of comboboxes. When I choose a font family it applies to the label, but when I choose font size from other combobox size also applies but after that font family of the label become default. Same situation occurs when I pick font size and then pick font family from other combobox.
It seems that only one combobox can be applied to the label.
How to resolve these problems?
*All code is in the Controller
*Problem #3 is the primordial one.
@FXML private ComboBox<String> fontSelector;
@FXML private ComboBox<Integer> size;
@FXML private Label fontLabel;
//create array of font sizes
ObservableList<Integer> fontSizes = FXCollections.observableArrayList(8,
10, 11, 12, 14, 16, 18, 20, 24, 30, 36, 40, 48, 60, 72);
//get fonts from system
ObservableList<String> fonts =
FXCollections.observableArrayList(Font.getFamilies());
//getting Controller variables and methods through Context class
Controller cont = Context.getInstance().getController();
@Override
public void initialize(URL location, ResourceBundle resources) {
//register FontController in Context Class
Context.getInstance().setFontController(this);
//bind text from textfield to label
fontLabel.textProperty().bind(fontTextfield.textProperty());
//show fonts' actual look in combobox list
fontSelector.setCellFactory((ListView<String> listView) -> {
final ListCell<String> cell = new ListCell<>(){
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item);
setFont(new Font(item, 14));
}
}
};
return cell;
});
fontSelector.setItems(fonts);
size.setItems(fontSizes);
size.setOnAction(e -> updateFontSize());
}
Method that applies font size to label from combobox
private void updateFontSize() {
fontLabel.setFont(Font.font(size.getValue()));
}
Method that applies font family from combobox to the label
public void changeLabel(ActionEvent event) {
fontSelector.getSelectionModel().selectedItemProperty().addListener((obs,
oldValue, newValue) -> fontLabel.setFont(Font.font(newValue,
FontWeight.NORMAL, 35)));
}
EDIT:
I assume that conflict of comboboxes appears here:
fontSelector.getSelectionModel().selectedItemProperty().addListener((obs,
oldValue, newValue) -> fontLabel.setFont(Font.font(newValue,
FontWeight.NORMAL, 35)));
How to refactor that line of code to make it work but without concrete font size after FontWeight.Normal in brackets?
You need to combine both values of the ComboBox
es to create the font. You only use a single one each though. As for the delay when opening the font ComboBox
: this is probably caused by the fact that multiple Font
s need to be loaded. You could replace the ComboBox
type parameter Font
and preload the fonts.
To use a custom display for the font in the ComboBox
button area too, you need to use set the same cell type that is created by the cellFactory
as buttonCell
.
Use a binding for the font based on the 2 value
properties of the ComboBox
es instead
Example
private static Font getFont(Font font, Integer size) {
return Font.font(font == null ? null : font.getFamily(), size == null ? -1d : size.doubleValue());
}
@Override
public void start(Stage primaryStage) throws Exception {
ComboBox<Font> fontSelector = new ComboBox<>();
fontSelector.getItems().addAll(Font.getFamilies().stream().map(name -> Font.font(name, 14)).toArray(Font[]::new));
ComboBox<Integer> size = new ComboBox<>();
size.getItems().addAll(10, 11, 12, 14, 16, 18, 20, 24, 30, 36, 40, 48, 60, 72);
Label fontLabel = new Label("Hello World");
// bind font based on size/family
fontLabel.fontProperty()
.bind(Bindings.createObjectBinding(() -> getFont(fontSelector.getValue(), size.getValue()),
fontSelector.valueProperty(), size.valueProperty()));
class FontListCell extends ListCell<Font> {
@Override
public void updateItem(Font item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.getFamily());
setFont(item);
} else {
setText("");
setFont(Font.font(14));
}
}
}
fontSelector.setCellFactory(lv -> new FontListCell());
fontSelector.setButtonCell(new FontListCell());
Scene scene = new Scene(new VBox(fontSelector, size, fontLabel), 300, 500);
primaryStage.setScene(scene);
primaryStage.show();
}