cmd in Appi mit GUI

Plattformunabhängige GUIs mit wxWidgets.
Antworten
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Samstag 27. Mai 2006, 13:19

Hallo Zusammen...

Ich habe wiedermal ein Problem ^^

Bis jetzt erstelle ich ein archiv mit WinRar (cmd Version), was allerdings ein cmd Fenster aufruft, welches auch nicht geschlossen werden kann.

Ich möchte das die Ausgabe nicht in die CMD erfolgt sondern in Ein TextCtrl.

Zusätzlich sollte es möglich sein die CMD irgend wie "abzuschiessen". Was benötigt wird, falls der Benutzer die Anwendung abbrechen möchte...

Gibts so was???

mfG
DM

Bild
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Samstag 27. Mai 2006, 14:06

Guck dir mal das Modul subprocess ([wiki]Neue_Features#Subprocess[/wiki]) an, damit kannst du den inhalt des CMDs auslesen und das CMD gar nicht erst öffnen.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Samstag 27. Mai 2006, 14:46

DatenMetzgerX hat geschrieben:Bis jetzt erstelle ich ein archiv mit WinRar (cmd Version), was allerdings ein cmd Fenster aufruft, welches auch nicht geschlossen werden kann.
[...]
Zusätzlich sollte es möglich sein die CMD irgend wie "abzuschiessen". Was benötigt wird, falls der Benutzer die Anwendung abbrechen möchte...
Hi DatenMetzgerX!

Ich rate dir von RAR ab. Warum? Wir haben erst vor Kurzem die Kompression unserer Server-Datensicherungen von RAR auf GZip umgestellt. Der Unterschied? Die Kompression ist nicht mehr ganz so gut, dafür dauert die Sicherung nicht mehr so lange.

Hier ein Vergleich:

Unser Testobjekt -- eine MSSQL-Datenbanksicherung in der Größe von 40 GB.

- Winzip: ca. 31min (kein direktes Spanning), Spanning auf 650MB-Teile ca. 10min

- ARJ: keine Dateien über 1GB -> untauglich

- WinRAR: Packzeit über 2,5 Std. -> untauglich

- GZip: ca. 26min

Ich empfehle dir das Python-Modul "tarfile" http://www.python.org/doc/current/lib/tar-examples.html da es auch mit "GZip" gepackte archive erstellen und lesen kann. Außerdem bestimmst du jedes File, das in das Tarfile gepackt wird und kannst diesen Vorgang **jederzeit** selber unterbrechen. Du musst also kein Signal an irgend ein DOS-Programm schicken.

mfg
Gerold
:-)

Edit: Komma am Ende eines Links weggenommen.
Zuletzt geändert von gerold am Samstag 27. Mai 2006, 15:00, insgesamt 2-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Samstag 27. Mai 2006, 14:49

Das wär doch was :))

Nimm bei deinem Link am schluss noch das Komma weg, könnte einige irritieren :D

Noch eine frage zu subprocess. Ist es möglich aus stdout Zeile für Zeile zu lesen. Macht keinen Sinn wenn ich 6h warte und nie sehe wie weit er ist und am schluss sehe ich für 1-2s noch die Meldungen ^^
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Samstag 27. Mai 2006, 20:48

Das Problem ist.... Das ganze Backup muss auch subversion unterstützen. Und da gibt es einen CMD-Befehl. Und das sollte auch in die GUI, und darum brauche ich das andere....

Und die GZ archive werden einfach extrem gross :roll:
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Samstag 27. Mai 2006, 22:52

DatenMetzgerX hat geschrieben:... Und das sollte auch in die GUI, und darum brauche ich das andere....
Und die GZ archive werden einfach extrem gross :roll:
Hi DatenMetzgerX!

Ich will dich nicht davon abhalten, RAR zu benutzen... :?

Hier wieder ein kleines Beispiel. Allerdings mit UNIX-Pfaden. Die Pfade musst du selber an Windows anpassen, da ich gerade KDE kompiliere und nicht zwischendurch mal Windows booten kann.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import wx
import threading
import time
import os


# NewMessageEvent
EVT_NEWMESSAGE_ID = wx.NewId()
class NewMessageEvent(wx.PyEvent):
    """
    Simple event
    """
    def __init__(self, message):
        """
        Init Event.
        """
       
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_NEWMESSAGE_ID)
        self.message = message


# StopEvent
EVT_STOP_ID = wx.NewId()
class StopEvent(wx.PyEvent):
    """
    Simple event
    """
    def __init__(self):
        """
        Init Event.
        """
       
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_STOP_ID)


class MyFrame(wx.Frame):
    """
    Hauptframe
    """
   
    def __init__(
        self, parent = None, title = "Hauptframe"
    ):
       
        # Frame initialisieren
        wx.Frame.__init__(self, parent, -1, title)
       
        # Ein Panel als Grundlage
        panel = wx.Panel(self)
       
        # Ein vertikaler Boxsizer zum Anordnen
        vb = wx.BoxSizer(wx.VERTICAL)
        panel.SetSizer(vb)
       
        # Ein Textfeld für die Ausgabe der Statusmeldungen (read only)
        self.messages = wx.TextCtrl(
            panel, -1,
            style = wx.TE_AUTO_SCROLL | wx.TE_LINEWRAP |
                    wx.TE_MULTILINE | wx.TE_READONLY
        )
        font = self.messages.GetFont()
        font.SetFamily(wx.FONTFAMILY_SCRIPT)
        self.messages.SetFont(font)
        
        vb.Add(self.messages, 1, wx.ALL | wx.EXPAND, 5)
       
        # Buttonleiste
        hb = wx.BoxSizer(wx.HORIZONTAL)
        vb.Add(hb, 0, wx.EXPAND)
       
        # Start
        self.start_btn = wx.Button(panel, -1, "Start")
        hb.Add(self.start_btn, 1, wx.ALIGN_CENTER_HORIZONTAL| wx.ALL, 5)
        self.start_btn.Bind(wx.EVT_BUTTON, self.start_thread)
        self.start_btn.SetDefault()
       
        # Thread-Variablen vorbereiten
        self.myworkerthread = None
        self.thread_started = False
       
        # NewMessage-Event und Stop-Event binden
        self.Connect(-1, -1, EVT_NEWMESSAGE_ID, self.add_message)
        self.Connect(-1, -1, EVT_STOP_ID, self.stop_signal_empfangen)
   
   
    def add_message(self, event = None, message = None):
        """
        Fügt an den Text eine neue Zeile mit der neuen Nachricht an.
        """
       
        if event:
            message = str(event.message)
       
        if len(self.messages.GetValue()) > 0:
            message = "\n" + message
        self.messages.AppendText(message)
        self.messages.ScrollLines(10)
   
   
    def start_thread(self, event = None):
        """
        Startet den Thread
        """
       
        # Prüfen ob der Thread schon läuft
        if self.thread_started:
            self.add_message(message = u"Der Thread läuft bereits...")
            return
        
        # Log-Feld leeren und Button deaktivieren
        self.messages.Clear()
        self.start_btn.Enable(False)
        
        # Thread initialisieren
        self.myworkerthread = MyWorkerThread(self)
       
        # Thread starten
        self.myworkerthread.start()
       
        # Variable setzen und Nachricht ausgeben
        self.thread_started = True
        self.add_message(message = u"Der Thread wurde soeben gestartet...")

   
    def stop_signal_empfangen(self, event = None):
        """
        Zeigt an, dass er fertig ist.
        """
       
        self.thread_started = False
        self.add_message(message = "Fertig...")
        wx.MessageBox(u"Fertig!", "Fertig", wx.OK | wx.CENTER, self)
        self.start_btn.Enable(True)



class MyWorkerThread(threading.Thread):
    """
    Diese Klasse soll Arbeit erledigen, aber nichts anzeigen.
    """
   
    def __init__(self, notify_window):
        """
        Initialisiert die Klasse und
        übernimmt das Objekt, an das später die Events geschickt werden.
        """
       
        threading.Thread.__init__(self)
       
        self._notify_window = notify_window
   
   
    def run(self):
        """
        Thread-Hauptprozedur
        """
        
        out = os.popen("rar a -idp hallo.rar /bin", "r", 0)
        
        for line in out:
            # Event an den Frame schicken
            wx.PostEvent(
                self._notify_window, NewMessageEvent(line.strip())
            )
       
        # Event zum Stoppen an Frame schicken
        wx.PostEvent(self._notify_window, StopEvent())



def main():
    """
    Hauptprozedur
    """
   
    app = wx.PySimpleApp()
    frame = MyFrame()
    frame.SetSize((600, 500))
    frame.Show()
    frame.Center()
    app.MainLoop()


if __name__ == "__main__":
    main()
lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Samstag 27. Mai 2006, 22:57

PS: Die Anzeigedaten kommen vom WinRAR nicht zeilenweise. Da ist ein Cache dazwischen. Den kannst du nicht umgehen. Also gar nicht erst fragen. Bringt nichts.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Sonntag 28. Mai 2006, 16:21

Ich glaube ich verstehe das ganze so einigermassen....

Nur, jetzt beendet ja der MyWorkerThread die GUI.

Code: Alles auswählen

frame.Bind(wx.EVT_CLOSE, lambda event: backupf.abort(app, frame,Appli))
Wenn die GUI geschlossen wird, sollte ja nicht noch der MyWorkerThread laufen, der soll auch beendet werden.

Momentan habe ich das ganz hässlich gelöst...

Code: Alles auswählen

    Appli.UserExit=1
    frame.SetError("Anwendung wird beendet")
          
    while Appli.isAlive():
        time.sleep(1)
    frame.Destroy()
Vor jedem Durchgang wo ich etwas kopiere / Archiviere... prüfe ich ob Appli.UserExit auf 1 ist oder nicht.

Problem z.B bei WinRar archiven, das ich subprocess nicht so schnell beenden kann, besser gesagt gar nicht...

Mir ist gerade aufgefallen das ich jetzt 2 Sachen aus 2 verschiedenen Treads frage :roll:
Antworten