I choose about eight-hundred image files, and each has a 5 MB size using the following code:
List<File> flist = fileChooser.showOpenMultipleDialog(label.getScene().getWindow());
When I click open, the filechooser and the main window freeze (and do not respond).
What should I do to ameliorate this problem? (I don't want to use Swing.)
My code is for adding image file names list to a tableView. Not for loading image. After running this code, I am getting output in the terminal:
Total Files added: 800.
But filechooser and the main window freeze (and do not respond)
public void addImage()
{
int i = 0;
List<File> list = fileChooser.showOpenMultipleDialog(label.getScene().getWindow());
if (list != null) {
for (File f : list) {
data.add( new ImgInfo(1 + data.size() + "", f));
i++;
}
System.out.println("Total Files added: " + i);
}
}
I assume that you are working on an image processing project where you don't actually need to view all the input images. I would suggest the following approach if all the files are in a single folder:
public void filesInFolder(File folder) {
for (File file : folder.listFiles()) {
if (fileEntry.isFile()) {
// Open File Here
}
}
}
fileChooser.showOpenMultipleDialog() does not hang and is not too slow when I use it.
Here is a sample application I used. Choosing a few thousand files and displaying their names in a ListView took less than a second. Test environment: JavaFX 8u20, Windows 7, 6 year old PC.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import java.io.File;
import java.util.List;
public class SelectedFileInfoViewer extends Application {
#Override public void start(final Stage stage) throws Exception {
final ListView<File> chosenFilesView = new ListView<>();
final Button chooseFilesButton = new Button("Choose Files");
chooseFilesButton.setOnAction(event -> {
List<File> files = new FileChooser().showOpenMultipleDialog(stage);
if (files != null) {
chosenFilesView.getItems().setAll(files);
}
});
final Label numFilesChosen = new Label();
numFilesChosen.textProperty().bind(
Bindings.concat(
"Number of Files: ",
Bindings.size(
chosenFilesView.getItems()
).asString()
)
);
VBox layout = new VBox(
10,
chooseFilesButton,
chosenFilesView,
numFilesChosen
);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) { launch(args); }
}
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 12 months ago.
Improve this question
Here I have written the following code. I can't run the program, and the error mentioned below keeps appearing. I tried many probable solutions but in vain.
import java.beans.EventHandler;
import java.io.File;
import javafx.application.Application;
import javafx.collections.*;
import javafx.event.ActionEvent;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.canvas.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.text.*;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class FileChooser_1 extends Application {
// launch the application
public void start(Stage stage) {
try {
// title
stage.setTitle("Filechooser");
//File chooser create
FileChooser file_chooser = new FileChooser();
// define Label
Label lab = new Label("select file");
// Button new
Button b = new Button("open dialog");
// create Event Handler
EventHandler<ActionEvent> eve
= new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
// get file
File file = file_chooser.showOpenDialog(stage);
if (file != null) {
lab.setText(file.getAbsolutePath()
+ " selected");
}
}
};
b.setOnAction(event);
// create Button
Button b1 = new Button("save");
// Event Handler
EventHandler<ActionEvent> eve1
= new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
// get file
File file = file_chooser.showSaveDialog(stage);
if (file != null) {
lab.setText(file.getAbsolutePath()
+ " selected");
}
}
};
b1.setOnAction(eve1);
// VBox
VBox vbox = new VBox(30, label, button, button1);
// set Alignment
vbox.setAlignment(Pos.CENTER);
// create scene
Scene scene = new Scene(vbox, 800, 500);
// scene
stage.setScene(scene);
stage.show();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
// Main Method
public static void main(String args[]) {
launch(args);
}
}
I am getting the following error:
Error: Unable to initialize main class FileChooser_1
Caused by: java.lang.NoClassDefFoundError: Stage
It will be really nice if you can help me with this.
With some attention to detail, your code works. In particular, especially when just starting out,
Use Java naming conventions.
Use meaningful names; for example, instead of Button b, try Button openButton.
When using detailed comments, keep them up to date; note how meaningful names make some comments superfluous.
Use constants for consistency.
As #jewelsea notes, your program imports java.beans.EventHandler; it should import javafx.event.EventHandler.
As #jewelsea notes, "Only import classes you use."
Let the layout do the work.
I can't explain the error in your question; I see errors related to the incorrect import for EventHandler. If you're using an IDE, it may be reporting errors from a different compilation unit. When in doubt, do a clean build, move the code to a new file, or move to a different development environment, e.g. the command line. As a concrete example, this simple VersionCheck illustrates both a minimal ant script, invoked as ant run, and a simple shell script, invoked as .run.sh:
#!/bin/sh
JFX="--module-path /Users/Shared/javafx-sdk-17.0.1/lib --add-modules ALL-MODULE-PATH"
javac $JFX *.java && java $JFX VersionCheck
import javafx.event.EventHandler;
import java.io.File;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class FileChooser1 extends Application {
private static final int PADDING = 32;
#Override
public void start(Stage stage) {
// title
stage.setTitle("FileChooser");
//File chooser create
FileChooser fileChooser = new FileChooser();
// define Label
Label label = new Label("Select a file to open or save:");
// open Button
Button openButton = new Button("Open");
// open Event Handler
EventHandler<ActionEvent> openHandler = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
// get file name
File file = fileChooser.showOpenDialog(stage);
if (file != null) {
label.setText(file.getName() + " selected");
}
}
};
openButton.setOnAction(openHandler);
// create save button
Button saveButton = new Button("Save");
// save Event Handler
EventHandler<ActionEvent> saveHandler = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
// save file
File file = fileChooser.showSaveDialog(stage);
if (file != null) {
label.setText(file.getName() + " selected");
}
}
};
saveButton.setOnAction(saveHandler);
// VBox
VBox vBox = new VBox(PADDING, label, openButton, saveButton);
// set Alignment
vBox.setAlignment(Pos.CENTER);
vBox.setPadding(new Insets(PADDING));
// create scene
Scene scene = new Scene(vBox);
// scene
stage.setScene(scene);
stage.show();
}
public static void main(String args[]) {
launch(args);
}
}
I'm new to JavaFX. I try to program a simple GUI but I face those problem whom might be related.
I set files with a File Chooser and want to do pretty basic operations:
save the last folder used
write the name of the selected file in the VBox
Here's my code (which compiles):
import java.io.File;
import java.io.IOException;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Main extends Application {
public static Stage primaryStageS;
public static Scene mainScene;
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene((new Test(primaryStage).getScene()));
primaryStageS = primaryStage;
primaryStage.setTitle("Parcel Manager Main Page");
primaryStage.initStyle(StageStyle.DECORATED);
VBox main = new VBox(new Label("Test program"));
mainScene = new Scene(main, 800, 600);
primaryStage.setScene((new Test(primaryStage)).getScene());
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
public class Object1 {
String name;
public Object1(File f) throws IOException {
name = f.getName();
}
public String getName() {
return name;
}
}
public class Test {
Object1 collec;
String collecName;
File lastFolder;
Pane rootGroup;
public Test(Stage stage) {
setButtons(stage);
}
public void setButtons(Stage stageGoal) {
VBox vbox = new VBox();
Button b = getButton(stageGoal);
vbox.getChildren().addAll(b, new Label(getCollecName() == null ? "no name" : collecName));
final GridPane inputGridPane = new GridPane();
GridPane.setConstraints(vbox, 0, 0);
inputGridPane.getChildren().addAll(vbox);
rootGroup = new VBox(12);
rootGroup.getChildren().addAll(inputGridPane);
rootGroup.setPadding(new Insets(12, 12, 12, 12));
}
public Button getButton(Stage stage) {
FileChooser fileChooserParcel = new FileChooser();
fileChooserParcel.setInitialDirectory(getLastFolder());
Button button = new Button("Select a File");
button.setOnAction(e -> {
File f = fileChooserParcel.showOpenDialog(stage);
if (f != null) {
try {
collec = new Object1(f);
} catch (IOException e1) {
e1.printStackTrace();
}
setLastFolder(f.getParentFile());
setCollecName(collec);
setButtons(stage); // tried to reload every buttons - doesn't work
stage.setWidth(stage.getWidth() + 0.0001); // found this dirty hack but doesn't work
}
});
return button;
}
public void setCollecName(Object1 o1) {
collecName = o1.getName();
}
public String getCollecName() {
return collecName;
}
public File getLastFolder() {
return lastFolder;
}
public void setLastFolder(File folder) {
System.out.println("set last folder: " + folder);
lastFolder = folder;
}
private Scene getScene() {
return new Scene(rootGroup, 800, 600);
}
}
}
I cannot refresh the Nodes, either to set a current Initial Directory or display the collecName on the VBox. I tried to regenerate them with reloading of objects or resizing the window, but nothing works. When I print the variables on console, I see that they changes. But haven't found any refresh method for any of my objects.
I bet it's a design program issue, but I have been moving things around for the last week and doesn't know how to fix this.
Thanks !
You are only setting the initial directory once. I guess you want to set it every time you click the button. So move that line of code to inside the handler.
Compare the below getButton() method with yours.
public Button getButton(Stage stage) {
FileChooser fileChooserParcel = new FileChooser();
Button button = new Button("Select a File");
button.setOnAction(e -> {
fileChooserParcel.setInitialDirectory(getLastFolder()); // CHANGE HERE.
File f = fileChooserParcel.showOpenDialog(stage);
if (f != null) {
try {
collec = new Object1(f);
} catch (IOException e1) {
e1.printStackTrace();
}
setLastFolder(f.getParentFile());
setCollecName(collec);
setButtons(stage); // tried to reload every buttons - doesn't work
stage.setWidth(stage.getWidth() + 0.0001); // found this dirty hack but doesn't work
}
});
return button;
}
While working with a TreeTableView I realized that when you scroll down the table and double click the last expand/collapse arrow, all items disappear. However, when you scroll again all items reappear. Of course, this happens when you have enough items so the vertical ScrollBar is active.
Does anyone experience this issue before? Is this a known issue?
Simple example:
import java.util.Arrays;
import java.util.List;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.layout.StackPane;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
public class App extends Application {
#Override
public void start(Stage stage) {
TreeTableView<List<String>> table = new TreeTableView<>();
table.setMaxHeight(250);
TreeTableColumn<List<String>, String> colCity = new TreeTableColumn<>("City");
TreeTableColumn<List<String>, String> colCountry = new TreeTableColumn<>("Country");
colCity.setCellValueFactory(c -> new SimpleStringProperty(c.getValue().getValue().get(0)));
colCountry.setCellValueFactory(c -> new SimpleStringProperty(c.getValue().getValue().get(1)));
table.getColumns().setAll(colCity, colCountry);
TreeItem<List<String>> root = new TreeItem<>(Arrays.asList("Root", ""));
root.setExpanded(true);
for (int i = 0; i < 10; i++) {
TreeItem<List<String>> item = new TreeItem<>(List.of("London", "UK"));
item.getChildren().add(new TreeItem<>(List.of("New York", "US")));
item.setExpanded(true);
root.getChildren().add(item);
}
table.setRoot(root);
Scene scene = new Scene(new StackPane(table));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
I have tested this code on:
Hardware/OS: MacBookPro16,1/macOS Catalina 10.15.6
Java: 11.0.2, 14.0.1
JavaFX: 11.0.2, 12.0.2, 13.0.2, 14.0.2.1, 15
Since JavaFX 16 this issue is solved. However, here's a hacky solution for older JavaFX versions.
It works by adding a listener to the expandedItemCountProperty() to force the TreeTableView to refresh when needed:
table.expandedItemCountProperty().addListener(e -> {
VirtualFlow<?> virtualFlow = (VirtualFlow<?>) table.lookup(".virtual-flow");
if (virtualFlow != null && virtualFlow.getFirstVisibleCell() != null) {
int firstVisibleIndex = virtualFlow.getFirstVisibleCell().getIndex();
int visibleCells = virtualFlow.getLastVisibleCell().getIndex() - firstVisibleIndex;
if (firstVisibleIndex > visibleCells) {
table.refresh();
}
}
});
Note: tested using the example in the question.
I have a file browser component in my app (TableView), and I load the icons of files via FileSystemView.getFileSystemView().getSystemIcon(). Now, this is quite slow as I also need to convert the icon to BufferedImage, and that to JavaFX Image. So I needed to push this all to background thread(s). I created an IconLoadingTask, that loads a single icon - and during updateItem() of TableView I push these IconLoadingTasks to ExecutorService. It works, but could be improved.
The problem I have is that if the folder has lots of icons, and the user quickly drags the scrollbar, lots of "redundant" icons are loaded, stalling the thread(s) and resulting in often not seeing the icons that matter at the time: the ones that are currently displayed in the TableView.
Anyone have ideas how to solve this issue? I was thinking of accessing the vertical scrollbar of TableView and listening to it (and perhaps only update after scroll has been released), but I'm not sure how to even access the scrollbar... and maybe there's a simpler solution that escapes me.
EDIT:
Well, well. I created a minimal, complete and verifiable example out of my Kotlin code into Java code, and I cannot reproduce the "effect" anymore. It appears to work now as I intended it to in the first place. So it seems I just have to figure what "extra" I am doing in my main application's code. Anyways, here's the apparently working sample code.
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.filechooser.FileSystemView;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class IconLoadTest extends Application {
public static class FileEntry {
public Path path;
private Image icon;
public FileEntry(Path path) {
this.path = path;
}
synchronized void setIcon(Image icon) {
this.icon = icon;
}
synchronized Image getIcon() {
return icon;
}
public void setPath(Path path) {
this.path = path;
}
public Path getPath() {
return path;
}
}
class MyTableCell extends TableCell<FileEntry, Path> {
#Override
protected void updateItem(Path item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText("");
setGraphic(null);
return;
}
setText(item.getFileName().toString());
Image icon = dataMap.get(item).getIcon();
if (icon == null) {
setGraphic(null);
executor.execute(new IconLoadingTask(item));
} else {
setGraphic(new ImageView(icon));
}
}
}
class IconLoadingTask extends Task<Void> {
private Path path;
IconLoadingTask(Path path) {
this.path = path;
}
#Override
protected Void call() {
FileEntry entry = dataMap.get(path);
if (entry.icon != null) {
return null;
}
entry.setIcon(getIcon(path.toFile()));
// Refresh currently visible items
Platform.runLater(() -> table.refresh());
return null;
}
}
private TableView<FileEntry> table = new TableView<>();
// Table data
private HashMap<Path, FileEntry> dataMap = new HashMap<>();
private List<FileEntry> data = FXCollections.observableArrayList();
private ExecutorService executor = Executors.newFixedThreadPool(1);
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
root.getChildren().add(table);
TableColumn<FileEntry, Path> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(new PropertyValueFactory<>("path"));
table.getColumns().add(nameCol);
nameCol.setCellFactory(tableColumn -> new MyTableCell());
// Sort so that dirs come first
nameCol.setComparator((o1, o2) -> {
if (Files.isDirectory(o1) && !Files.isDirectory(o2)) {
return -1;
} else if (!Files.isDirectory(o1) && Files.isDirectory(o2)) {
return 1;
} else {
return o1.toString().toLowerCase().compareTo(o2.toString().toLowerCase());
}
});
// Set to a directory with lots of files (e.g. System32 on Windows)
String directory = "C:\\Windows\\System32\\";
// Load files from directory, and create entries for table
Path dir = Paths.get(directory);
List<Path> files = listContents(dir);
for (Path p : files) {
FileEntry entry = new FileEntry(p);
data.add(entry);
dataMap.put(p, entry);
}
table.setItems((ObservableList<FileEntry>) data);
// Sort
table.getSortOrder().add(table.getColumns().get(0));
table.sort();
// Display the app
Scene scene = new Scene(root, 600, 480);
primaryStage.setTitle("Icon Background Loading");
primaryStage.setScene(scene);
primaryStage.show();
}
// Gets directory contents
private static List<Path> listContents(Path directory) {
ArrayList<Path> paths = new ArrayList<>();
try {
Files.newDirectoryStream(directory).forEach(paths::add);
} catch (IOException ex) {
ex.printStackTrace();
}
return paths;
}
// Gets a system icon for a file
private static Image getIcon(File file) {
Icon ico = FileSystemView.getFileSystemView().getSystemIcon(file);
java.awt.Image awtImage = ((ImageIcon) ico).getImage();
BufferedImage bImg;
if (awtImage instanceof BufferedImage) {
bImg = (BufferedImage) awtImage;
} else {
bImg = new BufferedImage(
awtImage.getWidth(null),
awtImage.getHeight(null),
BufferedImage.TYPE_INT_ARGB
);
Graphics graphics = bImg.createGraphics();
graphics.drawImage(awtImage, 0, 0, null);
graphics.dispose();
}
return SwingFXUtils.toFXImage(bImg, null);
}
public static void main(String[] args) {
Application.launch(IconLoadTest.class, args);
}
}
I am using JavaFX 8 and specifically the TextArea control. In that control I can enter free form text including "tab" characters. When I enter a tab, the data is spaced in units of 8 characters. For example. In the following, the ! character is where I enter a tab:
1234567890123456789012345678901234567890
! Data here
ABC! Data here
!! Data Here
My puzzle is how to change the tab spacing/sizing for the visual so that instead of the tab size being 8 characters it will only be 4 characters.
To further illustrate, here is an actual screen shot showing tabs in my text area:
I want to leave the data as containing tab characters and not replace tabs with spaces.
This Stack Exchange question does not apply as it talks exclusively about changing tabs to space:
JavaFX TextArea: how to set tabulation width
I decided to grunge through the source code of JavaFX to see if I could find an answer and, although I am not an expert in examining such a large amount of code, I seem to have found that the answer is that the tab size is hard-coded to be 8 characters!!
I found the source file called:
com.sun.javafx.text.PrismTextLayout.java
which has a method called getTabAdvance which returns a fixed value of "8". See the following:
This is most disappointing to me but it is what it is.
After the implementation of JDK-8130738 in JavaFX 14, you can now change the advance of a tab character to any multiple of 'spaceAdvance'. Text and TextFlow now have a tabSize property and the CSS supports -fx-tab-size
Since TextAreaSkin implements the TextArea using Text nodes, you can change the tab size of the TextArea with CSS.
Example:
package example.stackoverflow;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class TextAreaTabs extends Application {
private Scene scene;
private File cssFile;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
var slider = new Slider(1, 50, 8);
slider.valueProperty().addListener((obs, old, newValue) -> {
try {
updateTabSize(newValue.intValue());
} catch (IOException ex) {
System.err.println("Can't write CSS file.");
}
});
var ta = new TextArea("This is a test\n\tafter a tab\n\t1\t2\n");
ta.setFont(Font.font("Monospaced"));
var vbox = new VBox(8,new HBox(8,new Label("Tab size:"),slider),ta);
vbox.setPadding(new Insets(8));
scene = new Scene(vbox);
primaryStage.setScene(scene);
primaryStage.setTitle("TextArea Tab Experiment");
primaryStage.show();
}
private void updateTabSize(int spaces) throws IOException {
File oldFile = cssFile;
cssFile = File.createTempFile("textareatabs", ".css");
cssFile.deleteOnExit();
Files.writeString(cssFile.toPath(), """
Text {
-fx-tab-size: %d;
}
""".formatted(spaces), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
String confStyleSheet = cssFile.toURI().toString();
scene.getStylesheets().setAll(confStyleSheet);
if (oldFile != null) {
oldFile.delete();
}
}
}
Here's a version of Scotts Proggy adapted to use the new JavaFX 17 Data-URI's:
P.S. I use the Azul Zulu openJDK 17 JavaFX Runtime Bundle
You can get that here:
https://www.azul.com/downloads/?package=jdk#download-openjdk
package example.stackoverflow;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.util.Base64;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class TextAreaTabs extends Application {
private static final String CSS_TABSIZE_N = "Text {-fx-tab-size: %d}";
private static final char TAB = '\t';
private static final char NEWLINE = '\n';
private static final String TABBED_TEXT = "This is a test" + NEWLINE + TAB + "after a tab" + NEWLINE + TAB + "1" + TAB + "2";
public static void main(final String[] args) {
launch(args);
}
private Scene scene;
#Override
public void start(final Stage primaryStage) {
final var sliderLabel = new Label("Tab size:");
final var slider = new Slider(1, 50, 8);
; slider.valueProperty().addListener((obs, old, newValue) -> updateTabSize(newValue.intValue()));
final var textArea = new TextArea(TABBED_TEXT);
; textArea.setFont(Font.font("Monospaced"));
final var vBox = new VBox(8, new HBox(8, sliderLabel, slider), textArea);
; vBox.setPadding(new Insets(8));
scene = new Scene(vBox);
primaryStage.setScene(scene);
primaryStage.setTitle("TextArea Tab Experiment");
primaryStage.show();
}
private void updateTabSize(final int tabSize) {
final var styleText = CSS_TABSIZE_N.formatted(tabSize);
final var styleBase64 = Base64.getUrlEncoder().encodeToString(styleText.getBytes(UTF_8));
final var url = "data:text/css;charset=UTF-8;base64," + styleBase64;
System.out.println(styleText + TAB + " -> " + url);
scene.getStylesheets().setAll(url);
}
}