Probleme mit Threads

Plattformunabhängige GUIs mit wxWidgets.
cime
User
Beiträge: 152
Registriert: Dienstag 24. Mai 2005, 15:49

Probleme mit Threads

Beitragvon cime » Montag 17. April 2006, 20:15

Hallo,

ich habe ein Programm, dass im Hintergrund (mit Hilfe von threads)einiges bearbeitet ... sobald der Prozess beendet ist, soll ein MessageDialog kommen, dass er fertig ist ... wenn ich dieses Fenster aber im thread starte hängt sich das Programm auf ... Kann mir jemand sagen, wie ich das umsetze, da ich einfach kein Lösung finde?

Danke schon im voraus!

hier ein BeispielCode:

Code: Alles auswählen

import wx,time

from thread import start_new


def arbeite_ganz_doll(parent):
    busy = wx.BusyInfo("Ich arbeite hier gerade ganz doll im Hintergrund...")
    time.sleep(2)
    busy.Destroy()
    dlg=wx.MessageDialog(self, 'Bin Fertig',
                        'Titel', wx.OK | wx.ICON_INFORMATION)
    dlg.CenterOnScreen()
    dlg.ShowModal()
    dlg.Destroy()


class app(wx.App):
    def OnInit(self):
        frame = myframe(None)
        self.SetTopWindow(frame)
        frame.CenterOnScreen()
        frame.Show(True)
        return True

class myframe(wx.Frame):
    def __init__(self,parent):
        wx.Frame.__init__(self,parent,-1,'Hallo Welt',size=(100,100))
        btn=wx.Button(self,-1,'Hier klicken',(10,10),(80,80))
        self.Bind(wx.EVT_BUTTON,lambda event: start_new(arbeite_ganz_doll,(self,)),btn)
       
       
x=app()
x.MainLoop()


mfg
cime
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Re: Probleme mit Threads

Beitragvon Francesco » Dienstag 18. April 2006, 10:12

Das ist wieder das Problem, ein Gui Control in einem Thread aufzurufen.

Ich frage mal in der wxPyhton mailing list nach der
einfachsten Möglichkeit, dies zu lösen.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Re: Probleme mit Threads

Beitragvon gerold » Dienstag 18. April 2006, 10:36

Francesco hat geschrieben:Das ist wieder das Problem, ein Gui Control in einem Thread aufzurufen.

Hi!

Ich frage mich, ob es überhaupt sinnvoll ist, hier einen Thread zu verwenden.

wx.BusyInfo zeigt ein kleines Fenster ohne Rahmen an, in dem steht, dass gerade etwas getan wird.

Wenn nach dem Aufruf von wx.BusyInfo noch ein "wx.Yield()" angehängt wird, dann hat das Fenster genug Zeit, den Text anzuzeigen. Danach kann der lange Prozess abgearbeitet werden. Während dieser Zeit bleibt das BusyInfo-Fenster einfach stehen und zeigt an, dass etwas getan wird... Vielleicht mal zwischendurch im langen Prozess ein kleines wx.Yield() rein um eventuellen Anzeigeschwierigkeiten vorzubeugen. So lange, bis der Prozess fertig ist. Danach kann das BusyInfo-Fenster wieder zerstört werden.

Was ich sagen will: "Warum dann auch noch der zusätzliche Thread?" Macht man sich da nicht ein Problem, wo eigentlich keines wäre?

Es könnte natürlich auch einen wichtigen Grund für den Thread geben, aber darauf kann ich erst eingehen, wenn ich weiß warum.

Da es anscheinend Schwierigkeiten bereitet, ein Fenster in einem eigenen Thread anzuzeigen, empfehle ich mit Events zu arbeiten und vom arbeitenden Thread aus, Events an das Hauptprogramm zu schicken. Dieses kann dann darauf reagieren und die dementsprechenden Fenster anzeigen. Ich weiß zwar noch nicht wie das geht (ich bin noch beim Lernen von wxPython), aber zur Not kann man immer noch eine Queue zur Signalübermittlung einsetzen. Siehe http://www.python-forum.de/post-32524.html#32524

Falls ich Blödsinn geschrieben habe, bitte ich um Rücksicht, da ich noch am Anfang von wxPython stehe. :P

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Re: Probleme mit Threads

Beitragvon Francesco » Dienstag 18. April 2006, 10:47

