如何在C#WinForm中嵌入交互式python进程

2024-10-02 14:21:44 发布

您现在位置:Python中文网/ 问答频道 /正文

问题

我试图以System.Diagnostics.Process的形式启动Python,并将其标准输出、输入和错误重定向到Windows窗体上的RichTextBox,这样我就可以在我的窗体上使用Python REPL。在

进程正确启动(Start()返回true),但进程从未发送任何输出或错误数据:

  • 如果我试图从StandardOutputStandardErrorRead,那么读操作就会挂起。在
  • 如果我改为订阅OutputDataReceivedErrorDataReceived,它们永远不会触发。在

started with ProcessStartInfo("Python.exe")

只有当我通过发送Ctrl + C(在asd行尾按Enter后发送,因此是第三行)时,我才会看到python的输出。在

为了澄清这一点,我希望看到在输入“1+1”后按enter键之后从python发送的“2”(无论是从读取StandardOutput流还是在数据事件中)。在

为什么python执行时没有数据发送到标准输出,也没有引发事件?是否可以按我的要求进行此工作(以便立即从python获得响应)。

附加

如果我改为启动cmd.exe,那么一切都很好,我可以像使用常规命令提示符一样使用这个表单。所以在某种程度上我的应用程序是有效的。在

但是如果我尝试使用这个表单启动python,那么它就会挂起,直到我像以前一样发送Ctrl + C来终止进程:

started with ProcessStartInfo("cmd.exe")

很明显,标准输入正在进入python(因为python错误消息报告的行号取决于它前面的行数)

我正在使用: Python 3.5.2 |Anaconda 4.2.0 (64-bit)| (default, Jul 5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)] on win32

再说一遍: 为什么直到任何标准的python都发出强数据?我要怎么做?

代码

其中一些遵循的模式是www.codeproject.com/Articles/335909/Embedding-a-Console-in-a-C-Application在

设置

var processStartInfo = new ProcessStartInfo("python.exe");
processStartInfo.UseShellExecute = false;
processStartInfo.ErrorDialog = false;
processStartInfo.RedirectStandardError = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.CreateNoWindow = true;
process = new Process();
process.StartInfo = processStartInfo;
bool processStarted = process.Start();
outputReader = process.StandardOutput;
errorReader = process.StandardError;
inputWriter = process.StandardInput;

// start reading from standard output
outputWatchWorker.WorkerSupportsCancellation = true;
outputWatchWorker.DoWork += (o, e) =>
{
    while (!outputWatchWorker.CancellationPending)
    {
        int nChars = 0;
        string str;
        char[] buffer = new char[1024];
        nChars = outputReader.Read(buffer, 0, buffer.Length);
        if (nChars > 0)
        {
            str = new string(buffer, 0, nChars);
            Invoke((MethodInvoker)(() =>
            {
                WriteOutput(str, Color.Black);
            }));
        }
    }
};
outputWatchWorker.RunWorkerAsync();

// I've removed an almost identical block of code for errorWatchWorker to read from the error stream

RichTextBox

^{pr2}$

写入输出

public void WriteOutput(string output, Color color)
{
    if (string.IsNullOrEmpty(lastInput) == false &&
        (output == lastInput || output.Replace("\r\n", "") == lastInput))
        return;

    Invoke((Action)(() =>
    {
        //  Write the output.
        textConsole.SelectionColor = color;
        textConsole.AppendText(output);
        inputStart = textConsole.SelectionStart;
    }));
}

“Ctrl+C”按钮的单击侦听器发送Ctrl+C

就是这样

inputWriter.WriteLine("\x3");

基于这个问题How do I send ctrl+c to a process in c#?


Tags: 数据truenewoutput标准string进程buffer