Funktion in ÜberKlasse aufrufen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
HarryPython
User
Beiträge: 60
Registriert: Freitag 8. Juni 2007, 07:39

Hi

Ich habe folgendes Problem:
Ich hab zwei .py Dateien. In der einen die Klasse Main und in der anderen die Klasse Thread. Die Klasse Thread importiere ich mit 'from Thread import Thread' in die Klasse Main.
In Main habe ich einen Button der in Thread eine Funktion startet. Durch zb: self.test=Thread(self)
self.test.start()

Nun möchte ich dass wenn meine Funktion in der Klasse Thread durchlaufen ist die Eigenschaft des Buttons Label, der in meiner KlasseMain steht, ändern.

Ist es nicht möglich aus der Klasse Thread eine Funktion in der Klasse Main aufzurufen???? Wenn ich sowas wie oben in die Klasse Thread schreibe kennt er immer meine Klasse Main nicht. Arrrr.

Wahrscheinlch hab ich das mit Ober und Unterklassen noch nicht ganz verstanden :oops:

Hoffe es kann mir jemand Helfen. Danke!
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo HarryPython!
HarryPython hat geschrieben:Ich hab zwei .py Dateien. In der einen die Klasse Main und in der anderen die Klasse Thread.
1.) Das sind sehr unglücklich gewählte Namen. Sie sagen nichts aus.
2.) Warum teilst du dein Programm in mehrere Dateien auf? Funktioniert eines der Module auch ohne das andere Modul? Wenn nicht, dann verkompliziert eine Aufteilung dein Programm unnötig.
HarryPython hat geschrieben:In Main habe ich einen Button der in Thread eine Funktion startet. Durch zb:

Code: Alles auswählen

self.test=Thread(self)
      self.test.start()
Nun möchte ich dass wenn meine Funktion in der Klasse Thread durchlaufen ist die Eigenschaft des Buttons Label, der in meiner KlasseMain steht, ändern.
Du hast uns nicht gesagt, mit welchem Toolkit du deinen Button erstellt hast. Für Tkinter, wxPython und Co. gibt es eigene Unterforen.
HarryPython hat geschrieben:Ist es nicht möglich aus der Klasse Thread eine Funktion in der Klasse Main aufzurufen???? Wenn ich sowas wie oben in die Klasse Thread schreibe kennt er immer meine Klasse Main nicht.
Nein, von einem Thread aus, **direkt** eine Funktion in einem anderen Thread (auch das Hauptprogramm läuft in einem Thread) aufzurufen, geht nicht.
Unter wxPython wird diese Trennung z.B. mit wxPython-Events umgangen. Z.B. über die Funktion ``wx.CallAfter()``

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
HarryPython
User
Beiträge: 60
Registriert: Freitag 8. Juni 2007, 07:39

Hi Gerold.

Erstmal Danke für die schnelle Antwort. Echt klasse dieses Forum. Hatte nur ein Paar Probleme mit dem Anmelden. Als ich all meine Daten eingegeben hab kam eine Fehlermeldung danach konnte ich mich nicht nochmal anmelden, da die E-Mail Adresse schon regestriert ist. Mit der 3.Mail hat es dann geklappt. Vielleicht weißt du ja bereits wovon ich rede. Aber jetzt ist er drin. Jupi.

zum Thema:

Hab sie nur hier Main und Thread genannt zum leichteren Verständniss.

Warum aufteilen ist eine gute Frage. Als ich noch nicht wußte wie man Threads erstellt hab ich so mein Problem gelöst.

Ich arbeite mit wx.
Nein, von einem Thread aus, **direkt** eine Funktion in einem anderen Thread (auch das Hauptprogramm läuft in einem Thread) aufzurufen, geht nicht.
Aber ich starte ja auch aus Main mit start() meine Funktion run() in Thread. Oder ist das die einziege Ausnahme?

mfg Harry
BlackJack

Du startest mit `start()` einen neuen Thread und *der* ruft dann die `run()`-Methode auf. Das ist in der Tat eine Ausnahme weil die `start()`-Methode etwas sehr "magisches" tut: einen neuen Thread starten und sofort zum Aufrufer zurückkehren.
HarryPython
User
Beiträge: 60
Registriert: Freitag 8. Juni 2007, 07:39

Hilfe!!!!

Sitze jetzt seit drei Tagen an dem Problem und dreh langsam durch. :x

Ich hab die beiden Klassen zusammengefügt.
Hab es auch schon geschafft aus meinem Thread eine Funktion in Main aufzurufen. Irgendwelche print Anweisungen in dieser Funktion klappen aber sobald ich sage er soll das Label von meinem Button ändern ignoriert er das einfach. Gibt nicht mal ein Fehler.

wx.CallAfter liefert eine Fehlermeldung "NoneType Objekt not callable" führt dann aber dennoch die Funktion aus aber auch nur so als würde ich sie direkt aufrufen.


Ich möchte doch nur bei meinem Button in der Klasse Main das Label wieder auf "Start" setzen wenn der Tread zuende ist!!!!!!!!!!!!!!!!!
Damit der User sieht er kann den Thread wieder starten.

HILFE wo sind die Programmierer????
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

Du könntest mal dein Code posten bei: http://paste.pocoo.org/ und uns den Link sagen.

dann kann ich den Wikieintrag mit einem sehr großen Beispiel empfehlen [wiki]Threading Beispiel1[/wiki] wobei ich es etwas zu lang finde,

Code: Alles auswählen

#! /usr/bin/env python
#-*- coding: latin-1 -*-
#
import socket,time,thread

def Server(byte,host,port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #Socket defenieren
    sock.bind((host, port)) #server auf localhost, Port 12345 laufen lassen
    sock.listen(1) #Server maximal 1 Client akzeptieren lassen
    conn, addr = sock.accept()
    while True:
        #print addr," ",data
        print "<<<: %s"%(conn.recv(byte))
    conn.close()

def Run():
    host = "localhost"   #Hostname
    port = 12345         #Verbindungs Port
    byte = 1024          #Byte Groesse
    #
    thread.start_new_thread(Server, (byte,host,port)) #Lässt Server() im Hintergrundlaufen
    while True:
        print "Der Server blockt mich nicht dank dem Thread."
        time.sleep(2) #Nur damit wir keine 100% CPU Auslastung haben
        
Run()  
Das war der kürzeste Code zum Modul Thread den ich auf meiner Festplatte noch gefunden habe, ich bitte um Verzeihung der nicht PEP8 konformen Schreibweise ;-)

Wegen deinem Button Problem: Wenn keine Fehlermeldung kommt gibt es keine Fehler, ohne Code schwierig zusagen was da nicht geht.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

HarryPython hat geschrieben:Ich möchte doch nur bei meinem Button in der Klasse Main das Label wieder auf "Start" setzen wenn der Tread zuende ist!
Hallo HarryPython!

Nicht so kompliziert, aber mit weniger Möglichkeiten:

Code: Alles auswählen

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

import wx
import thread
import time

wx.SetDefaultPyEncoding("iso-8859-15")


class MyFrame(wx.Frame):
    
    def __init__(
        self, parent = None, id = -1, title = "Example", size = wx.Size(200, 150)
    ):
        wx.Frame.__init__(self, parent, id, title, size = size)
        
        self.panel = wx.Panel(self)
        
        vbox_main = wx.BoxSizer(wx.VERTICAL)
        self.panel.SetSizer(vbox_main)
        
        vbox_main.AddStretchSpacer()
        
        self.btn_start = wx.Button(self.panel, label = "Start")
        vbox_main.Add(self.btn_start, 0, wx.ALL | wx.ALIGN_CENTER)
        self.btn_start.Bind(wx.EVT_BUTTON, self.start_worker)
        
        vbox_main.AddStretchSpacer()
        
        self.panel.Layout()
    
    
    def start_worker(self, event = None):
        self.btn_start.SetLabel("working...")
        self.btn_start.Disable()
        self.panel.Layout()
        wx.SafeYield()
        
        thread.start_new_thread(self.worker, ())
    
    
    def worker(self):
        for i in xrange(5):
            print "Ich arbeite..."
            time.sleep(1)
        # Fertig
        wx.CallAfter(self.btn_start.SetLabel, "Start")
        wx.CallAfter(self.btn_start.Enable)
        wx.CallAfter(self.panel.Layout)
        wx.SafeYield()


def main():
    """Testing"""
    
    app = wx.PySimpleApp()
    f = MyFrame()
    f.Center()
    f.Show()
    app.MainLoop()


if __name__ == "__main__":
    main()
Komplizierter, aber mehr Möglichkeiten:

Code: Alles auswählen

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

import wx
import time
import threading

wx.SetDefaultPyEncoding("iso-8859-15")


class MyWorker(threading.Thread):
    
    def __init__(self, finished_function = None):
        threading.Thread.__init__(self)
        self.canceled = threading.Event()
        self.finished_function = finished_function
    
    
    def run(self):
        for i in xrange(10):
            if self.canceled.isSet():
                print "Gestoppt..."
                break
            print "Ich arbeite..."
            time.sleep(1)
        
        if self.finished_function:
            self.finished_function()
    
    
    def stop(self):
        self.canceled.set()


class MyFrame(wx.Frame):
    
    def __init__(
        self, parent = None, id = -1, title = "Example", size = wx.Size(200, 150)
    ):
        wx.Frame.__init__(self, parent, id, title, size = size)
        
        self.worker = None
        
        self.panel = wx.Panel(self)
        
        vbox_main = wx.BoxSizer(wx.VERTICAL)
        self.panel.SetSizer(vbox_main)
        
        vbox_main.AddStretchSpacer()
        
        self.btn_start = wx.Button(self.panel, label = "Start")
        vbox_main.Add(self.btn_start, 0, wx.ALL | wx.ALIGN_CENTER)
        self.btn_start.Bind(wx.EVT_BUTTON, self.start_worker)
        
        self.btn_cancel = wx.Button(self.panel, label = "Abbruch")
        self.btn_cancel.Disable()
        vbox_main.Add(self.btn_cancel, 0, wx.ALL | wx.ALIGN_CENTER)
        self.btn_cancel.Bind(wx.EVT_BUTTON, self.cancel_worker)
        
        vbox_main.AddStretchSpacer()
        
        self.panel.Layout()
    
    
    def start_worker(self, event = None):
        self.btn_start.SetLabel("working...")
        self.btn_start.Disable()
        self.btn_cancel.Enable()
        self.panel.Layout()
        wx.SafeYield()
        
        self.worker = MyWorker(self.worker_finished)
        self.worker.start()
    
    
    def cancel_worker(self, event = None):
        self.worker.stop()
    
    
    def worker_finished(self):
        wx.CallAfter(self.btn_start.SetLabel, "Start")
        wx.CallAfter(self.btn_start.Enable)
        wx.CallAfter(self.btn_cancel.Disable)
        wx.CallAfter(self.panel.Layout)
        wx.SafeYield()


def main():
    """Testing"""
    
    app = wx.PySimpleApp()
    f = MyFrame()
    f.Center()
    f.Show()
    app.MainLoop()


if __name__ == "__main__":
    main()
mfg
Gerold
:-)

PS: Schon spät... wenig Kommentare!
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
HarryPython
User
Beiträge: 60
Registriert: Freitag 8. Juni 2007, 07:39

Ahhhhhhhhhhhhhhhhhhhhhhhhhh. :o

Genau das hab ich gesucht!!!!!!!!!!!!!

Danke Meister Gerold!!!!!!!!!!!!!!

Die ganze Funktion an den Thread übergeben. :shock: Na klar.

Cool. Danke nochmal. Jetzt kann ich weiter machen.



mfg Padawan HarryPython
Antworten