gerold hat geschrieben:
Francesco hat geschrieben:Das ist wieder das Problem, ein Gui Control in einem Thread aufzurufen.

Hi!

Ich frage mich, ob es überhaupt sinnvoll ist, hier einen Thread zu verwenden.


Ich glaube, der cime hatte das Problem mit Threads und
versuchte nur ein vereinfachtes kurzes Sample zu posten,
das das Problem verdeutlicht.

Kann mich aber auch irren. :)

gerold hat geschrieben:
Falls ich Blödsinn geschrieben habe, bitte ich um Rücksicht, da ich noch am Anfang von wxPython stehe. :P


Nein, auf keinen Fall, ich glaube, das ist schon richtig, was du gesagt hast.
pr0stAta
User
Beiträge: 271
Registriert: Freitag 17. September 2004, 11:49
Wohnort: Bremen

Beitragvon pr0stAta » Dienstag 18. April 2006, 11:57

Öhm, bei mir funktioniert das so:

Code: Alles auswählen

import wx,time

import thread


def arbeite_ganz_doll(parent):
    busy = wx.BusyInfo("Ich arbeite hier gerade ganz doll im Hintergrund...")
    time.sleep(2)
    busy.Destroy()
    dlg=wx.MessageDialog(None, 'Bin Fertig',
                        'Titel', wx.OK | wx.ICON_INFORMATION)
    dlg.CenterOnScreen()
    dlg.ShowModal()
    dlg.Destroy()


class app(wx.App):
    def OnInit(self):
        frame = myframe(None)
        self.SetTopWindow(frame)
        frame.CenterOnScreen()
        frame.Show(True)
        return True

class myframe(wx.Frame):
    def __init__(self,parent):
        wx.Frame.__init__(self,parent,-1,'Hallo Welt',size=(100,100))
        btn=wx.Button(self,-1,'Hier klicken',(10,10),(80,80))
        self.Bind(wx.EVT_BUTTON,lambda event:thread.start_new_thread(arbeite_ganz_doll,(self,)),btn)
       
       
x=app()
x.MainLoop()
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Beitragvon Francesco » Dienstag 18. April 2006, 12:26

pr0stAta hat geschrieben:Öhm, bei mir funktioniert das so:



Benutzt du Linux?

bei WinXP gibt es einen Crash, nachdem ich die Messagebox beendet habe.

[code=]Busy: pythonw.exe - Fehler in Anwendung
Die Anwendung "0x0000007C"verweist auf den Speicher in "0x0000007C". Der Vorgang "read" konnte nicht ....[/code]
pr0stAta
User
Beiträge: 271
Registriert: Freitag 17. September 2004, 11:49
Wohnort: Bremen

Beitragvon pr0stAta » Dienstag 18. April 2006, 12:49

Habe es gerade auf einem XP Rechner getestet.
Dort geht es wirklich nicht :>
Konnte den Fehler allerdings eingrenzen, es liegt anscheinend
an
busy.Destroy()
Jedenfalls funktioniert alles sobald man diese Zeile auskommentiert.
Aber ob dies nun wirklich der Grund ist, und warum das so ist, weiss ich selbst noch nicht :>
*edit* Hmm ich glaube diese BusyInfo Methode ist noch nicht so ganz ausgereift. Gibt kaum Hilfe dazu. Ruft man das busy Objekt mit der
.__del__ Methode auf, crasht das Programm auch. Ich vermute einfach mal, das es für Windows einfach nicht geht ;)
Gruss
Zuletzt geändert von pr0stAta am Dienstag 18. April 2006, 13:09, insgesamt 1-mal geändert.
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Beitragvon Francesco » Dienstag 18. April 2006, 12:56

pr0stAta hat geschrieben:Habe es gerade auf einem XP Rechner getestet.
Dort geht es wirklich nicht :>
Konnte den Fehler allerdings eingrenzen, es liegt anscheinend
an
busy.Destroy()
Jedenfalls funktioniert alles sobald man diese Zeile auskommentiert.
Aber ob dies nun wirklich der Grund ist, und warum das so ist, weiss ich selbst noch nicht :>


Das ist interessant, danke für die Info.

Robin Dunn meint dazu:

You probably want to just do a "del self.busy" instead of calling
Destroy. The wx.BusyInfo class is already setup to destroy itself when
the python proxy object is garbage collected.

