我在C#和Windows窗体编程方面非常陌生。 我试图构建一个非常简单的表单。 我只有一个按钮和一个文本框,当我点击按钮时,一个进程从后台开始(它是我在Python中编程并编译为EXE文件的进程),这是一个非常简单的过程。只需在每个数字之间以2秒的延迟打印1到4的数字 我希望输出实时显示在文本框中,意味着2秒延迟中的数字1到4。 我在网上搜索并搜索了很多,但找不到任何可以帮助我的东西。 我读了这个帖子 - > How can I redirect process output (console) to richtextbox? 并试图实现写在那里没有运气的东西 非常感谢! 这是我的代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private StringBuilder sortOutput;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
String output="";
using (Process sortProcess = new Process())
{
sortProcess.StartInfo.FileName = @"c:/req/dist/ex/ex.exe";
sortProcess.StartInfo.CreateNoWindow = true;
sortProcess.StartInfo.UseShellExecute = false;
sortProcess.StartInfo.RedirectStandardOutput = true;
sortProcess.Start();
output = sortProcess.StandardOutput.ReadLine();
// sortProcess.WaitForExit();
while (!(sortProcess.HasExited))
{
richTextBox1.AppendText(output.ToString());
Application.DoEvents(); // This keeps your form responsive by processing events
}
}
//richTextBox1.AppendText(sortOutput.ToString());
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
//?????
}
}
}
答案 0 :(得分:1)
Process.BeginOutputReadLine
方法与Process.OutputDataReceived
事件相结合,可提供完全适合UI组件体系结构的异步行为。您不需要像引用的帖子那样使用WaitForExit
来调用阻塞while
或奇怪的Application.DoEevents
循环。您所需要的只是附加一个事件处理程序,调用BeginOutputReadLine
并处理事件中接收的数据。唯一棘手的(但同时是UI代码的标准)部分是确保UI仅从UI线程更新并进行一些线程同步。像这样:
using System;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private object syncGate = new object();
private Process process;
private StringBuilder output = new StringBuilder();
private bool outputChanged;
private void button1_Click(object sender, EventArgs e)
{
lock (syncGate)
{
if (process != null) return;
}
output.Clear();
outputChanged = false;
richTextBox1.Text = "";
process = new Process();
process.StartInfo.FileName = @"c:/req/dist/ex/ex.exe";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += OnOutputDataReceived;
process.Exited += OnProcessExited;
process.Start();
process.BeginOutputReadLine();
}
private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
lock (syncGate)
{
if (sender != process) return;
output.AppendLine(e.Data);
if (outputChanged) return;
outputChanged = true;
BeginInvoke(new Action(OnOutputChanged));
}
}
private void OnOutputChanged()
{
lock (syncGate)
{
richTextBox1.Text = output.ToString();
outputChanged = false;
}
}
private void OnProcessExited(object sender, EventArgs e)
{
lock (syncGate)
{
if (sender != process) return;
process.Dispose();
process = null;
}
}
}
}
编辑上述方法仅适用于行,看起来你的python exe输出字符。这是一个应该适用于该场景的修改版本:
using System;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private object syncGate = new object();
private Process process;
private StringBuilder output = new StringBuilder();
private bool outputChanged;
private void button1_Click(object sender, EventArgs e)
{
lock (syncGate)
{
if (process != null) return;
}
output.Clear();
outputChanged = false;
richTextBox1.Text = "";
process = new Process();
process.StartInfo.FileName = @"c:/req/dist/ex/ex.exe";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
new Thread(ReadData) { IsBackground = true }.Start();
}
private void ReadData()
{
var input = process.StandardOutput;
int nextChar;
while ((nextChar = input.Read()) >= 0)
{
lock (syncGate)
{
output.Append((char)nextChar);
if (!outputChanged)
{
outputChanged = true;
BeginInvoke(new Action(OnOutputChanged));
}
}
}
lock (syncGate)
{
process.Dispose();
process = null;
}
}
private void OnOutputChanged()
{
lock (syncGate)
{
richTextBox1.Text = output.ToString();
outputChanged = false;
}
}
}
}
答案 1 :(得分:0)
我发现Ivan Stoev的回复中提到了该问题。文本框仅在过程结束后更新。
实际上,该代码与批处理文件配合得很好。但是我在使用python代码时遇到了同样的问题。问题实际上出在python代码中。打印后,必须冲洗fflush(stdout)。
所以在我的python代码中,我只需要添加:
print(“ Something”,flush = True)
现在工作了!