流控制台流程输出到文本框实时

时间:2015-09-18 10:52:08

标签: c#

我在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)
            {
                //?????
            }
        }
    }

2 个答案:

答案 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)

现在工作了!