Frame bleibt bei Fensterwechsel weiß

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

Merci.... werde mri da sspäter mal genauer ansehen :)

Noch eine Frage (weiss ich habe viele ^^)

Ich habe ein frame welches beim start des Backups geladen wird.
Ich setzte in das (der die???) TextCtrl während des Backups weitere Zeilen rein und aktualisiere die Gauge.

Nur wenn jemand auf die Idee kommt das Fenster zu wechseln oder das Fenster zu verschieben / vergrössern bleibt der Inhalt für immer weiss :(

Sehr unpraktisch bei langen Backups...

vorher...
Bild

nachher :(...
Bild
pr0stAta
User
Beiträge: 271
Registriert: Freitag 17. September 2004, 11:49
Wohnort: Bremen

Bei solch wirklich Programmspezifischen Fragen wäre es
vielleicht das beste, wenn du uns den relevanten Code zeigen
würdest :)
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Code: Alles auswählen

def Copy(strDatei,strDateiroh, strZiel, Log, frame, counter=0):

    #Nur os.sep + Ordner /Dateiname bleibt zurueck
    strDatei = string.replace(strDatei,strDateiroh, '')
    counter+=1
    #frame.progress.Update(counter)
    frame.progress.SetValue(counter)
    
    if not os.path.isdir(strDateiroh + strDatei):   #ueperpruefen ob es ein Verzeichnis ist
        #Versuche Datei zu Kopieren, Wenn es nicht funktioniert ins Log File schreiben
        try:
            #print strDateiroh + strDatei
            frame.SetText(strDateiroh + strDatei)
            shutil.copy2(strDateiroh + strDatei, strZiel + strDatei)
            #if os.system('copy "' + strDateiroh + strDatei + '" "' + strZiel + strDatei + '"') !=0:
            #    Log.write("\n\nDatei %s konnte nicht kopiert werden" %(strDateiroh + strDatei))
        except:
            try:
                shutil.copy(strDateiroh + strDatei, strZiel + strDatei)
            except:
                Log.write("\n\nDatei %s konnte nicht gesichert werden"%(strDateiroh + strDatei))
    #Bei Verzeichnis
    else:
        try:    
            ToCreate = (strZiel  + strDatei)                        #Welches Verzeichnis angelegt werden muss 
            if not os.path.exists(ToCreate):                        #Wenn es nicht existiert neu anlegen
                os.mkdir(ToCreate)
            listDir = os.listdir(strDateiroh +os.sep + strDatei)    #Inhalt des Verzeichnisses ausgeben
            for element in listDir:                                 #Fuer jede Datei / Element selbstaufruf
                counter=Copy(strDateiroh + strDatei + os.sep + element, strDateiroh + strDatei, strZiel + strDatei, Log, frame, counter)    #Selbst aufruf fuer Unterverzeichnise
        except:
            Log.write("\nOrdner %s konnte samt Unterverzeichnisen / Dateien nicht\ngesichert werden" %(strDatei))
       
    return counter
Nicht der schönste code ^^

Code: Alles auswählen

class Frame(wx.Frame):
    def __init__(self, Files, parent="None", id=-1, title="Backup"):
        wx.Frame.__init__(self, parent, id, title)
        self.panel =wx.Panel(self)
        
        Sizer = wx.FlexGridSizer(2, 0)
        intFiles=0
        for File in Files:
            intFiles+=CountFiles(File)
        
        #self.progress = wx.ProgressDialog("Backup", "", intFiles, None, wx.PD_AUTO_HIDE | wx.PD_ELAPSED_TIME | wx.PD_REMAINING_TIME)
        #__init__(self, parent, id, pos, size, style, validator, name)
        self.progress=wx.Gauge(self.panel, id)
        self.progress.SetRange(intFiles)
        self.text = wx.TextCtrl(self.panel, -1, "", style=wx.TE_MULTILINE | wx.TE_READONLY)
        Sizer.AddGrowableRow(0)
        Sizer.AddGrowableRow(1)
        
        Sizer.Add(self.progress, 0, wx.EXPAND | wx.ALL, 10)
        Sizer.Add(self.text, 0, wx.EXPAND | wx.BOTTOM | wx.RIGHT | wx.LEFT, 10)
        
        self.progress.SetMinSize((300,30))
        self.text.SetMinSize((600,300))
        
        self.panel.SetSizer(Sizer)
        Sizer.Fit(self)
        Sizer.SetSizeHints(self)
        self.Show()
        
    def SetText(self, text):
        self.text.WriteText('\n' + text)

Code: Alles auswählen

elif intModus == 0 and strProg != 'subversion':
            Log = open(strZiel + os.sep + "log.txt", "w")
            Log.close
            #wxPython Applikation starten
            #__init__(self, parent, id, pos, size, style, name) 
            app = wx.PySimpleApp()
            #Frame setzen
            frame = BackupFunctions.Frame(Files, None, -1, "Backup")
            #frame als oberstes Fenster setzen
            #Kein frame.Show(), frame soll nicht angezeigt werden
            app.SetTopWindow(frame)
            
            #Dateien Sichern
            for File in Files:
                BackupFunctions.Copy(File,File, strZiel, Log, frame)
            #Fenster schliessen
            frame.Destroy()
Muss ich evth mit Threads arbeiten :s

app.MainLoop() habe ich nicht gemacht weil ich keinen Input des Benutzer möchte ;)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Ich habe aus deiner Frage ein neues Thema gemacht.

mfg
Gerold
:-)
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)

Merciii....

Aber glaube habe die Lösung auf mein Problem... Threats auch wenn ich die nicht mag ^^
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

DatenMetzgerX hat geschrieben:Threats auch wenn ich die nicht mag ^^
Du hast sicher recht. Das dürfte die einfachste Lösung sein..

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Evtl. reicht es auch, periodisch

Code: Alles auswählen

frame.Update()
aufzurufen
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Habe mich mal ein wenig mit Threads herumgeschlagen :roll: ...

Was ich nicht geschafft habe ist app.MainLoop() in einem eigenen Thread laufen zu lassen

Code: Alles auswählen

class guiThread(threading.Thread):
    def __init__(self, app):
        self.app = app
        threading.Thread.__init__(self)
    def run(self):
        self.app.MainLoop()
Das Fenster bleibt einfach weiss....

Das Andere Problem ist...

Eigentlich wollte ich das Frame automatisch nach dem Backup schliessen, aber wie. Über frame.Destroy() freut sich das app.MainLoop() nicht.

Deshalbt versuchte ich auch den Loop in einen eigenen Thread zu bringen dann häte ich nämlich prüfen können

Code: Alles auswählen

while corethread.isAlive() or guiThread.isAlive():
    if guiThread.isAlive():
        guiThread.abort()    #Weiss den exit /cancel Befehl gerade nicht...
    if corethread.isAlive():
        corethread.abort()
Und dann hätte ich das MainLoop weg, vieleicht ein wenig brutal aber was solls, geht ja eh nicht :D

Jemand eine Idee :roll:

Edit:// gibts so was wie ein Statusdialog, den ich einblenden könnte während die Files gezählt werden?
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

DatenMetzgerX hat geschrieben:Was ich nicht geschafft habe ist app.MainLoop() in einem eigenen Thread laufen zu lassen
Hi DatenMetzgerX!

Das ist sicher die falsche Weise so etwas anzugehen.
**app.mainloop()** kümmert sich um die Anzeige von Fenstern und das Abarbeiten von Events. **app** ist also ein eigener Thread.

Lass den dafür vorgesehenen Thread, also **app**, um die Anzeige kümmern und lagere die Arbeit in einen eigenen Thread aus. Allerdings musst du den arbeitenden Thread komplett unabhängig von der GUI machen. Wenn es eine neue Statusmeldung gibt, dann kann der arbeitende Thread eine Meldung an den GUI-Thread schicken. Der GUI-Thread kümmert sich dann darum, dass eine entsprechende Meldung angezeigt wird.

http://wiki.wxpython.org/index.cgi/LongRunningTasks

mfg
Gerold
:-)
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)

Das mit den Threads habe ich zum Teil hinbekommen. Nur wenn der Benutzer nun die Gui beendet. Wie kill ich den anderen Thread???

thread.stop(), thread.kill() und thread.cancel() ging nicht. Einen Befehl habe ich mit Googlen auch noch nicht herausgebracht :(

Code: Alles auswählen

#Main
if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = BackupFunctions.Frame(None, -1, "Backup")
    app.SetTopWindow(frame)
    Appli = CopyThread(app,frame)
    frame.Bind(wx.EVT_CLOSE, Appli.abort)
    Appli.start()
    app.MainLoop()

Code: Alles auswählen

class CopyThread(threading.Thread):
    def __init__(self, app, frame):
        threading.Thread.__init__(self)
        self.app = app
        self.frame = frame
        
    def run (self):
        Main()
        app.ExitMainLoop()
        frame.Destroy()
        
    def abort(self, event):
        self.stop()
Das ganze ist z.T ein wenig ein drucheinander, weil ich am Anfang noch zu wenig mit Funktionen und Klassengearbeitet habe :(

Aber wie ist der Befehl um einen Thread zu killen.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hier ein Beispiel. Nur unter Linux getestet.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import wx
import threading
import time


# Define notification event for thread completion
EVT_NEWMESSAGE_ID = wx.NewId()
EVT_STOP_ID = wx.NewId()


def EVT_NEWMESSAGE(win, func):
    """
    Define NewMessage Event.
    """
    win.Connect(-1, -1, EVT_NEWMESSAGE_ID, func)


def EVT_STOP(win, func):
    """
    Define NewMessage Event.
    """
    win.Connect(-1, -1, EVT_STOP_ID, func)


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


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", size = (400, 300)
    ):
        
        # 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
        )
        vb.Add(self.messages, 1, wx.ALL | wx.EXPAND, 5)
        
        # Buttonleiste
        hb = wx.BoxSizer(wx.HORIZONTAL)
        vb.Add(hb, 0, wx.EXPAND)
        
        # Start
        start_btn = wx.Button(panel, -1, "Start")
        hb.Add(start_btn, 1, wx.ALIGN_CENTER_HORIZONTAL| wx.ALL, 5)
        start_btn.Bind(wx.EVT_BUTTON, self.start_thread)
        
        # Stopp 
        stopp_btn = wx.Button(panel, -1, "Stopp")
        hb.Add(stopp_btn, 1, wx.ALIGN_CENTER_HORIZONTAL| wx.ALL, 5)
        stopp_btn.Bind(wx.EVT_BUTTON, self.stop_thread)
        
        # Thread-Variablen vorbereiten
        self.myworkerthread = None
        self.thread_started = False
        
        # NewMessage-Event binden
        EVT_NEWMESSAGE(self, self.add_message)
        
        # Stop-Event binden
        EVT_STOP(self, self.stop_me)
    
    
    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
        
        # 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_thread(self, event = None):
        """
        Stoppt den Thread
        """
        
        if self.myworkerthread:
            self.myworkerthread.stop()
            self.thread_started = False
            self.add_message(message = "Der Thread wurde soeben unterbrochen...")
        else:
            self.add_message(message = "Kein Thread aktiv...")
    
    
    def stop_me(self, event = None):
        """
        Fragt ob beendet werden soll und beendet bei Ja.
        """
        
        retval = wx.MessageBox(
            u"Möchten Sie jetzt beenden?", 
            "Beenden",
            wx.YES_NO | wx.NO_DEFAULT | wx.CENTER ,
            self
        )
        if retval == wx.YES:
            self.Close()



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
        self.stop_event = threading.Event()
    
    
    def run(self):
        """
        Thread-Hauptprozedur
        """
        
        while True:
            # Wenn das threading.Event (stop_event) gesetzt wurde --> abbrechen.
            if self.stop_event.isSet():
                # Thread stoppen
                break
            
            # Event an den Frame schicken
            wx.PostEvent(
                self._notify_window, NewMessageEvent(time.strftime("%H:%M:%S"))
            )
            time.sleep(2)
        
        # Event zum Stoppen an Frame schicken
        wx.PostEvent(self._notify_window, StopEvent())


    def stop(self):
        """
        Versucht den Thread zu unterbrechen. Dazu wird das
        threading.Event (stop_event) gesetzt. Der Thread muss sich immer
        selber abbrechen. Deshalb der Umweg über ein threading.Event.
        """
        
        self.stop_event.set()



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


if __name__ == "__main__":
    main()
mfg
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:

So finde ich es fast noch ein bischen einfacher. Ohne die beiden Funktionen EVT_NEWMESSAGE und EVT_STOP.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import wx
import threading
import time


# 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", size = (400, 300)
    ):
        
        # 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
        )
        vb.Add(self.messages, 1, wx.ALL | wx.EXPAND, 5)
        
        # Buttonleiste
        hb = wx.BoxSizer(wx.HORIZONTAL)
        vb.Add(hb, 0, wx.EXPAND)
        
        # Start
        start_btn = wx.Button(panel, -1, "Start")
        hb.Add(start_btn, 1, wx.ALIGN_CENTER_HORIZONTAL| wx.ALL, 5)
        start_btn.Bind(wx.EVT_BUTTON, self.start_thread)
        
        # Stopp 
        stopp_btn = wx.Button(panel, -1, "Stopp")
        hb.Add(stopp_btn, 1, wx.ALIGN_CENTER_HORIZONTAL| wx.ALL, 5)
        stopp_btn.Bind(wx.EVT_BUTTON, self.stop_thread)
        
        # 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_me)
    
    
    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
        
        # 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_thread(self, event = None):
        """
        Stoppt den Thread
        """
        
        if self.myworkerthread:
            self.myworkerthread.stop()
            self.thread_started = False
            self.add_message(message = "Der Thread wurde soeben unterbrochen...")
        else:
            self.add_message(message = "Kein Thread aktiv...")
    
    
    def stop_me(self, event = None):
        """
        Fragt ob beendet werden soll und beendet bei Ja.
        """
        
        retval = wx.MessageBox(
            u"Möchten Sie jetzt beenden?", 
            "Beenden",
            wx.YES_NO | wx.NO_DEFAULT | wx.CENTER ,
            self
        )
        if retval == wx.YES:
            self.Close()



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
        self.stop_event = threading.Event()
    
    
    def run(self):
        """
        Thread-Hauptprozedur
        """
        
        while True:
            # Wenn das threading.Event (stop_event) gesetzt wurde --> abbrechen.
            if self.stop_event.isSet():
                # Thread stoppen
                break
            
            # Event an den Frame schicken
            wx.PostEvent(
                self._notify_window, NewMessageEvent(time.strftime("%H:%M:%S"))
            )
            time.sleep(2)
        
        # Event zum Stoppen an Frame schicken
        wx.PostEvent(self._notify_window, StopEvent())


    def stop(self):
        """
        Versucht den Thread zu unterbrechen. Dazu wird das
        threading.Event (stop_event) gesetzt. Der Thread muss sich immer
        selber abbrechen. Deshalb der Umweg über ein threading.Event.
        """
        
        self.stop_event.set()



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


if __name__ == "__main__":
    main()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten