我正在使用Javafx GUI,但我还需要命令行提供相同级别的功能。我想知道什么是最好的方法来创建一个同时具有命令行和Javafx功能的主类,这样你就可以在GUI上做一件事,然后在命令行上做下一件事。命令行还将更新GUI显示。
答案 0 :(得分:3)
(真的,这个问题是偏离主题的,因为它太宽泛了。但是,对我来说,尝试对我来说看起来很自然的方法的概念证明非常有趣,所以无论如何我都回答了。)
你基本上需要两件事:
start()
方法启动CLI,在后台线程中运行它,以便它不会阻止UI。您只需要确保模型在正确的(即FX应用程序)线程上进行更新。这是一个简单的例子,它只计算整数列表的总和。这是模型,它存储列表和总数。它具有添加新值或清除列表的方法。请注意这些方法如何在UI线程上执行更改:
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 ;
}
}
这是UI代码。首先是一个视图,在FXML中:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddingController">
<top>
<HBox spacing="5">
<TextField fx:id="valueField" onAction="#addValue"/>
<Button text="Clear" onAction="#clearValues"/>
</HBox>
</top>
<center>
<ListView fx:id="values"/>
</center>
<bottom>
<Label fx:id="sum"/>
</bottom>
</BorderPane>
和一个观察和更新模型的控制器:
import java.util.function.UnaryOperator;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
public class AddingController {
private final AddingModel model ;
@FXML
private TextField valueField ;
@FXML
private ListView<Integer> values ;
@FXML
private Label sum ;
public AddingController(AddingModel model) {
this.model = model ;
}
@FXML
private void initialize() {
values.setItems(model.getValues());
sum.textProperty().bind(model.totalProperty().asString("Total = %,d"));
// Allow only integer values in the text field:
UnaryOperator<TextFormatter.Change> filter = c -> {
if (c.getControlNewText().matches("-?[0-9]*")) {
return c;
} else {
return null ;
}
};
valueField.setTextFormatter(new TextFormatter<>(filter));
}
@FXML
private void addValue() {
String text = valueField.getText();
if (! text.isEmpty()) {
int value = Integer.parseInt(text);
model.addValue(value);
valueField.clear();
}
}
@FXML
private void clearValues() {
model.clear();
}
}
现在是一个简单的命令行解释器,它从命令行读取并引用模型。它支持整数条目(为模型添加值)或命令total
,show
或clear
:
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);
}
}
}
最后,组装所有这些的JavaFX应用程序。请注意,相同的模型实例将传递给CLI和UI控制器,因此两者都在更新相同的数据。您可以在文本字段中输入一些值,然后键入&#34; show&#34;在命令行中,您将看到值。输入&#34;清除&#34;在命令行中,值将从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;两者都是相互独立的(它们都只取决于模型)。
答案 1 :(得分:1)
我认为 borderline 过于宽泛。其中一部分是:您的要求不清楚。您打算使用命令行,如:
java -jar whatever.jar -command A
java -jar whatever.jar -command B
java -jar whatever.jar -command C
所以 - 你反复调用java,而且what.jar基本上是一个客户端,需要一些服务器&#34;这是真正的工作,还是你想象的
java -jar whatever.jar
> Type your command:
> A
... ran command A
> Type your command:
显然,这在这里有很大的不同。
但最后,它还告诉我们解决方案的位置:通过将这些客户端从实际执行中解除耦合。
含义:你应该做两件事
避免将所有这些不同方面都烘焙到一个 main()方法中!
答案 2 :(得分:0)
GUI上的所有内容都是基于事件的。这意味着当您按下按钮或以另一种方式与JavaFX窗口交互时调用方法,例如选择列表中的项目。
我建议保持内部逻辑和GUI逻辑分离。 单击按钮时,您将调用链接到该按钮的handleButton(ActionEvent actionEvent)方法。此方法应调用其他一个实际包含逻辑的类中的方法。
您可以通过命令行使用扫描仪获取用户输入:
public String getUserInput() {
Scanner scan = new Scanner(System.in);
String s = scan.next();
return s
}
您现在可以检查此用户输入字符串,并使用switch(s)语句连接相应的方法。
我不确定您何时希望通过命令行获取此输入,但我建议您在舞台中添加一个开发人员按钮,在按下时调用getUserInput()
。