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.
HarryPython
User
Beiträge: 60
Registriert: Freitag 8. Juni 2007, 07:39

Funktion in ÜberKlasse aufrufen

Beitragvon HarryPython » Freitag 8. Juni 2007, 09:15

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: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Re: Funktion in ÜberKlasse aufrufen

Beitragvon gerold » Freitag 8. Juni 2007, 10:33

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

Beitragvon HarryPython » Samstag 9. Juni 2007, 12:07

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

Beitragvon BlackJack » Samstag 9. Juni 2007, 12:17

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

Beitragvon HarryPython » Sonntag 10. Juni 2007, 20:09

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:

Beitragvon Sr4l » Sonntag 10. Juni 2007, 20:31

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: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Sonntag 10. Juni 2007, 21:52

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

Beitragvon HarryPython » Montag 11. Juni 2007, 09:10

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

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder