JavaFX-TextArea实时输出
一、不推荐使用JavaFx
Java 是好文明,而awt、swing,甚至JavaFx……
注意,如果你还未学过JavaFx相关,仅仅是想做桌面端程序的图形界面,极度不建议使用JavaFx!快去另寻出路吧!!!
注:桌面端推荐C#的WPF。
为什么这么说呢?用一个梗解释就是——
Java开发GUI?狗都不干!
至于具体原因,下面的话供大家参考。
【第一位的话】
很少有人用java开发界面,如果用也是netbean(国外多一点)。
GUI一般都用的vc和c#开发,java一般写b/s网页结构的程序。
【第二位的话】
硬要java做客户端程序,只有使用SWING库了。不过我觉得很丑。
PC客户端不会用java来做的,没人会在装软件的时候,再让客户装一个JRE。客户端都是C/C++。
Java的王道在于在网络编程、数据库编程。
java有成熟而且统一、强大的类库,开发起来相当方便。
【笔者的话】
现在的主流开发是网页开发(例如Java后端+Vue前端),在此基础上则是配套的移动端APP(Android/iOS)。b站就是最典型的例子。
而且对于jdk11及更高的版本,由于jdk中已经不再自带jfx,所以还需要自己下载相应内容并配置全局变量,较为麻烦。
最重要的是,如果你使用jfx遇到了问题,很难在网上找到相关解决方案,因为国内用jfx的人实在是太少太少了。
笔者是建议转WPF的,因为c#本身是面向对象,跟java语法结构基本一致,学习很容易;而且WPF也跟jfx类似,不能说不像,只能说完全一样。
如果你看到这里依然想了解JavaFx,那就看下去吧。
二、TextArea输出问题的背景
大家都肯定安装过很多应用,大部分应用安装的时候都会有安装进度窗口。有些比较简约的只有一个进度条,还有一些是可以看到当前的文件的详细处理情况。对于后者,如何做到处理的过程中就能让显示的窗口刷新信息呢?
在代码逻辑处理部分(相当于软件安装的安装逻辑)较为复杂,耗时过长的情况下,如果在处理的过程中给TextArea增加一行文本,该文本并不会立刻显示,而是在逻辑部分处理结束后,内容才一口气全部输出到TextArea中。
这显然不是我们想要的效果。预想效果应该是如同软件安装进度显示那样,在界面a确认后,跳转到界面b,并且自动开始处理;同时,TextArea可以像控制台程序一样,一行行及时输出。
三、原因及解决办法
很显然,这是一个UI刷新的问题。查阅资料后,发现了原因:
swing主线程必须结束返回,才将内容刷新到TextArea中。
解决方法也很容易:
在新的线程中对TextArea进行操作即可。
【笔者的碎碎念】
现在距离我当初写这篇文章时间已经过了很久了。现在想想,其实只要接触过UI的,基本都知道UI刷新应该新开线程循环,而非在主线程中直接操作。所以这个解决方案大概只有跟我一样小白的人才会看吧(
四、具体代码
说明:代码框架基于这位老哥的 JavaFX 登录界面跳转。
下面只放出修改的地方!
下面只放出修改的地方!
下面只放出修改的地方!
重要的事情说三遍。
请从上方链接下载基础代码,再按如下内容修改。
FXMLTest.java修改
public void gotoMain() {
try {
MainController main = (MainController) replaceSceneContent("FXML_MAIN.fxml");
main.setApp(this);
// 新开三个线程,每个线程往TextArea不断输出指定字符串
new PrintThread(main, "test1").start();
new PrintThread(main, "test2").start();
new PrintThread(main, "test3").start();
} catch (Exception e) {
Logger.getLogger(FXMLTest.class.getName()).log(Level.SEVERE, null, e);
}
}
MainController.java新增
@FXML
TextArea textArea;
FXML_MAIN.fxml修改
增加一个TextArea,并且将其fx:id设为textArea。
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="500.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fxmltest.MainController">
<children>
<Hyperlink layoutX="40.0" layoutY="254.0" onAction="#OUT_M" prefHeight="30.0" prefWidth="106.0" text="退出登录!" />
<TextArea fx:id="textArea" layoutX="22.0" layoutY="24.0" prefHeight="215.0" prefWidth="457.0" />
</children>
</AnchorPane>
新文件PrintThread.java
package fxmltest;
public class PrintThread extends Thread {
private MainController main;
private String s;
PrintThread(MainController main, String s) {
this.main = main;
this.s = s;
}
public void run() {
for (int i = 0; i < 10; i++) {
// 注意,这里不属于swing主线程,所以appendText的内容才会被刷新
main.textArea.appendText(s + "\n");
try {
sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
五、结尾
感谢你花费时间看到这里!希望本文能对你有所帮助。
一入jfx深似海,从此红尘是路人
立刻删除jfx,转战wpf