简体   繁体   English

C#WPF应用程序捕获python脚本控制台输出

[英]C# WPF application capture python script console output

I have been trying for hours to figure out how to do this but I have a python script that was made into an exe so it acts a console application I'm trying to write a GUI wrapper for it using WPF I have it set up to where it does execute the exe with the command arguments but I want to capture the output from the console and display it in a text box and i can not figure it out. 我已经尝试了数小时,以找出解决方法,但是我将python脚本编写为exe文件,因此它可以充当控制台应用程序,而我正在尝试使用WPF为它编写GUI包装程序,它确实使用命令参数执行exe,但我想从控制台捕获输出并在文本框中显示它,但我无法弄清楚。 I have tried multiple code snippets but it either does nothing, Outputs after the python exe has finished, or locks up the GUI until the python exe finishes then dumps the completed output to the textbox. 我尝试了多个代码段,但它要么不执行任何操作,要么在python exe完成后输出,要么锁定GUI,直到python exe完成,然后将完成的输出转储到文本框中。

Would someone be able to take a look and see if they can help me with this? 有人可以看一看,看看他们是否可以帮助我?

public partial class MainWindow : Window


{

    //string output = string.Empty;
    private static StringBuilder output = new StringBuilder();
    private object syncGate = new object();
    private Process process;
    private bool outputChanged;


    public MainWindow()
    {
        InitializeComponent();
    }

    private void RB_Mii_Checked(object sender, RoutedEventArgs e)
    {   
    }

    //If we click the button we copy the bin file to the work directory
    private void btn_SelMiiQR_Click(object sender, RoutedEventArgs e)
    {
        //Copy the encrypted.bin file to the working directory
        OpenFileDialog openFileDialog = new OpenFileDialog();
        openFileDialog.Filter = "Input.bin (*.bin)|*.bin|All files (*.*)|*.*";
        openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        if (openFileDialog.ShowDialog() == true)
        {
            var fileName = openFileDialog.FileName;
            String exePath = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
            //If the file exists delete the existing file and copy the newone.
            if (System.IO.File.Exists(System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName)))
            {
                System.IO.File.Delete(System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName));
            }
                System.IO.File.Copy(fileName, System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName));
        }

    }

    //If the button was clicked use the input.bin file and attempt to brute force the movable_sedpart1.bin
    private void BTN_MIIBF_Click(object sender, RoutedEventArgs e)
    {
        //If the mfg has input year or no input use it
        if (TB_MFGYR.Text.Length == 0 || TB_MFGYR.Text.Length == 4)
        {
            string DStype = null;
            string MFGYR = null;
            //Grab the Year if it has value
            if (TB_MFGYR.Text.Length == 4)
            {
                 MFGYR = TB_MFGYR.Text;
            }
            else
            {
                MFGYR = null;
            }

            if (RB_N3ds.IsChecked == true)
            {
                DStype = "new";
            }

            else if (RB_O3DS.IsChecked == true)
            {
                DStype = "old";
            }


            //Execute Command with Arguments
            String exePath = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
            string dir = System.IO.Path.GetDirectoryName(exePath)+"\\App\\";

            //Start the process and export thr console output to the textbox
            CreateProcess(dir + "seedminer_launcher.exe", "Mii " + DStype + " " + MFGYR, dir);


        }
        //Else display Error Message WIP
        else
        {
            tb_outputtext.Text = null;
            tb_outputtext.Text = "MFG Year must have 4 characters or none";
        }
    }

    //Execute a new process
    private void CreateProcess(string fileName, string arguments, string workdir)
    {
        // Process process = new Process();
        process = new Process();
        process.StartInfo.FileName = fileName;
        process.StartInfo.Arguments = arguments;
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardError = true;
        process.StartInfo.WorkingDirectory = workdir;
        process.OutputDataReceived += proc_OutputDataReceived;


        process.Start();
        process.BeginOutputReadLine();

    }

    void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        this.Dispatcher.Invoke((Action)(() =>
        {
            tb_outputtext.Text = tb_outputtext.Text + "\n" + e.Data;
            tb_outputtext.ScrollToEnd();
        }));

    }


    private void ReadData()
    {
        var input = process.StandardOutput;
        int nextChar;
        while ((nextChar = input.Read()) >= 0)
        {
            lock (syncGate)
            {
                output.Append((char)nextChar);
                if (!outputChanged)
                {
                    outputChanged = true;
                    var dispatcher = Application.Current.MainWindow.Dispatcher;
                    Dispatcher.BeginInvoke(new Action(OnOutputChanged));
                }
            }
        }
        lock (syncGate)
        {
            process.Dispose();
            process = null;
        }
    }

    private void OnOutputChanged()
    {
        lock (syncGate)
        {
            tb_outputtext.AppendText(output.ToString());
            outputChanged = false;
        }
    }


}

If I understand you correctly then you want your WPF app to continously update the content ot the TextBox while your python executable is running? 如果我理解正确,那么您希望WPF应用程序在python可执行文件运行时不断更新TextBox的内容吗?

I have stripped down your code and used the Windows command ping -t 127.0.0.1 -w 10000 which generates a new line every second to test your code. 我已经精简了您的代码,并使用Windows命令ping -t 127.0.0.1 -w 10000每秒生成一条新行来测试您的代码。 On my machine your code works as expected: the output in the WPF textbox is updated every second. 在我的机器上,您的代码可以按预期工作:WPF文本框中的输出每秒更新一次。

What happens if you replace the ping command with your python executable in the code below? 如果在下面的代码中用python可执行文件替换ping命令,会发生什么情况? Does your python script output a newline character after each line (as mentioned in Process.OutputDataReceived Event )? 您的python脚本是否在每行之后输出换行符(如Process.OutputDataReceived Event中所述 )?

MainWindow.xaml.cs MainWindow.xaml.cs

using System;
using System.Diagnostics;
using System.Windows;

namespace SO_Continous_Process_Output
{
    public partial class MainWindow : Window
    {
        private Process process;

        public MainWindow()
        {
            InitializeComponent();

            CreateProcess("ping", "-t 127.0.0.1 -w 1000", "");
        }

        //Execute a new process
        private void CreateProcess(string fileName, string arguments, string workdir)
        {
            // Process process = new Process();
            process = new Process();
            process.StartInfo.FileName = fileName;
            process.StartInfo.Arguments = arguments;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.WorkingDirectory = workdir;
            process.OutputDataReceived += proc_OutputDataReceived;

            process.Start();
            process.BeginOutputReadLine();
        }

        void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            this.Dispatcher.Invoke((Action)(() =>
            {
                tb_outputtext.Text = tb_outputtext.Text + "\n" + e.Data;
                tb_outputtext.ScrollToEnd();
            }));
        }
    }
}

MainWindow.xaml MainWindow.xaml

<Window x:Class="SO_Continous_Process_Output.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Name="tb_outputtext" Text="{Binding ProcessOutput}"></TextBox>
    </Grid>
</Window>

Update 更新资料

Python script Python脚本

I wrote a python script to test if the output works and I had to set flush=True in order to make it work. 我编写了一个python脚本来测试输出是否有效,并且必须设置flush=True才能使其正常工作。

import time

while True:
    print('hi!', flush=True)
    time.sleep(1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM