我正在为批处理程序制作包装器,但找不到实时更新输出的方法
I'm making a wrapper for a batch program and I can't find a way to update output in realtime
我运行一个服务器是一个jar文件,通过批处理执行。我试图为它制作一个包装器,但我找不到一种方法让批处理文件的输出在文本框上实时更新。
目前我使用的代码如下所示:
public partial class Form1 : Form
{
string output = "Server has not been started yet...";
public void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(batch); // Kick off a new thread
t.Start(); // Running batch()
Thread l = new Thread(loop);
l.Start(); //Running loop
}
// This will run the batch file in the background
public void batch()
{
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c @echo off";
p.StartInfo.Arguments = "/c java -Xms512M -Xmx1G -XX:MaxPermSize=128M -XX:+UseConcMarkSweepGC -jar spigot.jar";
p.Start();
// reading to the end of its redirected stream.
output = p.StandardOutput.ReadToEnd();
// Can't do this because it only happens when the program
// is exited and won't work cross-thread
//textBox1.Text += output;
}
// Can't use this either because it will repeat messages
// and it's still cross-thread
//public void loop()
//{
//bool update = true;
//while (update == true)
//{
//textBox1.Text += output;
//}
//}
如果没看过代码,基本上我的主要问题是不能跨线程更新文本框,不能使用循环,因为会重复消息,所以我不知道该怎么办。
我是 c# 表单的新手,我找不到关于如何制作批处理包装器的任何结果。
调用 textBox1.Invoke
可能是在您的情况下更新 GUI 控件的关键:
public partial class Form1 : Form
{
private object _sync;
private ConcurrentQueue<string> _outputs;
private bool _running;
private delegate void OutputHandler(string line);
private OutputHandler _append;
public Form1()
{
InitializeComponent();
_sync = new Object();
_outputs = new ConcurrentQueue<string>();
_append = new OutputHandler(line => {
textBox1.AppendText(line + "\r\n");
});
}
private void button1_Click(object sender, EventArgs e)
{
var p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.OutputDataReceived += p_OutputDataReceived;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c @echo off";
p.StartInfo.Arguments = "/c java -Xms512M -Xmx1G -XX:MaxPermSize=128M -XX:+UseConcMarkSweepGC -jar spigot.jar";
p.Start();
p.BeginOutputReadLine();
lock(_sync)
{
_running = true;
}
p.Exited += p_Exited;
Task.Run(() => UpdateOutput());
}
void p_Exited(object sender, EventArgs e)
{
lock(_sync)
{
_running = false;
}
}
void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if(e.Data != null)
{
_outputs.Enqueue(e.Data);
}
}
private async Task UpdateOutput()
{
await Task.Run(() =>
{
var running = _running;
while (running)
{
var line = default(string);
if (_outputs.TryDequeue(out line))
{
try
{
textBox1.Invoke(_append, line);
}
catch
{
}
}
lock (_sync)
{
running = _running;
}
}
});
}
}
我运行一个服务器是一个jar文件,通过批处理执行。我试图为它制作一个包装器,但我找不到一种方法让批处理文件的输出在文本框上实时更新。
目前我使用的代码如下所示:
public partial class Form1 : Form
{
string output = "Server has not been started yet...";
public void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(batch); // Kick off a new thread
t.Start(); // Running batch()
Thread l = new Thread(loop);
l.Start(); //Running loop
}
// This will run the batch file in the background
public void batch()
{
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c @echo off";
p.StartInfo.Arguments = "/c java -Xms512M -Xmx1G -XX:MaxPermSize=128M -XX:+UseConcMarkSweepGC -jar spigot.jar";
p.Start();
// reading to the end of its redirected stream.
output = p.StandardOutput.ReadToEnd();
// Can't do this because it only happens when the program
// is exited and won't work cross-thread
//textBox1.Text += output;
}
// Can't use this either because it will repeat messages
// and it's still cross-thread
//public void loop()
//{
//bool update = true;
//while (update == true)
//{
//textBox1.Text += output;
//}
//}
如果没看过代码,基本上我的主要问题是不能跨线程更新文本框,不能使用循环,因为会重复消息,所以我不知道该怎么办。
我是 c# 表单的新手,我找不到关于如何制作批处理包装器的任何结果。
调用 textBox1.Invoke
可能是在您的情况下更新 GUI 控件的关键:
public partial class Form1 : Form
{
private object _sync;
private ConcurrentQueue<string> _outputs;
private bool _running;
private delegate void OutputHandler(string line);
private OutputHandler _append;
public Form1()
{
InitializeComponent();
_sync = new Object();
_outputs = new ConcurrentQueue<string>();
_append = new OutputHandler(line => {
textBox1.AppendText(line + "\r\n");
});
}
private void button1_Click(object sender, EventArgs e)
{
var p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.OutputDataReceived += p_OutputDataReceived;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c @echo off";
p.StartInfo.Arguments = "/c java -Xms512M -Xmx1G -XX:MaxPermSize=128M -XX:+UseConcMarkSweepGC -jar spigot.jar";
p.Start();
p.BeginOutputReadLine();
lock(_sync)
{
_running = true;
}
p.Exited += p_Exited;
Task.Run(() => UpdateOutput());
}
void p_Exited(object sender, EventArgs e)
{
lock(_sync)
{
_running = false;
}
}
void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if(e.Data != null)
{
_outputs.Enqueue(e.Data);
}
}
private async Task UpdateOutput()
{
await Task.Run(() =>
{
var running = _running;
while (running)
{
var line = default(string);
if (_outputs.TryDequeue(out line))
{
try
{
textBox1.Invoke(_append, line);
}
catch
{
}
}
lock (_sync)
{
running = _running;
}
}
});
}
}