JavaFX TextArea appendText works in initialize but not elsewhere - javafx

Simple enough problem but it's been driving me crazy.
In my program I have a TextArea, defined as:
<TextArea fx:id="output" editable="false" prefHeight="300.0" prefWidth="200.0" text="Output" GridPane.columnSpan="2" GridPane.rowIndex="4" />
#FXML private TextArea output;
...
public void initialize(URL url, ResourceBundle rb) {
output.setText("Test"); //Test appears correctly in output
...
}
#FXML
public void download() {
String outputTemplate = templateField.getText();
String url = urlField.getText();
System.out.println("Downloading from " + url);
try {
Process down = Runtime.getRuntime().exec("youtube-dl -o \"" + outputTemplate + "\" " + url);
BufferedReader reader = new BufferedReader(new InputStreamReader(down.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); //Prints as expected
output.appendText(line + "\n"); //Has no effect
}
} catch (IOException e) {
e.printStackTrace();
}
}
Any ideas on how to get the text to appear would be great, I've done this before on different programs, just for some reason, this time it's being cantankerous
EDIT: Upon further tinkering, it actually will print out the results, but only after the Process ends and it exits the loop.

The text shown in the UI changes on a layout pulse. Layout pulses are done on the JavaFX application thread. Event handlers, like your download method run on the same thread effectively preventing it from doing any layouting or processing and other events until it completes. This is why you shouldn't block this thread with longrunning tasks, but execute them on a different thread.
Since updates to the UI should be done from the application thread, use Platform.runLater to append the text:
#FXML
public void download() {
String outputTemplate = templateField.getText();
String url = urlField.getText();
Runnable r = () -> {
System.out.println("Downloading from " + url);
try {
Process down = Runtime.getRuntime().exec("youtube-dl -o \"" + outputTemplate + "\" " + url);
BufferedReader reader = new BufferedReader(new InputStreamReader(down.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); //Prints as expected
final String printText = line + "\n";
// append the line on the application thread
Platform.runLater(() -> output.appendText(printText));
}
} catch (IOException e) {
e.printStackTrace();
}
};
// run task on different thread
Thread t = new Thread(r);
t.start();
}

The problem is that you're doing this in the main thread. So stage can not be updated, until the cycle is finished. Try it in new thread:
#FXML
public void download() {
Task<Void> task = new Task<Void>() {
#Override
protected Void call() {
String outputTemplate = templateField.getText();
String url = urlField.getText();
System.out.println("Downloading from " + url);
try {
Process down = Runtime.getRuntime().exec("youtube-dl -o \"" + outputTemplate + "\" " + url);
BufferedReader reader = new BufferedReader(new InputStreamReader(down.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // Prints as expected
output.appendText(line + "\n"); // Has no effect
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
new Thread(task).start();
}

Related

CLICK JAVAFXML BUTTON SCENEBUILDER

#FXML
void handleButtonAction(ActionEvent event) {
buttonOpenFile.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
int result = fileChooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
openFiletxtField.setText(selectedFile.getAbsolutePath());
System.out.println("Selected file: " + selectedFile.getAbsolutePath());
}
}
});
buttonSaveFile.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
File file = new File("Details.txt");
try {
FileOutputStream fOut = new FileOutputStream(file, true);
OutputStreamWriter osw = new OutputStreamWriter(fOut);
osw.write("whatever you need to write");
JOptionPane.showMessageDialog(null, "Saved Successfully..");
osw.flush();
osw.close();
} catch (IOException iOException) {
System.out.println("" + iOException.getMessage());
}
}
});
}
I Have a problem using javafx fxml button click event. Whenever I click the button once, nothing happens. I have to click it the second time for it to work? What could I be doing wrong? I have shared my code above. I am using scene builder I have everything in place apart from this error. everything is working fine apart from this issue. The code load text file from the computer directory and save the data to the loaded file.
#FXML
void handleOpenFileButtonAction(ActionEvent event) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
int result = fileChooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
openFiletxtField.setText(selectedFile.getAbsolutePath());
}
}
#FXML
void handleSaveFileButtonAction(ActionEvent event) {
File file = new File("Details.txt");
try {
FileOutputStream fOut = new FileOutputStream(file, true);
OutputStreamWriter osw = new OutputStreamWriter(fOut);
osw.write(firstNametxtField.getText() + "," + lastNametxtField1.getText() + "," + enrolledCheckBox.isSelected() + "," + addresstxtField.getText() + "," + statesCombobox.getSelectionModel().getSelectedItem().toString() + "\n");
JOptionPane.showMessageDialog(null, "Saved Successfully..");
osw.flush();
osw.close();
} catch (IOException iOException) {
System.out.println("" + iOException.getMessage());
}
}

DownloadFileAsync with webclient issue

I am trying to download file from FTP using Webclient DownloadFileAsync method. i have used below code
private bool DownloadFileFromFtp()
{
try
{
MyWebClient client = new MyWebClient();
Uri ftpurl = new Uri("ftp://MyFtpserver/Filename.pdf");
client.Credentials = new NetworkCredential("Userid", "mypassword");
client.DownloadProgressChanged += Client_DownloadProgressChanged;
client.DownloadDataCompleted += Client_DownloadDataCompleted;
client.DownloadFileAsync(ftpurl, #"D:\RTP\Filename.pdf");
return true;
}
catch (Exception ex)
{
return false;
}
}
private void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
lbldatareceived.Text = bytesIn + "/" + totalBytes;
lblPercentage.Text = percentage+"%";
FileProgress.Attributes.CssStyle.Add("width", Convert.ToString(percentage) + '%');
FileProgress.Attributes.Add("aria-valuenow", Convert.ToString(percentage));
}
private void Client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
throw new NotImplementedException();
}
When I run this code file download gets starts and browser start loading. How can I download files without loading a browser?

Javafx TextArea setText method using text files

Hi I am trying to create a method to be used in the TextArea setText method for javafx.
I am trying to get a method that does this:
public static void setTextArea(String fileName) {
String line;
try {
FileReader fileReader = new FileReader(fileName);
BufferedReader buffer = new BufferedReader(fileReader);
while ((line = buffer.readLine()) != null) {
out.println(line);
}
buffer.close();
} catch //etc etc
but I can't use it in the setText method because it is a void method.
Can anyone help translate this method so it could work in the TextArea setText method?
-Thanks!
You just pring out the lines to System.out I guess. You have to add up the content of the text file by doing something like this
public static void setTextArea(String fileName) {
String line;
String content;
try {
FileReader fileReader = new FileReader(fileName);
BufferedReader buffer = new BufferedReader(fileReader);
while ((line = buffer.readLine()) != null) {
out.println(line);
content += line;
}
buffer.close();
} catch //etc etc
Then you can either return content or call setText(content) from the TextArea class. If it's a big file, then using StringBuilder would probably be a better idea instead of concatenating each line.
You will have to get the data from the file and and set the data to textArea..
TextArea txtArea = new TextArea();
String data = getDataForTextArea(String fileLocation);
txtArea.setText(data);
public String getDataForTextArea(String fileLocation) {
InputStream inputStream = new FileInputStream(fileLocation);
if (inputStream != null) {
int b;
String txtData = "";
try {
while ((b = inputStream.read()) != -1) {
txtData += (char) b;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
inputStream.close();
}
return txtData;
}
Make sure to check for nullpointerException.

If there is data, how is the stream returning zero bytes?

I have a RXTX project that I'm working on. I have it set ups as follows:
public void doConnect(ActionEvent event)
{
String selectedPort = (String)connectTabController.portList.getValue();
System.out.println("Connecting to: " + selectedPort);
selectedPortIdentifier = (CommPortIdentifier)portMap.get(selectedPort);
CommPort commPort = null;
try
{
commPort = selectedPortIdentifier.open("AT QC ReponseTime", TIMEOUT);
serialPort = (SerialPort)commPort;
setConnected(true);
if (isConnected)
{
if (initIOStream() == true)
{
initListener();
System.out.println("Initializing listener");
connectTabController.gui_changeStatusLabel("Device Connected!");
}
}
}
catch (PortInUseException e)
{
System.out.println("Port In use! " + e.toString());
}
catch (Exception e)
{
System.out.println("Failed to open! " + e.toString());
}
}
public boolean initIOStream()
{
//return value for whether opening the streams is successful or not
boolean successful = false;
try {
//
input = serialPort.getInputStream();
output = serialPort.getOutputStream();
writeData(RESETTPOD);
System.out.println("Writing Reset command");
successful = true;
System.out.println("IO Stream opened successfully!");
return successful;
}
catch (IOException e) {
System.out.println("I/O Streams failed to open. (" + e.toString() + ")");
return successful;
}
}
public void initListener()
{
try
{
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
}
catch (TooManyListenersException e)
{
System.out.println("Too many listeners. (" + e.toString() + ")");
}
}
That's how the connection is made, and it has a listener that's supposed to notify when data is available, which triggers the following:
#Override
public void serialEvent(SerialPortEvent evt) {
BufferedReader reader = null;
if (evt.getEventType() == SerialPortEvent.DATA_AVAILABLE)
{
try
{
reader = new BufferedReader(new InputStreamReader(input));
if (reader.ready())
{
fullLine = reader.readLine();
System.out.println(fullLine + "\n");
}
}
catch (Exception e)
{
System.out.println("#SerialEvent Failed to read data. (" + e.toString() + ")");
}
}
}
However, I keep getting "UNDERLYING INPUT STREAM RETURNED ZERO BYTES"
This makes no sense, since if there is nothing to read then the listener shouldnt be triggered int he first place. I tried running the app and I keep getting this error message around every 1/3 second, which corresponds to the burst-output of the device that's sending data. (which works fine in programs like PuttY)
If you are going to use the BufferedReader, take a look at the refence API document for javax.comm, CommPort and getInputStream. Then try using different settings for threshold and receive timeout.
eg).
serialPort.enableReceiveThreshold(3);
serialPort.enableReceiveTimeout(1);
https://docs.oracle.com/cd/E17802_01/products/products/javacomm/reference/api/

Write Glassfish output into servlet html page

How to redirect Glassfish server output into HttpServletResponse.out? I am making servlet in NetBeans.
here is a working example, just expose this as a servlet
public class ReadLogs extends HttpServlet {
private static final String CONTENT_TYPE = "text/html; charset=UTF-8";
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.append("<html>\n<head>\n\n");
out.append("<script>function toBottom()" + "{"
+ "window.scrollTo(0, document.body.scrollHeight);" + "}");
out.append("\n</script>");
out.append("\n</head>\n<body onload=\"toBottom();\">\n<pre>\n");
try {
File file = new File("C:\\pathToServerLogFile");
BufferedReader in = new BufferedReader(new FileReader(file));
StringBuilder sb = new StringBuilder();
while (in.ready()) {
String x = in.readLine();
sb.append(x).append("<br/>");
}
in.close();
out.append("\n</pre>\n</body>\n</html>");
out.close();
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
UPDATE
If you need to print only the last portion of the file use this after line "in.close();"
//print only 1MB Oof data
if(sb.length()>1000000){
out.append(sb.substring(sb.length()-1000000, sb.length()));
}else{
out.append(sb.toString());
}
So.. to print only lines which appeared after invoking script I've made such code:
BufferedReader reader = new BufferedReader(new FileReader("/path/to/server/log/server.log"));
int lines = 0;
while (reader.readLine() != null) {
lines++;
}
reader.close();
BufferedReader reader2 = new BufferedReader(new FileReader("/path/to/server/log/server.log"));
String strLine;
int i = 0;
while (i != lines) {
reader2.readLine();
i++;
}
while ((strLine = reader2.readLine()) != null) {
out.println(stringToHTMLString(strLine));
out.println("<br>");
}
reader2.close();
When servlet starts it counts lines in server log (saves it in variable i), then after clicking on action form it read lines which indexes are higher than i and displays it on html page. I've used function stringToHTMLString which I found somewhere on stackoverflow.
Greets.

Resources