gpt4 book ai didi

java - 处理已启动的 JavaFX 应用程序

转载 作者:行者123 更新时间:2023-11-29 03:09:18 27 4
gpt4 key购买 nike

如何使用以下代码获取 JavaFX 应用程序的句柄?

CPUUsageChart.launch(CPUUsageChart.class);

CPUUsageChart 从 JavaFX 扩展应用程序,我从一个简单 Java 项目的主要方法启动它。

我最终想要实现的是,我可以在简单的Java代码中启动应用程序并使用它的方法,这样我就不必在应用程序扩展类的构造函数中进行调用。我只想使用 JavaFX 的功能来绘制图表并将它们保存到 HDD 以备后用,但我不需要看到任何用 JavaFX 制作的 GUI。

最佳答案

建议的解决方案

您可以 only launch an application once ,因此您的应用程序类只会有一个实例。

因为应用程序只有一个实例,所以可以在应用程序启动时将对该实例的引用存储在应用程序的静态变量中,并且可以根据需要从静态方法(一种单例模式)。

注意事项

必须注意确保:

  1. 实例在您尝试使用之前可用。
  2. 正确遵守线程规则。
  3. JavaFX 平台在不再需要时适当关闭。

示例解决方案

下面的示例代码使用锁和条件来确保应用程序实例在您尝试使用它之前可用。当不再需要时,它还需要明确关闭 JavaFX 平台。

感谢 StackOverflow 用户 James-D 对这段代码的一些编辑帮助。

import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class CPUUsageChart extends Application {
private static CPUUsageChart appInstance;

private static final Lock lock = new ReentrantLock();
private static final Condition appStarted = lock.newCondition();

/**
* Starts the application and records the instance.
* Sets the JavaFX platform not to exit implicitly.
* (e.g. an explicit call to Platform.exit() is required
* to exit the JavaFX Platform).
*/
@Override
public void start(Stage primaryStage) {
lock.lock();

try {
Platform.setImplicitExit(false);
appInstance = this;
appStarted.signalAll();
} finally {
lock.unlock();
}
}

/**
* Get an instance of the application.
* If the application has not already been launched it will be launched.
* This method will block the calling thread until the
* start method of the application has been invoked and the instance set.
* @return application instance (will not return null).
*/
public static CPUUsageChart getInstance() throws InterruptedException {
lock.lock();

try {
if (appInstance == null) {
Thread launchThread = new Thread(
() -> launch(CPUUsageChart.class),
"chart-launcher"
);
launchThread.setDaemon(true);
launchThread.start();
appStarted.await();
}
} finally {
lock.unlock();
}

return appInstance;
}

/**
* Public method which can be called to perform the main operation
* for this application.
* (render a chart and store the chart image to disk).
* This method can safely be called from any thread.
* Once this method is invoked, the data list should not be modified
* off of the JavaFX application thread.
*/
public void renderChart(
ObservableList<XYChart.Data<Number, Number>> data
) {
// ensure chart is rendered on the JavaFX application thread.
if (!Platform.isFxApplicationThread()) {
Platform.runLater(() -> this.renderChartImpl(data));
} else {
this.renderChartImpl(data);
}
}

/**
* Private method which can be called to perform the main operation
* for this application.
* (render a chart and store the chart image to disk).
* This method must be invoked on the JavaFX application thread.
*/
private void renderChartImpl(
ObservableList<XYChart.Data<Number, Number>> data
) {
LineChart<Number, Number> chart = new LineChart<>(
new NumberAxis(),
new NumberAxis(0, 100, 10)
);
chart.setAnimated(false);
chart.getData().add(
new XYChart.Series<>("CPU Usage", data)
);

Scene scene = new Scene(chart);

try {
LocalDateTime now = LocalDateTime.now();
File file = Paths.get(
System.getProperty("user.dir"),
"cpu-usage-chart-" + now + ".png"
).toFile();
ImageIO.write(
SwingFXUtils.fromFXImage(
chart.snapshot(null, null),
null
),
"png",
file
);

System.out.println("Chart saved as: " + file);
} catch (IOException e) {
e.printStackTrace();
}
}
}

要使用它(从任何线程):

try {
// get chartApp instance, blocking until it is available.
CPUUsageChart chartApp = CPUUsageChart.getInstance();
// call render chart as many times as you want
chartApp.renderChart(cpuUsageData);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
// note your program should only ever exit the platform once.
Platform.exit();
}

完整的示例应用程序创建了五个 cpu 使用数据图表,每个图表中有十个样本,每个样本间隔 100 毫秒。当示例调用图表应用程序呈现图表时,它将在当前 java 工作目录中创建图表 png 图像文件,文件名将输出到系统控制台。不显示 JavaFX 阶段或窗口。

示例 CPU 使用率的代码复制自:How to get percentage of CPU usage of OS from java

import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.chart.XYChart;

import javax.management.*;
import java.lang.management.ManagementFactory;

public class ChartTest {
public static void main(String[] args) {
try {
CPUUsageChart chart = CPUUsageChart.getInstance();
for (int i = 0; i < 5; i++) {
ObservableList<XYChart.Data<Number, Number>> cpuUsageData = FXCollections.observableArrayList();
for (int j = 0; j < 10; j++) {
cpuUsageData.add(
new XYChart.Data<>(
j / 10.0,
getSystemCpuLoad()
)
);
Thread.sleep(100);
}
chart.renderChart(cpuUsageData);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (MalformedObjectNameException | ReflectionException | InstanceNotFoundException e) {
e.printStackTrace();
} finally {
Platform.exit();
}
}

public static double getSystemCpuLoad() throws MalformedObjectNameException, ReflectionException, InstanceNotFoundException {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
AttributeList list = mbs.getAttributes(name, new String[]{ "SystemCpuLoad" });

if (list.isEmpty()) return Double.NaN;

Attribute att = (Attribute)list.get(0);
Double value = (Double)att.getValue();

if (value == -1.0) return Double.NaN; // usually takes a couple of seconds before we get real values

return ((int)(value * 1000) / 10.0); // returns a percentage value with 1 decimal point precision
}
}

示例输出(Y 轴上的 CPU 使用率百分比,X 轴上的十分之一秒采样间隔时间)。

enter image description here enter image description here enter image description here enter image description here enter image description here

背景信息

替代实现

  • 你可以使用 JFXPanel而不是扩展应用程序的类。不过,您的应用程序也会依赖于 Swing。
  • 您可以让您的应用程序的主类扩展 Application,这样应用程序会在您的应用程序启动时自动启动,而不是只为您的使用图表创建一个单独的应用程序。
  • 如果您要呈现大量图表,您可以查看此 off screen chart renderer implementation .

关于java - 处理已启动的 JavaFX 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30335165/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com