我有一个 Java 记录器,当前使用下面指定的设置输出到文件。我还有一个 JavaFX TextArea,我希望我的记录器同时写入文件和 TextArea。
记录器设置:
java.util.logging.FileHandler.level = ALL
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.FileHandler.append = true
java.util.logging.FileHandler.pattern = log.txt
记录器声明:
static Logger LOGGER;
static {
try(FileInputStream ins = new FileInputStream("src/main/resources/log.config")) {
LogManager.getLogManager().readConfiguration(ins);
LOGGER = Logger.getLogger(BuildGet.class.getName());
initialContext = new InitialContext();
} catch (NamingException | IOException e) {
LOGGER.log(Level.WARNING,"ERROR LOGGER", e);
}
}
JavaFX 文本区域:
```xml``<TextArea layoutX="20.0" layoutY="755.0" prefHeight="80.0" prefWidth="560.0" fx:id="logTextArea"/>`
播放示例时出现错误:
javafx.fxml.LoadException:
/C:/Users/slizo/Desktop/DConsole/target/classes/DConsoleScene.fxml:18
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:944)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:981)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:230)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:755)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2808)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2634)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2516)
at jmxClientConsole.gui.DConsoleFrame.start(DConsoleFrame.java:46)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NoSuchMethodException: jmxClientConsole.DConsoleFrameControllerGetMessage.<init>()
at java.base/java.lang.Class.getConstructor0(Class.java:3349)
at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2553)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:939)
... 17 more
这是我的启动类(class):
package jmxClientConsole.gui;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import jmxClientConsole.BuildGet;
import jmxClientConsole.TextAreaHandler;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
public class ConsoleFrame extends Application {
static Logger LOGGER;
static {
try(FileInputStream ins = new FileInputStream("src/main/resources/log.config")) {
LogManager.getLogManager().readConfiguration(ins);
LOGGER = Logger.getLogger(BuildGet.class.getName());
LOGGER.setUseParentHandlers(false);
} catch (IOException e) {
LOGGER.log(Level.WARNING," Eror ConsoleFrame ", e);
}
}
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
try {
FXMLLoader loader = new FXMLLoader();
URL xmlUrl = getClass().getResource("/ConsoleScene.fxml");
loader.setLocation(xmlUrl);
TextArea textArea = new TextArea();
textArea.setEditable(false);
textArea.setFont(Font.font("Monospaced", 13));
TextAreaHandler handler = new TextAreaHandler(textArea);
handler.setFormatter(new SimpleFormatter());
LOGGER.addHandler(handler);
Parent root = loader.load();
stage.setTitle("Console");
stage.getIcons().add(new Image(ConsoleFrame.class.getClassLoader().getResourceAsStream("logoC.png")));
stage.setScene(new Scene(root));
stage.show();
LOGGER.log(Level.INFO,"Success console ");
} catch (Exception e) {
LOGGER.log(Level.SEVERE,"Eror Console", e);
}
}
}
我在关于 Controller 的评论中写的,我有这个。我里面有按钮的所有逻辑:
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="900.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="jmxClientConsole.ConsoleFrameControllerGetMessage">
最佳答案
最终,您需要一个 java.util.logging.Handler
将日志消息附加到 TextArea
中。这是一个相对简单的实现:
package sample;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.logging.ErrorManager;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import javafx.application.Platform;
import javafx.scene.control.TextArea;
public class TextAreaHandler extends Handler {
// Avoid doing too much work at once. Tune this value as needed.
private static final int MAX_APPEND = 100;
private final Queue<LogRecord> recordQueue = new ArrayDeque<>();
private boolean notify = true;
private final TextArea textArea;
private volatile boolean open = true;
public TextAreaHandler(TextArea textArea) {
this.textArea = textArea;
}
@Override
public void publish(LogRecord record) {
if (open && isLoggable(record)) {
if (Platform.isFxApplicationThread()) {
appendRecord(record);
} else {
synchronized (recordQueue) {
recordQueue.add(record);
if (notify) {
notify = false;
notifyFxThread();
}
}
}
}
}
private void notifyFxThread() {
try {
Platform.runLater(this::processQueue);
} catch (Exception ex) {
reportError(null, ex, ErrorManager.GENERIC_FAILURE);
}
}
private void processQueue() {
List<LogRecord> records = new ArrayList<>();
synchronized (recordQueue) {
while (!recordQueue.isEmpty() && records.size() < MAX_APPEND) {
records.add(recordQueue.remove());
}
if (recordQueue.isEmpty()) {
notify = true;
} else {
notifyFxThread();
}
}
records.forEach(this::appendRecord);
}
private void appendRecord(LogRecord record) {
String message;
try {
message = getFormatter().format(record);
} catch (Exception ex) {
reportError(null, ex, ErrorManager.FORMAT_FAILURE);
return;
}
try {
textArea.appendText(message);
} catch (Exception ex) {
reportError(null, ex, ErrorManager.GENERIC_FAILURE);
}
}
@Override
public void flush() {
/*
* This implementation has no "buffer". If the 'recordQueue' is not
* empty then the JavaFX Application Thread has already been notified
* of work, meaning the queue will be emptied eventually. And if the
* JavaFX framework has been shutdown, then there's no work to do
* anyway.
*/
}
@Override
public void close() {
open = false;
}
}
上面可以像这样使用:
package sample;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class Main extends Application {
private static final Logger LOGGER = Logger.getLogger(Main.class.getName());
static {
LOGGER.setUseParentHandlers(false);
}
@Override
public void start(Stage primaryStage) {
TextArea textArea = new TextArea();
textArea.setEditable(false);
textArea.setFont(Font.font("Monospaced", 13));
TextAreaHandler handler = new TextAreaHandler(textArea);
handler.setFormatter(new SimpleFormatter());
LOGGER.addHandler(handler);
primaryStage.setScene(new Scene(textArea, 600, 400));
primaryStage.show();
LOGGER.info("This log message will be appended to the text area.");
}
}
不幸的是,我不知道如何(如果可能的话)从文件中配置它。至少,不是没有某种方法来间接获取 TextArea
(例如,依赖项注入(inject)、JNDI(?) 等)。
您已经编辑了您的问题,表示您收到此错误:
Caused by: java.lang.NoSuchMethodException: jmxClientConsole.DConsoleFrameControllerGetMessage.<init>()
at java.base/java.lang.Class.getConstructor0(Class.java:3349)
at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2553)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:939)
这是一个与您最初询问的问题不同的问题。但是,该错误告诉您某些代码期望您的类(如错误中所指定)具有无参数构造函数,但该构造函数不存在。
如果该类用作 FXML Controller ,请注意默认 Controller 工厂需要无参构造函数。添加该构造函数或设置自定义 Controller 工厂(如何做到这一点超出了本问答的范围;应该有教程,可能还有其他 Stack Overflow 问答)。
关于java - 如何在JavaFX TextArea中显示日志?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76488986/
原网址: 访问
创建于: 2024-02-21 11:23:37
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论