【问题标题】:Stream Console process output to Textbox In real - Time流控制台进程实时输出到文本框
【发布时间】:2015-09-18 10:52:07
【问题描述】:

我对 C# 和 Windows 窗体编程非常陌生。 我正在尝试构建一个非常非常简单的表单。 我只有一个按钮和一个文本框,当我单击按钮时,会在后台启动一个进程(这是我用 Python 编程并编译为 EXE 文件的进程),这是一个非常简单的过程......只需打印从 1 到4 在每个数字之间有 2 秒的延迟 我希望输出实时显示在文本框中,这意味着 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)
            {
                //?????
            }
        }
    }

【问题讨论】:

  • 你的 python exe 直接运行时在哪里打印数字。从命令提示符执行 python exe 时,你得到它的输出吗?
  • 为什么您从示例代码中删除了sortProcess.OutputDataReceived +=...sortProcess.BeginOutputReadLine();?这对于解决方案至关重要。
  • @amit dayama:当我在控制台(cmd)中运行它时,我将 python 代码编译为 exe 文件,它打印 1...2...3..4,每个之间有 2 秒的延迟号码
  • @Ivan Stoev 我不太了解 c#,但我提到的线程中的代码肯定不能正常工作,所以我试着玩了一下.. 没有运气
  • 下面我的呢?

标签: c#


【解决方案1】:

Process.BeginOutputReadLine 方法结合Process.OutputDataReceived 事件提供了完全适合 UI 组件架构的异步行为。您不需要像在引用的线程中那样使用Application.DoEevents 调用阻塞WaitForExit 或奇怪的while 循环。您只需要附加一个事件处理程序,调用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;
            }
        }
    }
}

EDIT 上述方法仅适用于行,看起来您的 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;
            }
        }
    }
}

【讨论】:

  • ...对不起,但它不起作用..仍然是同样的问题..所有输出都是在过程结束后打印的,而不是实时打印
  • 没有人仍然没有工作......我的python代码非常简单,只需在2秒延迟内打印数字我使用pyinstaller将它编译为EXE文件......我可以从CMD运行它只需输入程序的名称..您的代码在进程结束时打印输出 8 秒后而不是在运行时...我可以以某种方式向您发送 EXE 文件吗?谢谢
  • 不,抱歉 - 我要起飞了。显然你的 python exe 有问题。在发布我的两个答案中的任何一个之前,我已经制作了一个简单的 C# Console exe 应用程序来执行您所解释的操作,并且两个代码 sn-ps 都可以工作。祝你好运。
  • 对不起。但我认为错误是在你这边..我做了一个非常简单的 Python 代码并编译为 EXE ......你的代码在过程完成后打印程序输出。无论如何谢谢..我希望有人能帮助我解决这个非常简单的问题
【解决方案2】:

我发现了 Ivan Stoev 的回复中提到的问题。文本框仅在进程结束后更新。

事实上,代码与批处理文件配合得很好。但是我在使用 python 代码时遇到了同样的问题。问题实际上出在python代码中。打印后,您必须刷新 fflush(stdout)。

所以在我的 python 代码中,我只需要添加:

print("Something", flush=True)

现在可以了!

【讨论】:

  • 使用 -u 选项(无缓冲)运行 python 往往是更简单的解决方案。
猜你喜欢
  • 1970-01-01
  • 2014-03-13
  • 2016-05-10
  • 1970-01-01
  • 2013-02-22
  • 2011-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多