private void updateStyleInSelection(StyleInfo mixin) { IndexRange selection = area.getSelection(); if (selection.getLength() != 0) { StyleSpans<StyleInfo> styles = area.getStyleSpans(selection); StyleSpans<StyleInfo> newStyles = styles.mapStyles(style -> style.updateWith(mixin)); area.setStyleSpans(selection.getStart(), newStyles); } }
@Override public void start(Stage primaryStage) { CheckBox wrapToggle = new CheckBox("Wrap"); wrapToggle.setSelected(true); area.wrapTextProperty().bind(wrapToggle.selectedProperty()); Button undoBtn = createButton("undo", () -> area.undo()); Button redoBtn = createButton("redo", () -> area.redo()); Button cutBtn = createButton("cut", () -> area.cut()); Button copyBtn = createButton("copy", () -> area.copy()); Button pasteBtn = createButton("paste", () -> area.paste()); Button boldBtn = createButton("bold", () -> toggleBold()); Button italicBtn = createButton("italic", () -> toggleItalic()); Button underlineBtn = createButton("underline", () -> toggleUnderline()); Button strikeBtn = createButton("strikethrough", () -> toggleStrikethrough()); ComboBox<Integer> sizeCombo = new ComboBox<>( FXCollections.observableArrayList( 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 28, 32, 36, 40, 48, 56, 64, 72)); sizeCombo.getSelectionModel().select(Integer.valueOf(12)); ComboBox<String> familyCombo = new ComboBox<>(FXCollections.observableList(Font.getFamilies())); familyCombo.getSelectionModel().select("Serif"); ColorPicker textColorPicker = new ColorPicker(Color.BLACK); ColorPicker backgroundColorPicker = new ColorPicker(); sizeCombo.setOnAction(evt -> updateFontSize(sizeCombo.getValue())); familyCombo.setOnAction(evt -> updateFontFamily(familyCombo.getValue())); textColorPicker.valueProperty().addListener((o, old, color) -> updateTextColor(color)); backgroundColorPicker .valueProperty() .addListener((o, old, color) -> updateBackgroundColor(color)); undoBtn.disableProperty().bind(Bindings.not(area.undoAvailableProperty())); redoBtn.disableProperty().bind(Bindings.not(area.redoAvailableProperty())); BooleanBinding selectionEmpty = new BooleanBinding() { { bind(area.selectionProperty()); } @Override protected boolean computeValue() { return area.getSelection().getLength() == 0; } }; cutBtn.disableProperty().bind(selectionEmpty); copyBtn.disableProperty().bind(selectionEmpty); area.beingUpdatedProperty() .addListener( (o, old, beingUpdated) -> { if (!beingUpdated) { boolean bold, italic, underline, strike; Integer fontSize; String fontFamily; Color textColor; Color backgroundColor; IndexRange selection = area.getSelection(); if (selection.getLength() != 0) { StyleSpans<StyleInfo> styles = area.getStyleSpans(selection); bold = styles.styleStream().anyMatch(s -> s.bold.orElse(false)); italic = styles.styleStream().anyMatch(s -> s.italic.orElse(false)); underline = styles.styleStream().anyMatch(s -> s.underline.orElse(false)); strike = styles.styleStream().anyMatch(s -> s.strikethrough.orElse(false)); int[] sizes = styles .styleStream() .mapToInt(s -> s.fontSize.orElse(-1)) .distinct() .toArray(); fontSize = sizes.length == 1 ? sizes[0] : -1; String[] families = styles .styleStream() .map(s -> s.fontFamily.orElse(null)) .distinct() .toArray(i -> new String[i]); fontFamily = families.length == 1 ? families[0] : null; Color[] colors = styles .styleStream() .map(s -> s.textColor.orElse(null)) .distinct() .toArray(i -> new Color[i]); textColor = colors.length == 1 ? colors[0] : null; Color[] backgrounds = styles .styleStream() .map(s -> s.backgroundColor.orElse(null)) .distinct() .toArray(i -> new Color[i]); backgroundColor = backgrounds.length == 1 ? backgrounds[0] : null; } else { int p = area.getCurrentParagraph(); int col = area.getCaretColumn(); StyleInfo style = area.getStyleAtPosition(p, col); bold = style.bold.orElse(false); italic = style.italic.orElse(false); underline = style.underline.orElse(false); strike = style.strikethrough.orElse(false); fontSize = style.fontSize.orElse(-1); fontFamily = style.fontFamily.orElse(null); textColor = style.textColor.orElse(null); backgroundColor = style.backgroundColor.orElse(null); } updatingToolbar.suspendWhile( () -> { if (bold) { if (!boldBtn.getStyleClass().contains("pressed")) { boldBtn.getStyleClass().add("pressed"); } } else { boldBtn.getStyleClass().remove("pressed"); } if (italic) { if (!italicBtn.getStyleClass().contains("pressed")) { italicBtn.getStyleClass().add("pressed"); } } else { italicBtn.getStyleClass().remove("pressed"); } if (underline) { if (!underlineBtn.getStyleClass().contains("pressed")) { underlineBtn.getStyleClass().add("pressed"); } } else { underlineBtn.getStyleClass().remove("pressed"); } if (strike) { if (!strikeBtn.getStyleClass().contains("pressed")) { strikeBtn.getStyleClass().add("pressed"); } } else { strikeBtn.getStyleClass().remove("pressed"); } if (fontSize != -1) { sizeCombo.getSelectionModel().select(fontSize); } else { sizeCombo.getSelectionModel().clearSelection(); } if (fontFamily != null) { familyCombo.getSelectionModel().select(fontFamily); } else { familyCombo.getSelectionModel().clearSelection(); } if (textColor != null) { textColorPicker.setValue(textColor); } backgroundColorPicker.setValue(backgroundColor); }); } }); HBox panel1 = new HBox(3.0); HBox panel2 = new HBox(3.0); panel1 .getChildren() .addAll( wrapToggle, undoBtn, redoBtn, cutBtn, copyBtn, pasteBtn, boldBtn, italicBtn, underlineBtn, strikeBtn); panel2.getChildren().addAll(sizeCombo, familyCombo, textColorPicker, backgroundColorPicker); VBox vbox = new VBox(); VBox.setVgrow(area, Priority.ALWAYS); vbox.getChildren().addAll(panel1, panel2, area); Scene scene = new Scene(vbox, 600, 400); scene.getStylesheets().add(RichText.class.getResource("rich-text.css").toExternalForm()); primaryStage.setScene(scene); area.requestFocus(); primaryStage.setTitle("Rich Text Demo"); primaryStage.show(); }