Führen Sie Python-Skripte in C # -GUI-Anwendungen aus

Einführung

Python hat viele großartige Bibliotheken, einschließlich maschinelles Lernen. Andererseits ist C # eine weit verbreitete Sprache für die Entwicklung von GUI-Anwendungen. Daher wäre es für C # -Anwendungsentwickler praktisch, Python-Skripte aus C # -Anwendungen aufrufen zu können, und vor allem sollte der Bereich der GUI-Anwendungen erweitert werden. Dieses Mal habe ich untersucht, wie ein Python-Skript aus einer C # -GUI-Anwendung aufgerufen werden kann, und einen Prototyp erstellt.

Umgebung

Prototyp, den Sie entwickeln möchten

Ich habe die Anforderungen für den Prototyp identifiziert, den ich unten entwickeln möchte.

Was wurde gemacht

Bildschirm

So was. image.png

Bildschirmbeschreibung

Quelle

Die Quelle ist wie folgt. Es ist sehr lang, aber es ist umständlich zu bearbeiten, also füge ich es einfach ein (ausschneiden). Der Code auf der Design-Seite wird weggelassen. Bitte lesen Sie den Variablennamen des Objekts des GUI-Teils aus dem Code. Die Quelle wird im nächsten Abschnitt erläutert.

using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace PythonCommandExecutor
{

    public partial class Form1 : Form
    {
        private Process currentProcess;
        private StringBuilder outStringBuilder = new StringBuilder();
        private int readCount = 0;
        private Boolean isCanceled = false;

        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        ///Fügen Sie der Textbox eine Zeichenfolge hinzu
        /// </summary>
        public void AppendText(String data, Boolean console)
        {
            textBox1.AppendText(data);
            if (console)
            {
                textBox1.AppendText("\r\n");
                Console.WriteLine(data);
            }
        }

        /// <summary>
        ///Verhalten beim Klicken auf die Schaltfläche Ausführen
        /// </summary>
        private void button1_Click(object sender, EventArgs e)
        {
            //Vorverarbeitung
            button1.Enabled = false;
            button2.Enabled = true;
            isCanceled = false;
            readCount = 0;
            outStringBuilder.Clear();
            this.Invoke((MethodInvoker)(() => this.textBox1.Clear()));

            //Lauf
            RunCommandLineAsync();
        }

        /// <summary>
        ///Hauptteil des Befehlsausführungsprozesses
        /// </summary>
        public void RunCommandLineAsync()
        {

            ProcessStartInfo psInfo = new ProcessStartInfo();
            psInfo.FileName = this.textBox2.Text.Trim();
            psInfo.WorkingDirectory = this.textBox3.Text.Trim();
            psInfo.Arguments = this.textBox4.Text.Trim();

            psInfo.CreateNoWindow = true;
            psInfo.UseShellExecute = false;
            psInfo.RedirectStandardInput = true;
            psInfo.RedirectStandardOutput = true;
            psInfo.RedirectStandardError = true;

            // Process p = Process.Start(psInfo);
            Process p = new System.Diagnostics.Process();
            p.StartInfo = psInfo;

            p.EnableRaisingEvents = true;
            p.Exited += onExited;
            p.OutputDataReceived += p_OutputDataReceived;
            p.ErrorDataReceived += p_ErrorDataReceived;

            p.Start();

            //Schreiben Sie in die Standardeingabe
            using (StreamWriter sw = p.StandardInput)
            {
                sw.Write(this.textBox5.Text.Trim()); 
            }

            //Starten Sie das asynchrone Lesen von Ausgabe und Fehler
            p.BeginOutputReadLine();
            p.BeginErrorReadLine();

            currentProcess = p;
        }

        void onExited(object sender, EventArgs e)
        {
            int exitCode;

            if (currentProcess != null)
            {
                currentProcess.WaitForExit();

                //Ausatmen von Daten, die ohne Ausatmen verbleiben
                this.Invoke((MethodInvoker)(() => AppendText(outStringBuilder.ToString(), false)));
                outStringBuilder.Clear();

                exitCode = currentProcess.ExitCode;
                currentProcess.CancelOutputRead();
                currentProcess.CancelErrorRead();
                currentProcess.Close();
                currentProcess.Dispose();
                currentProcess = null;

                this.Invoke((MethodInvoker)(() => this.button1.Enabled = true));
                this.Invoke((MethodInvoker)(() => this.button2.Enabled=false));


                if (isCanceled)
                {
                    //Abschlussmeldung
                    this.Invoke((MethodInvoker)(() => MessageBox.Show("Bearbeitung abgebrochen")));
                }
                else
                {
                    if (exitCode == 0)
                    {
                        //Abschlussmeldung
                        this.Invoke((MethodInvoker)(() => MessageBox.Show("Die Verarbeitung ist abgeschlossen")));
                    }
                    else
                    {
                        //Abschlussmeldung
                        this.Invoke((MethodInvoker)(() => MessageBox.Show("Ein Fehler ist aufgetreten")));
                    }
                }
            }
        }

        /// <summary>
        ///Verarbeitung beim Empfang von Standardausgabedaten
        /// </summary>
        void p_OutputDataReceived(object sender,
            System.Diagnostics.DataReceivedEventArgs e)
        {
            processMessage(sender, e);
        }

        /// <summary>
        ///Was tun, wenn ein Standardfehler empfangen wird?
        /// </summary>
        void p_ErrorDataReceived(object sender,
            System.Diagnostics.DataReceivedEventArgs e)
        {
            processMessage(sender, e);
        }

        /// <summary>
        ///Empfängt CommandLine-Programmdaten und spuckt sie an TextBox aus
        /// </summary>
        void processMessage(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            if (e != null && e.Data != null && e.Data.Length > 0)
            {
                outStringBuilder.Append(e.Data + "\r\n");
            }
            readCount++;
            //Atme zu einem zusammenhängenden Zeitpunkt aus
            if (readCount % 5 == 0)
            {
                this.Invoke((MethodInvoker)(() => AppendText(outStringBuilder.ToString(), false)));
                outStringBuilder.Clear();
                //Stellen Sie den Schlaf so ein, dass er den Faden nicht einnimmt
                if (readCount % 1000 == 0)
                {
                    Thread.Sleep(100);
                }
            }
        }

        /// <summary>
        ///Verhalten beim Klicken auf die Schaltfläche Abbrechen
        /// </summary>
        private void button2_Click(object sender, EventArgs e)
        {
            if (currentProcess != null)
            {
                try
                {
                    currentProcess.Kill();
                    isCanceled = true;
                }
                catch (Exception e2)
                {
                    Console.WriteLine(e2);
                }
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            //Standardeingabebereich löschen
            this.textBox5.Clear();
            //Standardausgabebereich löschen
            this.textBox1.Clear();
        }
    }
}

Quellenkommentar

Es ist im Grunde eine Sammlung von Referenzen, aber die Erklärung ist unten angegeben.

p.BeginOutputReadLine();,p.BeginErrorReadLine();Da jeder Ereignishandler jedes Mal ausgeführt wird, wenn eine Zeile ausgegeben wird, wird die Ausgabe an TextBox darin ausgeführt. Wenn Sie jede Zeile in TextBox schreiben, kann die Verarbeitung der GUI bei einer Anwendung mit einer hohen Ausgabemenge sehr lange dauern. Daher entwickeln wir Möglichkeiten, die gesamte Zeile bis zu einem gewissen Grad gemeinsam auszugeben.




# Ausführungsbeispiel (1) Führen Sie ein Python-Skript mit viel Ausgabe aus (ein Fehler in der Mitte).
 Das folgende Beispiel zeigt die Ausführung eines als Beispiel erstellten Python-Skripts mit einer bestimmten Menge an Standardausgabe und Standardfehlerausgabe. Es ist ersichtlich, dass die an den Standardfehler ausgegebene Fehlermeldung auch an die TextBox ausgegeben wird und die Fehlernachrichtenbox durch den Endcode angezeigt wird.

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329816/f2c9e895-314f-f7e9-795a-2588ca113c6d.png)


# Ausführungsbeispiel (2) Führen Sie das Python-Skript über die Standardeingabe aus
 Das folgende Diagramm zeigt die Ausführung des Skripts "[MOL-Datei über Standardeingabe / -ausgabe in SMILES konvertieren](https://qiita.com/kimisyo/items/c7eb3a6a10298590438e)" über diese GUI. Sie werden feststellen, dass Sie die Verarbeitungsergebnisse von C # und Python nur durch Schreiben eines einfachen Python-Skripts übergeben können.
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329816/f46c8aee-2950-836c-7a00-5d10fad6021d.png)


# abschließend
 - Ich habe anfangs mit der Methode async / await fortgefahren, aber ich habe aufgegeben, weil ein Phänomen aufgetreten ist, das ein Deadlock in der Benutzeroberfläche zu sein schien, und ich konnte es auch nach einem ganzen Tag nicht lösen.
 
 

# 

 
        // Process p = Process.Start(psInfo);
        Process p = new System.Diagnostics.Process();
        p.StartInfo = psInfo;

# 
 
 ――Da die Operation einigermaßen stabil ist, möchte ich eine attraktive App basierend auf diesem Prototyp erstellen, indem ich die praktischen Funktionen von Python aus C # verwende. 2020/2/24 Es wurde wie folgt behoben, da es einen schwerwiegenden Fehler gab, dass der Korrekturprozess zweimal gestartet wurde. Wir entschuldigen uns für die Unannehmlichkeiten. Referenzen- [Prozessklasse](https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process?view=netframework-4.8)-[Wenn Sie eine Standardausgabe erhalten, indem Sie einen asynchronen externen Prozess starten Anmerkungen](https://qiita.com/skitoy4321/items/10c47eea93e5c6145d48)
 - [Starten Sie eine externe Anwendung und warten Sie, bis sie abgeschlossen ist](https://dobon.net/vb/dotnet/process/openfile.html)
 - [Was ist, wenn der Prozess einfriert, wenn das externe Programm ausgeführt wird? ](Https://www.atmarkit.co.jp/fdotnet/dotnettips/805pipeasync/pipeasync.html)



Recommended Posts

Führen Sie Python-Skripte in C # -GUI-Anwendungen aus
Rufen Sie Python-Skripte aus Embedded Python in C ++ / C ++ auf
Führen Sie Python-Skripte in Excel aus (mit xlwings).
Führen Sie das Illustrator-Skript von Python aus
Führen Sie Python-Code über die C # -GUI aus
Führen Sie Python-Skripte synchron von C # aus
So führen Sie ein Python-Programm in einem Shell-Skript aus
Führen Sie den Python-Interpreter im Skript aus
Verwenden Sie Django aus einem lokalen Python-Skript
Führen Sie eine Python-Webanwendung mit Docker aus
So führen Sie Maya Python-Skripte aus
Ich habe eine GUI-App mit Python + PyQt5 erstellt
Erstellen Sie ein C-Array aus einer Python> Excel-Tabelle
Erstellen Sie eine neue Todoist-Aufgabe aus Python Script
Führen Sie Python aus Excel aus
"Python Kit", das Python-Skripte von Swift aufruft
Führen Sie Python-Dateien mit Django aus HTML aus
Ein Memorandum zum Ausführen eines Python-Skripts in einer Bat-Datei
Python zeigt aus der Perspektive eines C-Sprachprogrammierers
Python-Skript, das eine JSON-Datei aus einer CSV-Datei erstellt
[Python] So rufen Sie eine Funktion von c aus Python auf (ctypes edition)
Führen Sie ein mehrzeiliges Skript in einem PDB aus
Führen Sie das Python-Skript aus der Batchdatei aus
Löse ABC163 A ~ C mit Python
Rufen Sie C von Python mit DragonFFI auf
Berühren Sie Python-Objekte in Elixir
ABC127 A, B, C Erklärung (Python)
Erstellen Sie mit tkinter eine Python-GUI
Lassen Sie uns eine GUI mit Python erstellen.
ABC166 in Python A ~ C Problem
Rufen Sie popcount von Ruby / Python / C # auf
Python / Machen Sie ein Diktat aus einer Liste.
Löse ABC168 A ~ C mit Python
Führen Sie Aprili von Python auf Orange aus
Löse ABC036 A ~ C mit Python
Tipps zum Aufrufen von Python von C.
Python-Fehlererkennung von Powershell ausgeführt
Löse ABC162 A ~ C mit Python
Löse ABC167 A ~ C mit Python
ABC128 A, B, C Kommentar (Python)
Löse ABC158 A ~ C mit Python
ABC126 A, B, C Erklärung (Python)
Löse ABC037 A ~ C mit Python
Führen Sie Ansible über Python mithilfe der API aus
Starten Sie das Python-Skript im Dienst
Führen Sie einen einfachen Algorithmus in Python aus
Schreiben Sie ein Batch-Skript mit Python3.5 ~
Rufen Sie C / C ++ von Python auf dem Mac auf
Führen Sie das Python-Skript in Cisco Memorandum_EEM aus
Rufen Sie die c-Sprache von Python aus auf (python.h)
Erstellen Sie ein Shell-Skript, um die Python-Datei mehrmals auszuführen
Rufen Sie dlm von Python aus auf, um ein zeitvariables Koeffizientenregressionsmodell auszuführen
Übergeben Sie die Liste von Python an C ++ als Referenz in pybind11
[Python] Webanwendung von 0! Hands-on (3) -API-Implementierung-
Führen Sie Cloud Dataflow (Python) über AppEngine aus
Löse ABC175 A, B, C mit Python
Führen Sie ein Skript von Jupyter aus, um es zu verarbeiten
Führen Sie ein lokales Skript auf einem Remote-Host aus
Erstellen Sie eine einfache GUI-App in Python