terminalfx 代替模拟终端

This commit is contained in:
汪方大 2024-02-01 14:49:52 +08:00
parent 034f895b25
commit 56fdb968b4
5 changed files with 25 additions and 162 deletions

13
pom.xml
View File

@ -15,7 +15,20 @@
<junit.version>5.9.2</junit.version> <junit.version>5.9.2</junit.version>
<javafx.version>20.0.2</javafx.version> <javafx.version>20.0.2</javafx.version>
</properties> </properties>
<repositories>
<repository>
<id>terminalfx-repo</id>
<url>https://github.com/javaterminal/terminalfx/raw/master/releases</url>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency>
<groupId>com.kodedu.terminalfx</groupId>
<artifactId>terminalfx</artifactId>
<version>1.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.fxmisc.richtext/richtextfx --> <!-- https://mvnrepository.com/artifact/org.fxmisc.richtext/richtextfx -->
<!--JavaFX 的富文本区域--> <!--JavaFX 的富文本区域-->
<dependency> <dependency>

View File

@ -19,6 +19,7 @@ module org.jcnc.jnotepad {
requires java.desktop; requires java.desktop;
requires org.commonmark; requires org.commonmark;
requires javafx.web; requires javafx.web;
requires com.kodedu.terminalfx;
exports org.jcnc.jnotepad; exports org.jcnc.jnotepad;
exports org.jcnc.jnotepad.model.enums; exports org.jcnc.jnotepad.model.enums;

View File

@ -120,6 +120,7 @@ public class ApplicationManager {
instance.checkFileTabStatus(instance.getSelected()); instance.checkFileTabStatus(instance.getSelected());
} }
}); });
primaryStage.setOnCloseRequest(event -> System.exit(0));
} }
/** /**

View File

@ -1,15 +1,16 @@
package org.jcnc.jnotepad.component.module.vbox; package org.jcnc.jnotepad.component.module.vbox;
import com.kodedu.terminalfx.TerminalBuilder;
import com.kodedu.terminalfx.TerminalTab;
import com.kodedu.terminalfx.config.TerminalConfig;
import javafx.scene.control.Tab; import javafx.scene.control.Tab;
import javafx.scene.control.TabPane; import javafx.scene.control.TabPane;
import org.jcnc.jnotepad.component.module.vbox.components.CmdTerminalBox;
import org.jcnc.jnotepad.component.module.vbox.components.DebugBox; import org.jcnc.jnotepad.component.module.vbox.components.DebugBox;
import org.jcnc.jnotepad.component.module.vbox.components.RunBox; import org.jcnc.jnotepad.component.module.vbox.components.RunBox;
/** /**
* 底部Run,Debug,Cmd面板 * 底部Run,Debug,Cmd面板
* *
*
* @author cccqyu * @author cccqyu
*/ */
public class BuildPanel extends TabPane { public class BuildPanel extends TabPane {
@ -24,28 +25,25 @@ public class BuildPanel extends TabPane {
return instance; return instance;
} }
private final CmdTerminalBox cmdTerminalBox;
private final RunBox runBox; private final RunBox runBox;
private final DebugBox debugBox; private final DebugBox debugBox;
private BuildPanel() { private BuildPanel() {
cmdTerminalBox = new CmdTerminalBox(); TerminalConfig config = new TerminalConfig();
TerminalBuilder builder = new TerminalBuilder(config);
TerminalTab terminalTab = builder.newTerminal();
terminalTab.setClosable(false);
runBox = new RunBox(); runBox = new RunBox();
debugBox = new DebugBox(); debugBox = new DebugBox();
Tab runTab = new Tab("运行",runBox); Tab runTab = new Tab("运行", runBox);
runTab.setClosable(false); runTab.setClosable(false);
Tab buildTab = new Tab("构建", debugBox); Tab buildTab = new Tab("构建", debugBox);
buildTab.setClosable(false); buildTab.setClosable(false);
Tab cmdTab = new Tab("终端",cmdTerminalBox); this.getTabs().addAll(runTab, buildTab, terminalTab);
cmdTab.setClosable(false);
this.getTabs().addAll(runTab,buildTab,cmdTab);
}
public CmdTerminalBox getCmdTerminalBox() {
return cmdTerminalBox;
} }
public RunBox getRunBox() { public RunBox getRunBox() {

View File

@ -1,150 +0,0 @@
package org.jcnc.jnotepad.component.module.vbox.components;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.control.TextField;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.util.Duration;
import org.fxmisc.richtext.StyleClassedTextArea;
import org.jcnc.jnotepad.util.LogUtil;
import java.io.*;
import java.nio.charset.Charset;
/**
* 命令行终端界面
*
* @author luke
*/
public class CmdTerminalBox extends VBox {
/**
* 用于显示命令输出的文本区域
*/
private final StyleClassedTextArea cmdOutput;
/**
* 用户输入命令的文本框
*/
private final TextField cmdInput;
/**
* 用于运行命令的进程
*/
private Process cmdProcess;
/**
* 用于向命令进程发送输入的写入器
*/
private PrintWriter cmdInputWriter;
String currentDirectory;
/**
* 创建CmdTerminal对象的构造函数
*/
public CmdTerminalBox() {
// 创建UI元素
cmdOutput = new StyleClassedTextArea();
cmdInput = new TextField();
// 设置CodeArea的大小策略和边距
// 让CodeArea在垂直方向上扩展以填充剩余空间
VBox.setVgrow(cmdOutput, Priority.ALWAYS);
// 设置CodeArea的边距
VBox.setMargin(cmdOutput, new Insets(8));
// 添加输入框的Enter键监听器按下Enter执行命令
cmdInput.setOnAction(e -> executeCommand());
// 创建布局
getChildren().addAll(cmdOutput, cmdInput);
// 获取当前工作目录的文件夹路径
currentDirectory = System.getProperty("user.dir");
// 创建并启动cmd进程使用GBK字符编码
try {
cmdProcess = new ProcessBuilder("cmd.exe")
// 设置CMD工作目录为当前文件夹路径
.directory(new File(currentDirectory))
.redirectErrorStream(true)
.start();
cmdInputWriter = new PrintWriter(new OutputStreamWriter(cmdProcess.getOutputStream(), Charset.forName("GBK")));
} catch (IOException e) {
LogUtil.getLogger(this.getClass()).info("已调用, {}", cmdProcess);
}
// 延迟执行打印当前文件夹路径的语句
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(0.5), event -> {
appendTextToCmdOutput(currentDirectory + ">" + "\n");
}));
timeline.setCycleCount(1);
timeline.play();
// 读取cmd的输出并显示在UI中
InputStream cmdOutputInputStream = cmdProcess.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(cmdOutputInputStream, Charset.forName("GBK")));
Thread cmdOutputThread = getCmdOutputThread(reader);
cmdOutputThread.start();
// 关闭cmd进程
Platform.runLater(() -> getScene().getWindow().setOnCloseRequest(e -> {
if (cmdProcess != null) {
cmdProcess.destroy();
}
}));
}
private Thread getCmdOutputThread(BufferedReader reader) {
Task<Void> cmdOutputTask = new Task<>() {
@Override
protected Void call() {
String line;
try {
while ((line = reader.readLine()) != null) {
final String outputLine = line + "\n";
Platform.runLater(() -> appendTextToCmdOutput(outputLine));
}
} catch (IOException e) {
LogUtil.getLogger(this.getClass()).info("已调用, {}", this);
}
return null;
}
};
Thread cmdOutputThread = new Thread(cmdOutputTask);
cmdOutputThread.setDaemon(true);
return cmdOutputThread;
}
/**
* 执行用户输入的命令
*/
private void executeCommand() {
String command = cmdInput.getText();
if (cmdProcess != null && command != null) {
cmdInputWriter.println(command);
cmdInputWriter.flush();
cmdInput.clear();
}
}
/**
* 将文本追加到命令输出文本区域并滚动到最后一行
*
* @param text 要追加的文本
*/
private void appendTextToCmdOutput(String text) {
Platform.runLater(() -> {
cmdOutput.appendText(text);
// 将滚动条滚动到最后一行
cmdOutput.moveTo(cmdOutput.getLength());
cmdOutput.requestFollowCaret();
});
}
}