【问题标题】:Launch a windows batch file from Java GUI Application从 Java GUI 应用程序启动 Windows 批处理文件
【发布时间】:2014-02-19 05:55:13
【问题描述】:

我使用 Java Swing 创建了一个桌面应用程序。它需要用户的一些输入,创建一个配置文件和一个批处理文件来运行 python 脚本。许多担忧是:
- 我希望 GUI 在批处理文件执行过程中处于活动模式
- 应用程序中有一个类似 ShowLog 的按钮,用于在执行期间检查控制台输出。这应该可以点击
- 我在 GUI 中有一个“正在进行中的任务”类型的消息,当批处理文件执行完成时,它应该被替换为“任务已完成”
- 一个“停止”按钮也可以强制停止批处理文件的执行。那也应该可以正常工作
(注意:批处理文件执行需要几个小时才能完成)

任何人都可以提出一些想法来实现所有这些吗?

【问题讨论】:

标签: java multithreading swing batch-file


【解决方案1】:

您似乎知道,Swing 是一个单线程框架,这意味着在事件调度线程的上下文中运行的任何东西都会阻止它更新屏幕或响应用户输入。

基本的解决方案是使用Thread 来运行批处理,但这会引发与 UI 更新同步的问题,因为您不应该从 EDT 上下文之外修改 UI 或与 UI 交互.

更好的解决方案是使用SwingWorker,它使您能够在后台运行长时间运行的任务,但使您能够在上下文中进行publish 更新和process 更新在 EDT 中,它还为您提供了一个 done 方法,该方法在 doInBackground 方法退出后调用,并在 EDT 的上下文中调用。

最后,它为您提供了一个cancel 选项——然而,这正是问题所在。大概您将在辅助线程中从进程中读取输入,并且将是 waiting 以使进程在您启动它的同一线程 (SwingWorker) 中退出。 SwingWorker 依赖于 Thread 的 interrupt 功能,这可能不会触发 waitFor 方法返回。

现在阅读了Process 文档,waitFor 确实抛出了InterruptedException

如果当前线程被另一个线程中断,而它正在 等待,然后等待结束并抛出 InterruptedException。

这表明当done 被调用时,你需要调用isCancelled 来检查worker 是否被取消。如果是,您需要在Process 上调用destroy 并关闭您可能正在运行的任何辅助Threads。

您可以使用额外的SwingWorker 来读取进程的输入,并利用它的publish/process 功能来更新日志。

这意味着,您将启动一个SwingWorker 来执行您的外部进程。这可能是为了响应某些事件,例如按钮按下。

当这个worker的doInBackground方法被调用时,它会执行外部进程并调用Process#waitFor。这将阻止doInBackground 方法返回,直到进程退出。

在调用Process#waitFor 之前,您可以创建另一个SwingWorker 并将Process 的OutputStream 传递给它。这将允许该工作人员独立处理流程的输出。然后,您可以使用它通过SwingWorker 的publish/process 功能将进程的输出发送回EDT,该功能可以添加到JTextArea 之类的东西中。

这将为您节省很多处理SwingUtilities.invokeLater 的麻烦。

你需要第二份工作吗?这取决于你想让工人做什么。我倾向于在单独的线程中处理外部进程的所有输出,并允许创建该进程的人使用waitFor,它更多地隔离了责任,并防止 IO 被锁定到永远不会到达waitFor,但这就是只有我。

查看Concurrency in Swing了解更多详情

【讨论】:

  • 我认为这是白痴。新流程将拥有自己的“SwingWrokers”。您不需要线程来执行并行进程。
  • @Val 你是什么意思?我通常使用单独的线程来读取进程OutputStream,同时允许Thread 开始到waitFor
  • @Val 你能更详细地解释一下你的观点吗?
  • @MadProgrammer 感谢您的新想法。但我在想的是,我已经在 NetBeans 中设计了一个现有的 GUI。我可以将 SwingWorkers 集成到现有设置中,还是需要从头开始?
  • 不,您应该能够非常简单地集成它。基本上,您只需要获取执行和监视外部进程的代码部分并将其包装在SwingWorker 中。只需确保您保留对它的引用,以便您可以将其称为 cancel 方法
【解决方案2】:

您可以使用 Runtime 在 java 中运行 bat 文件

Runtime.getRuntime().exec("cmd /c start your_batch_file.bat");

【讨论】:

  • 谢谢@Dark。但是,你知道,我关心的不是如何从 Java App 启动一个 bat 文件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-14
  • 2020-04-10
  • 2010-10-19
  • 1970-01-01
  • 2016-04-24
  • 2016-05-24
  • 2013-08-26
相关资源
最近更新 更多