Javafx程序,它可以由GUI和命令行控制?
我正在使用javafxgui,但我也需要从命令行获得相同级别的功能。我想知道制作一个同时具有命令行和Javafx功能的主类的最佳方法是什么,这样您就可以在GUI上做一件事,然后在命令行上做下一件事。命令行还将更新GUI显示 我认为这是一个界限,不能太宽。其中一部分是:您的需求不明确。是否打算使用以下命令行:Javafx程序,它可以由GUI和命令行控制?,java,javafx,command-line-interface,Java,Javafx,Command Line Interface,我正在使用javafxgui,但我也需要从命令行获得相同级别的功能。我想知道制作一个同时具有命令行和Javafx功能的主类的最佳方法是什么,这样您就可以在GUI上做一件事,然后在命令行上做下一件事。命令行还将更新GUI显示 我认为这是一个界限,不能太宽。其中一部分是:您的需求不明确。是否打算使用以下命令行: java -jar whatever.jar -command A java -jar whatever.jar -command B java -jar whatever.jar -com
java -jar whatever.jar -command A
java -jar whatever.jar -command B
java -jar whatever.jar -command C
因此,您反复调用java,而which.jar基本上是一个客户机,它将连接到某个“服务器”来完成真正的工作,或者您设想的是什么
java -jar whatever.jar
> Type your command:
> A
... ran command A
> Type your command:
显然,这在这里有很大的不同
但最后,它还告诉我们解决方案在哪里:通过将这些客户机与实际执行分离
意思:你应该做两件事
- 定义某些服务器必须提供的功能或服务
- 然后,您可以研究创建使用这些服务的不同客户端的方法
避免将所有这些不同的方面烘焙到一个main()方法中 GUI上的所有内容都是基于事件的。这意味着当您按下按钮或以另一种方式与JavaFX窗口交互时,方法会被调用,就像在列表中选择一个项目一样 我建议将内部逻辑和GUI逻辑分开。 单击按钮时,调用链接到该按钮的handleButton(ActionEvent ActionEvent)方法。这个方法应该调用一个实际包含逻辑的其他类中的方法 您可以使用扫描仪通过命令行获取用户输入:
public String getUserInput() {
Scanner scan = new Scanner(System.in);
String s = scan.next();
return s
}
您现在可以检查此用户输入字符串,并使用switch(s)语句连接相应的方法
我不确定您何时希望通过命令行获取此输入,但我建议在阶段中添加一个开发人员按钮,按下该按钮时调用getUserInput()
。(真的,这个问题是离题的,因为它太宽泛了。不过,对我来说,尝试一个对我来说似乎很自然的方法的概念证明已经足够有趣了,所以我还是回答了。)
这里基本上需要两件事:
start()
方法启动CLI,在后台线程中运行它,这样它就不会阻塞UI。您只需要确保模型在正确的(即FX应用程序)线程上进行更新import java.util.stream.Collectors;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class AddingModel {
private final ObservableList<Integer> values = FXCollections.observableArrayList();
private final ReadOnlyIntegerWrapper total = new ReadOnlyIntegerWrapper();
public AddingModel() {
total.bind(Bindings.createIntegerBinding(() ->
values.stream().collect(Collectors.summingInt(Integer::intValue)),
values));
}
private void ensureFXThread(Runnable action) {
if (Platform.isFxApplicationThread()) {
action.run();
} else {
Platform.runLater(action);
}
}
public void clear() {
ensureFXThread(values::clear);
}
public void addValue(int value) {
ensureFXThread(() -> values.add(value));
}
public final ReadOnlyIntegerProperty totalProperty() {
return this.total.getReadOnlyProperty();
}
public final int getTotal() {
return this.totalProperty().get();
}
public ObservableList<Integer> getValues() {
return values ;
}
}
最后是组装所有这些的JavaFX应用程序。请注意,相同的模型实例同时传递给CLI和UI控制器,因此两者都在更新相同的数据。您可以在文本字段中输入一些值,然后在命令行中键入“show”,您将看到这些值。键入“clear”在命令行中,这些值将从UI中删除,等等
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class AddingApp extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
AddingModel model = new AddingModel();
AddingController controller = new AddingController(model);
FXMLLoader loader = new FXMLLoader(AddingController.class.getResource("ValueTotaler.fxml"));
loader.setControllerFactory(type -> {
if (type == AddingController.class) {
return controller ;
} else {
throw new IllegalArgumentException("Unexpected controller type: "+type);
}
});
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
AddingCLI cli = new AddingCLI(model);
Thread cliThread = new Thread(cli::processCommandLine);
cliThread.setDaemon(true);
cliThread.start();
}
public static void main(String[] args) {
launch(args);
}
}
当然,您可以在不使用CLI的情况下创建UI,也可以在不使用UI的情况下创建CLI;两者都是相互独立的(它们都取决于模型)。scan.next()
是一个阻塞调用:它会等待收到输入。因此,您的建议会使UI没有响应(完全冻结它)直到用户输入一些东西。
import java.util.List;
import java.util.Scanner;
import java.util.regex.Pattern;
public class AddingCLI {
private final AddingModel model ;
private final Pattern intPattern = Pattern.compile("-?[0-9]+");
public AddingCLI(AddingModel model) {
this.model = model ;
}
public void processCommandLine() {
try (Scanner in = new Scanner(System.in)) {
while (true) {
String input = in.next().trim().toLowerCase();
if (intPattern.matcher(input).matches()) {
int value = Integer.parseInt(input);
model.addValue(value);
} else if ("show".equals(input)) {
outputValues();
} else if ("clear".equals(input)) {
model.clear();
System.out.println("Values cleared");
} else if ("total".equals(input)) {
System.out.println("Total = "+model.getTotal());
}
}
}
}
private void outputValues() {
List<Integer> values = model.getValues();
if (values.isEmpty()) {
System.out.println("No values");
} else {
values.forEach(System.out::println);
}
}
}
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class AddingApp extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
AddingModel model = new AddingModel();
AddingController controller = new AddingController(model);
FXMLLoader loader = new FXMLLoader(AddingController.class.getResource("ValueTotaler.fxml"));
loader.setControllerFactory(type -> {
if (type == AddingController.class) {
return controller ;
} else {
throw new IllegalArgumentException("Unexpected controller type: "+type);
}
});
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
AddingCLI cli = new AddingCLI(model);
Thread cliThread = new Thread(cli::processCommandLine);
cliThread.setDaemon(true);
cliThread.start();
}
public static void main(String[] args) {
launch(args);
}
}