Dann funktioniert das auch tatsächlich ohne Crash.
cime
User
Beiträge: 152
Registriert: Dienstag 24. Mai 2005, 15:49

Beitragvon cime » Sonntag 23. April 2006, 17:22

okay, ich muss mich entschuldigen, ich hatte mein kleines testprog für euch nich noch einmal ausführlich getestet ... ich hatte gedacht, der Fehler liegt dort auch, wie im folgenden, an der Anzeige des Dialogs ... aber leider scheint ein wx.Dialog Unterschiede zum wx.MessageDialog in dieser Hinsicht zu haben. Hier mal ein wx.Dialog, so ähnlich wie ich ihn auch in meinem Programm benutze in einem thread:

Code: Alles auswählen

# -*- coding: cp1252 -*-
import wx,time,os,sys

from thread import start_new

class mydialog_save(wx.Dialog):
    def __init__(self,parent,name,txt):
        self.txt=txt
        self.path,self.name=os.path.split(name)
        pre = wx.PreDialog()
        pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP)
        pre.Create(parent,-1,"Speichern ... %s"%name,wx.DefaultPosition,(700,700))
        self.PostCreate(pre)
       
        self.outp = wx.TextCtrl(self, -1,txt,(10,10),size=(674, 620), style=wx.TE_MULTILINE|wx.TE_READONLY)
        self.outp.SetBackgroundColour(wx.NamedColor('WHITE'))

        btn=wx.Button(self,-1,"Speichern",(300,640))
        btn.SetDefault()
        self.Bind(wx.EVT_BUTTON,self.save_as,btn)
        btn = wx.Button(self, wx.ID_OK,"Fertig",(450,640))

    def save_as(self,event=None):
        if self.path and not os.path.isdir(self.path):
            os.makedirs(self.path)
        while True:
            dlg = wx.FileDialog(
                self, defaultDir=self.path,
                defaultFile=self.name, wildcard=wildcard, style=wx.SAVE | wx.CHANGE_DIR
                )
            if dlg.ShowModal() == wx.ID_OK:
                path=dlg.GetPaths()[0]
                if os.path.isfile(path):
                    dlg = wx.MessageDialog(self,'Diese Datei existiert schon. Wollen SIe die Daten anfügen?',
                                'ERROR', wx.YES_NO|wx.NO_DEFAULT)
                    ret=dlg.ShowModal()
                    dlg.Destroy()
                    if ret==wx.ID_YES:
                        try:
                            f=open(path,'a')
                        except:
                            dlg.Destroy()
                            dlg = wx.MessageDialog(self,'Datei kann nicht geschrieben werden',
                                        'ERROR', wx.OK)
                            dlg.ShowModal()
                            dlg.Destroy()
                            continue
                    else:
                        continue
                else:
                    try:
                        f=open(path,'w')
                    except:
                        dlg.Destroy()
                        dlg = wx.MessageDialog(self,'Datei kann nicht geschrieben werden',
                                    'ERROR', wx.OK)
                        dlg.ShowModal()
                        dlg.Destroy()
                        continue
                f.write(self.outp.GetValue())
                f.close()
            break
        pass

def arbeite_ganz_doll(parent):
    busy = wx.BusyInfo("Ich arbeite hier gerade ganz doll im Hintergrund...")
    time.sleep(2)
    del busy

    dlg=mydialog_save(parent, os.path.join(os.path.split(sys.argv[0])[0],'Testordner','Testdatei.txt'),
                        'hier ist halt der Text.')
    dlg.CenterOnScreen()
    print 'bis hier gehts'
    dlg.ShowModal()
    print 'hier schon nicht mehr'
    dlg.Destroy()


class app(wx.App):
    def OnInit(self):
        frame = myframe(None)
        self.SetTopWindow(frame)
        frame.CenterOnScreen()
        frame.Show(True)
        return True

class myframe(wx.Frame):
    def __init__(self,parent):
        wx.Frame.__init__(self,parent,-1,'Hallo Welt',size=(100,100))
        btn=wx.Button(self,-1,'Hier klicken',(10,10),(80,80))
        self.Bind(wx.EVT_BUTTON,lambda event: start_new(arbeite_ganz_doll,(self,)),btn)
       
       
x=app(redirect=False)
x.MainLoop()

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder