This program is suppose to store the values in the program to a when write is pressed. Then when read is pressed it will read and display the values. The results are supposed to be displayed in a text area. However, the buttons do not show up when I run the program. When I run it java begins to run on my computer but nothing comes up.
package program;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.Date;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class program extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws ClassNotFoundException, IOException {
// Text area
TextArea textArea = new TextArea();
textArea.setStyle("-fx-background-color: lightgrey; -fx-text-fill: blue; -fx-control-inner-background: grey");
textArea.setPadding(new Insets(15, 15, 15, 15));
Button write = new Button("Write");
write.setOnAction(e -> {
// Create an output stream for file
try(ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("Exercise17_05.dat", true))) {
int[] numbers = {1, 2, 3, 4, 5};
// Write to file
// 1. Write double
output.writeDouble(5.5);
// 2. Write int array object
output.writeObject(numbers);
// 3. Write date object
output.writeObject(new java.util.Date());
// 4. Write utf string
output.writeUTF("Exercise17_05.dat");
} catch(IOException exception) {
System.exit(0);
}
});
Button read = new Button("Read");
read.setOnAction(e -> {
//Create an input stream for file
try(ObjectInputStream input = new ObjectInputStream(new FileInputStream("Exercise17_05.dat"));){
// Read from file
// 1. Read double
double doubleValue = input.readDouble();
textArea.appendText("Double value: " + doubleValue);
// 2. Read int array object
int[] newNumbers = (int[]) (input.readObject());
textArea.appendText("Integers: " + Arrays.toString(newNumbers));
// 3. Read date object
Date date = (java.util.Date) (input.readObject());
textArea.appendText("DateTime: " + date);
// 4. Read utf string
String fileName = input.readUTF();
textArea.appendText("File name: " + fileName);
} catch(IOException | ClassNotFoundException exception) {
System.exit(0);
}});
HBox hButtons = new HBox(read, write);
VBox vProgram = new VBox(8);
vProgram.getChildren().addAll(hButtons, textArea);
primaryStage.setScene(new Scene(vProgram));
primaryStage.setTitle("Write and Read");
primaryStage.show();
}
}
add these two lines of code at the end of your code, to make your gui visible
primaryStage.setScene(new Scene(vProgram, 300, 250));
primaryStage.show();
Related
here is my first class client
package hwch33;
import java.net.*;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.io.*;
public class Client extends Application {
// IO streams
DataOutputStream toServer = null;
DataInputStream fromServer = null;
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Panel p to hold the label and text field
BorderPane paneForTextField = new BorderPane();
paneForTextField.setPadding(new Insets(5, 5, 5, 5));
paneForTextField.setStyle("-fx-border-color: green");
paneForTextField.setLeft(new Label("Enter a radius: "));
TextField tf = new TextField();
tf.setAlignment(Pos.BOTTOM_RIGHT);
paneForTextField.setCenter(tf);
BorderPane mainPane = new BorderPane();
// Text area to display contents
TextArea ta = new TextArea();
mainPane.setCenter(new ScrollPane(ta));
mainPane.setTop(paneForTextField);
// Create a scene and place it in the stage
Scene scene = new Scene(mainPane, 450, 200);
primaryStage.setTitle("Client"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
tf.setOnAction(e -> {
try {
// Get the radius from the text field
double radius = Double.parseDouble(tf.getText().trim());
// Send the radius to the server
toServer.writeDouble(radius);
toServer.flush();
// Get area from the server
double area = fromServer.readDouble();
// Display to the text area
ta.appendText("Radius is " + radius + "\n");
ta.appendText("Area received from the server is "
+ area + '\n');
}
catch (IOException ex) {
System.err.println(ex);
}
});
try {
// Create a socket to connect to the server
Socket socket = new Socket("localhost", 8000);
//Socket socket = new Socket("130.254.204.36", 8000);
//Socket socket = new Socket("drake.Armstrong.edu", 8000);
// Create an input stream to receive data from the server
fromServer = new DataInputStream(socket.getInputStream());
// Create an output stream to send data to the server
toServer = new DataOutputStream(socket.getOutputStream());
}
catch (IOException ex) {
ta.appendText(ex.toString() + '\n');
}
}
}
here is my second class server
package hwch33;
import java.io.*;
import java.net.*;
import java.util.Date;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
public class Server extends Application {
/**
*
* #param primaryStage
*/
#Override
public void start(Stage primaryStage) {
// Text area for displaying contents
TextArea ta = new TextArea();
// Create a scene and place it in the stage
Scene scene = new Scene(new ScrollPane(ta), 450, 200);
primaryStage.setTitle("Server"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
new Thread(() -> {
try {
// Create a server socket
ServerSocket serverSocket = new ServerSocket(8000);
Platform.runLater(() ->
ta.appendText("Server started at " + new Date() + '\n'));
Socket socket = serverSocket.accept();
DataInputStream inputFromClient = new DataInputStream(
socket.getInputStream());
DataOutputStream outputToClient = new DataOutputStream(
socket.getOutputStream());
while (true) {
double radius = inputFromClient.readDouble();
double area = radius * radius * Math.PI;
outputToClient.writeDouble(area);
Platform.runLater(() -> {
ta.appendText("Radius received from client: "
+ radius + '\n');
ta.appendText("Area is: " + area + '\n');
});
}
}
catch(IOException ex) {
ex.printStackTrace();
}
}).start();
}
}
Here is where i need to add the code to make it all work
/*
* To change this license header, choose License Headers in Project
Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package hwch33;
/**
*
* #author
*/
public class HWCH33 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
}
}
Not sure how to construct a main from here.
Ive been trying to form one but cannot get it right. I either get static error or it just doesnt work at all.
Any help is appreciated. Did not include any of my previous attempts because they are useless and I got rid of them all.
If the error is that a non-static variable is not compatible with a static method or something along those lines, just omit the word "static" from public static void main(String[] args){}.
I'm currently creating a program where the user gives a text as input, and then gets displayed the same text with the Code 128 font to see his input as a barcode.
I already installed and located Code 128 and Code 39 under /usr/share/fonts/truetype/
Both fonts should be installed correctly because both work in Libre Office Writer. However, only Code 39 is displayed correctly in my JavaFx Application.
That's my code:
package sample;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.stage.Stage;
public class CreateBarcodeStage extends Stage {
VBox vbox;
TextField textFieldInput;
TextFlow textFlowOutput;
public CreateBarcodeStage() {
createUI();
this.setTitle("Create Barcode");
this.setScene(new Scene(vbox));
}
private void createUI() {
vbox = new VBox(10);
textFieldInput = new TextField();
textFieldInput.textProperty().addListener((ObservableValue<? extends String> observableValue, String s, String t1) -> {
String inputText = textFieldInput.getText();
textFlowOutput.getChildren().clear();
Text textReadable = new Text();
textReadable.setFont(Font.font("Verdana", 20));
textReadable.setText(inputText + "\n\n");
Text textBarcode = new Text();
textBarcode.setFont(Font.font("Code 128", 40));
textBarcode.setText(inputText);
textFlowOutput.getChildren().addAll(textReadable, textBarcode);
});
textFlowOutput = new TextFlow();
textFlowOutput.setPadding(new Insets(15));
textFlowOutput.setPrefWidth(200);
textFlowOutput.setPrefHeight(150);
vbox.getChildren().addAll(textFieldInput, textFlowOutput);
}
}
If I replace "Code 128" with "Code 39" everthing works fine.
This is the output with Code 39:
Code 39 output
And here is the output with Code 128:
Code 128 output
I don't know why Code 128 isn't displayed correctly.
EDIT:
Ok, so now I tried to add an asterix before and after the Code 39 text and in this case everything works. I tested it with a barcode scanner app on my smartphone and the result was right.
For Code 128 I enhanced my code with a checksum maker which I found on github:
github Code 128 barcode generator
Now my code looks like this:
package sample;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.stage.Stage;
public class CreateBarcodeStage extends Stage {
VBox vbox;
TextField textFieldInput;
TextFlow textFlowOutput;
public CreateBarcodeStage() {
createUI();
this.setTitle("Create Barcode");
this.setScene(new Scene(vbox));
}
private void createUI() {
vbox = new VBox(10);
textFieldInput = new TextField();
textFieldInput.textProperty().addListener((ObservableValue<? extends String> observableValue, String s, String t1) -> {
String inputText = textFieldInput.getText();
textFlowOutput.getChildren().clear();
Text textReadable = new Text();
textReadable.setFont(Font.font("Verdana", 20));
textReadable.setText(inputText + "\n\n");
Text textBarcode = new Text();
textBarcode.setFont(Font.font("Code 128", 40));
textBarcode.setText(inputText);
textFlowOutput.getChildren().addAll(textReadable, textBarcode);
});
textFlowOutput = new TextFlow();
textFlowOutput.setPadding(new Insets(15));
textFlowOutput.setPrefWidth(200);
textFlowOutput.setPrefHeight(150);
vbox.getChildren().addAll(textFieldInput, textFlowOutput);
}
private String createCode128(String text) {
return (char) 136 + text + checksum(text) + (char) 138;
}
char checksum(String text) {
int result = 104; // Code 128B start code
for (int i = 0; i < text.length(); i++) {
result += ((int) text.charAt(i) - 32) * (i + 1);
}
return (char) (result % 103 + 32); // Return the character value of the checksum.
}
}
However, it still doesn't work:
Code 128 with start/stop symbol and checksum
While the output may look fine using the Code 39 font, it isn't. It will not scan and is not recognizable as a Code 39 barcode. This is what the word "TEXT" looks like in Code 39:
And this is what "TEXT" looks like with Code 128:
It looks like, with Code 39, you are missing the start and stop characters because what you are displaying in the Code 39 example is actually a subset of the bars, like so:
I suspect that with Code 128, you might not be supplying the start, stop and checksum characters, and the render is failing because of it.
This question already has answers here:
Reading a plain text file in Java
(31 answers)
Closed 5 years ago.
I have a program called "AddUser" that allows the user to type in their username and password, which will add this info to user.txt file. I also have a program called "Login" that takes the information the user inputs, username and password, and verifies the input against the user.txt file.
However, I cannot figure out how to validate the input for the Login program. I have found several other posts here, but not from validating from a text file. Any help or guidance would be GREATLY appreciated.
Program Add User
import javax.swing.JOptionPane;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.geometry.HPos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import java.io.*;
public class AddUser extends Application {
private TextField tfUsername = new TextField();
private TextField tfPassword = new TextField();
private Button btAddUser = new Button("Add User");
private Button btClear = new Button("Clear");
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create UI
GridPane gridPane = new GridPane();
gridPane.setHgap(5);
gridPane.setVgap(5);
gridPane.add(new Label("Username:"), 0, 0);
gridPane.add(tfUsername, 1, 0);
gridPane.add(new Label("Password:"), 0, 1);
gridPane.add(tfPassword, 1, 1);
gridPane.add(btAddUser, 1, 3);
gridPane.add(btClear, 1, 3);
// Set properties for UI
gridPane.setAlignment(Pos.CENTER);
tfUsername.setAlignment(Pos.BOTTOM_RIGHT);
tfPassword.setAlignment(Pos.BOTTOM_RIGHT);
GridPane.setHalignment(btAddUser, HPos.LEFT);
GridPane.setHalignment(btClear, HPos.RIGHT);
// Process events
btAddUser.setOnAction(e -> writeNewUser());
btClear.setOnAction(e -> {
tfUsername.clear();
tfPassword.clear();
});
// Create a scene and place it in the stage
Scene scene = new Scene(gridPane, 300, 150);
primaryStage.setTitle("Add User"); // Set title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
public void writeNewUser() {
try (BufferedWriter bw = new BufferedWriter(new FileWriter("users.txt", true))) {
bw.write(tfUsername.getText());
bw.newLine();
bw.write(tfPassword.getText());
bw.newLine();
}
catch (IOException e){
e.printStackTrace();
}
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
Program Login
import javax.swing.JOptionPane;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.geometry.HPos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import java.io.*;
public class Login extends Application {
private TextField tfUsername = new TextField();
private TextField tfPassword = new TextField();
private Button btAddUser = new Button("Login");
private Button btClear = new Button("Clear");
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create UI
GridPane gridPane = new GridPane();
gridPane.setHgap(5);
gridPane.setVgap(5);
gridPane.add(new Label("Username:"), 0, 0);
gridPane.add(tfUsername, 1, 0);
gridPane.add(new Label("Password:"), 0, 1);
gridPane.add(tfPassword, 1, 1);
gridPane.add(btAddUser, 1, 3);
gridPane.add(btClear, 1, 3);
// Set properties for UI
gridPane.setAlignment(Pos.CENTER);
tfUsername.setAlignment(Pos.BOTTOM_RIGHT);
tfPassword.setAlignment(Pos.BOTTOM_RIGHT);
GridPane.setHalignment(btAddUser, HPos.LEFT);
GridPane.setHalignment(btClear, HPos.RIGHT);
// Process events
btClear.setOnAction(e -> {
tfUsername.clear();
tfPassword.clear();
});
// Create a scene and place it in the stage
Scene scene = new Scene(gridPane, 300, 150);
primaryStage.setTitle("Login"); // Set title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
Consider this Example (Explanation in Comments):
// create boolean variable for final decision
boolean grantAccess = false;
// get the user name and password when user press on login button
// you already know how to use action listener
// (i.e wrap the following code with action listener block of login button)
String userName = tfUsername.getText();
String password = tfPassword.getText();
File f = new File("users.txt");
try {
Scanner read = new Scanner(f);
int noOfLines=0; // count how many lines in the file
while(read.hasNextLine()){
noOfLines++;
}
//loop through every line in the file and check against the user name & password (as I noticed you saved inputs in pairs of lines)
for(int i=0; i<noOfLines; i++){
if(read.nextLine().equals(userName)){ // if the same user name
i++;
if(read.nextLine().equals(password)){ // check password
grantAccess=true; // if also same, change boolean to true
break; // and break the for-loop
}
}
}
if(grantAccess){
// let the user continue
// and do other stuff, for example: move to next window ..etc
}
else{
// return Alert message to notify the deny
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
I am currently working on an assignment in which I need to make an application that has two buttons: read/write, and a textArea with a gray background and blue text, that will display the read content of a file that is written to on button press. I have to save an array of 5 numbers, the date, and a double (2.5).
I have gotten to the point of getting everything to work except for the appending of the text to the textArea... no matter where I seem to pass the value it gives me an error or tells me that it doesn't exist as a variable!
My question is: How do I get the values that I have read from the file to update the text in the textArea instead of just console?
Here is my first file which will create the application and populate the scene. The buttons and text area are all the correct color.
package chapter17;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import java.io.IOException;
import javafx.scene.layout.Region;
import javafx.scene.control.TextArea;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
public class Exercise17_5 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
HBox hBox = new HBox();
hBox.setSpacing(10);
hBox.setAlignment(Pos.CENTER);
Button write = new Button("Write");
Button read = new Button("Read");
TextArea readText = new TextArea("This is text testing...");
readText.setPrefColumnCount(15);
readText.setPrefRowCount(5);
readText.setWrapText(true);
readText.setStyle("-fx-text-fill: blue");
//readText.setStyle("-fx-background-color: grey");
readText.setFont(Font.font("Times", 20));
hBox.getChildren().addAll(write, read, readText);
ReadWrite readWriting = new ReadWrite();
write.setOnAction(e -> {
try {
readWriting.write();
}
catch (IOException excepiton) {
excepiton.printStackTrace();
}});
read.setOnAction(e -> {
try {
readWriting.read();
}
catch (IOException exception){
exception.printStackTrace();
}
});
Scene scene = new Scene(hBox,550,550);
primaryStage.setScene(scene);
primaryStage.setTitle("Exercise 17.5");
primaryStage.show();
Region region = (Region) readText.lookup(".content");
region.setStyle("-fx-background-color: gray");
}
}
Here is the second file that will contain the read and write methods, and the variables that store what is read. I can get them to print out to console as demonstrated below. They need to be appended to my already existing textArea readText.
package chapter17;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
public class ReadWrite extends Exercise17_5 {
int[] numbers = {1, 2, 3, 4, 5};
public ReadWrite(){
};
public void write() throws IOException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("Exercise17_5.dat"))){
output.writeObject(numbers);
output.writeObject(new Date());
output.writeDouble(2.5);
}
catch (IOException exception) {
exception.printStackTrace();
}
}
public void read() throws IOException {
try{
FileInputStream inputFile = new FileInputStream("Exercise17_5.dat");
ObjectInputStream input = new ObjectInputStream(inputFile);
int[] numbers = (int[])(input.readObject());
java.util.Date date = (java.util.Date)(input.readObject());
double decimal = (double)(input.readDouble());
for (int i = 0; i < numbers.length; i++){
System.out.print(numbers[i] + " ");
}
System.out.println();
System.out.println(decimal);
System.out.println(date);
input.close();
}
catch (IOException | ClassNotFoundException exception2){
exception2.printStackTrace();
}
}
}
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);
}
}