GTK+ und Threads

Programmierung für GNOME und GTK+, GUI-Erstellung mit Glade.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

GTK+ und Threads

Beitragvon Leonidas » Freitag 11. Februar 2005, 20:37

Hallo!
Ich bin auch grad am Verzweifeln, ich bekomme das nicht so zum laufen wie ich will:

Code: Alles auswählen

import thread, threading, time
import gtk

class UpdaterThread(threading.Thread):
    def __init__(self, win):
        threading.Thread.__init__(self)
        self.gtkwin = win
   
    def update(self):
        time.sleep(2)
        self.gtkwin.update.set_label(str(time.localtime()[5]))
   

class StationWindow(object):
    def __init__(self):
        self.window = gtk.Window()
        self.window.connect("delete_event", self.delete_event)
        self.update = gtk.Button('Update')
        self.update.connect("clicked", self.update_click)
        self.window.add(self.update)
        self.window.show_all()
   
    def delete_event(self, widget, event, data=None):
        """Window closing"""
        gtk.main_quit()
        return False
   
    def update_click(self, widget):
        ut = UpdaterThread(self)
        ut.update()

def main():
    """The main method - just opens the window"""
    sw = StationWindow()
    gtk.gdk.threads_init()
    gtk.gdk.threads_enter()
    gtk.main()
    gtk.gdk.threads_leave()

if __name__ == '__main__':
    main()


Also, wenn man auf Update klickt, soll der Button wieder rauskommen und nach zwei Sekunden die Beschriftung geändert werden. Aber es geht nicht! Hilfe!?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Beitragvon mawe » Freitag 11. Februar 2005, 20:56

Hi!

Der Button ist 2 sec gedrückt, dann ändert sich die Beschriftung. So siehts bei mir aus. Sollte es anders sein?

EDIT: Oh, der Button soll gleich wider rauskommen, oder?

Gruß, mawe
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Freitag 11. Februar 2005, 21:28

mawe hat geschrieben:EDIT: Oh, der Button soll gleich wider rauskommen, oder?

Genau. Das Programm ist nur ein Demo Teil, aber vom Konzept her, sollte der Button rauskommen und dann nach 2 sec die Beschriftung ändern.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Beitragvon mawe » Freitag 11. Februar 2005, 21:34

Hi!

Naja, wie Du sicher gemerkt hast, kenn ich mich mit Gtk noch nicht wirklich aus. Aber kannst Du nicht statt clicked einfach pressed nehmen? :)

Gruß, mawe
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Freitag 11. Februar 2005, 21:40

Na mir geht es nicht darum, dass der Button wieder hochkommt, sondern das das was in UpdateClick aufgerufen wird, in einen seperaten Thread kommt. Ich möchte halt einfach, dass die GUI noch reagiert, so dass man noch andere Dinge machen kann.

Folgendes habe ich noch gefunden, will aber bei mir auch nicht (also PyGTK ist bei mir angeblich mit Thread Support).

Code: Alles auswählen

from gtk import *
from threading import *
import time

class Worker(Thread):
    def __init__ (self, widget):
        Thread.__init__(self)
        self.counter = 0
        self.widget = widget
   
    def run (self):
        while 1:
            threads_enter()
            self.widget.set_text ("Count: %d" % self.counter)
            threads_leave()
            time.sleep(1)
            self.counter = self.counter + 1

win = Window()
label = Label()
win.add(label)
win.show_all()

threads_enter()
worker = Worker(label)
worker.start()
main()
threas_leave()
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Freitag 11. Februar 2005, 22:07

Okay. Hit. Jetzt werde ich mal schauen wie das anzupassen ist.

Edit: So:

Code: Alles auswählen

#!/usr/bin/env python
# -*- encoding: latin-1 -*-
import threading, time
import gtk

class UpdaterThread(threading.Thread):
    def __init__(self, win):
        threading.Thread.__init__(self)
        self.gtkwin = win
   
    def run(self):
        time.sleep(2)
        gtk.gdk.threads_enter()
        self.gtkwin.update.set_label(str(time.localtime()[5]))
        gtk.gdk.threads_leave()
   

class StationWindow(object):
    def __init__(self):
        self.window = gtk.Window()
        self.window.connect("delete_event", self.delete_event)
        self.update = gtk.Button('Update')
        self.update.connect("clicked", self.update_click)
        self.window.add(self.update)
        self.window.show_all()
   
    def delete_event(self, widget, event, data=None):
        """Window closing"""
        gtk.main_quit()
        return False
   
    def update_click(self, widget):
        ut = UpdaterThread(self)
        ut.start()

def main():
    """The main method - just opens the window"""
    sw = StationWindow()
    gtk.gdk.threads_init()
    gtk.gdk.threads_enter()
    gtk.main()
    gtk.gdk.threads_leave()

if __name__ == '__main__':
    main()

Also muss bei praktisch allem eine threads_enter() und threads_leave() aufgerufen werden. Ja wenn es sonst nichts ist..
Zuletzt geändert von Leonidas am Freitag 11. Februar 2005, 22:13, insgesamt 1-mal geändert.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Beitragvon Dookie » Freitag 11. Februar 2005, 22:13

Hi Leonidas,

wo haste denn den Code her? Da kennt sich ja kein Schwein aus!
Welche Funktion ist aus Threading und welche aus gtk?

Ich würd da eher was mit gtk.timeout_add(...) oder gtk.idle_add(...) versuchen bevor ich mit Threads in der GUI rumfummle.


Gruß

Dookie

Code: Alles auswählen

#!/usr/bin/env python
import this
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Freitag 11. Februar 2005, 22:17

Dookie hat geschrieben:wo haste denn den Code her? Da kennt sich ja kein Schwein aus!
Welche Funktion ist aus Threading und welche aus gtk?

Hihi, hast absolut recht, ich bin auch kein Freund der * imports. Der Code ist aus einem Mailinglistenarchiv, muss wohl etwas älter sein, da damals da noch GtkWindow und GtkLabel aktuell waren (ich hab das kurz mal weggemacht, damit es mit aktuellem PyGTK auch geht).

Wäre nett Dookie, wenn du mir zeigen könntest wie man sowas mit timeout_add machen könnte, denn auf Threads bin ich nicht wirklich scharf, besonders nicht in der Kombination mit PyGTK.

Edit: Ich habe es mit idle_add gemacht:

Code: Alles auswählen

import time
import gtk

class StationWindow(object):
    def __init__(self):
        self.window = gtk.Window()
        self.window.connect("delete_event", self.delete_event)
        self.update = gtk.Button('Update')
        self.update.connect("clicked", self.update_click)
        self.window.add(self.update)
        self.window.show_all()
   
    def delete_event(self, widget, event, data=None):
        """Window closing"""
        gtk.main_quit()
        return False
   
    def async(self):
        time.sleep(2)
        self.update.set_label(str(time.localtime()[5]))
   
    def update_click(self, widget):
        gtk.idle_add(self.async)

def main():
    sw = StationWindow()
    gtk.main()

if __name__ == '__main__':
    main()


Zugegeben, das ist eine wesentlich bessere Lösung als mit Threads. Warum gibt es denn dazu keine Doku, wenn das doch ganz klar so gut ist?

Habe mir mit diesem netten Programm geholfen, das Programm selbst ist auch recht hübsch :)
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Beitragvon Dookie » Freitag 11. Februar 2005, 23:54

Hi Leonidas,

ich hab noch eine Version mit timeout_add gemacht:

Code: Alles auswählen

import time
import gtk, gobject

def do_timer(button):
    button.set_label(str(time.localtime()[5]))
    return False # only one time

class StationWindow(object):
    def __init__(self):
        self.window = gtk.Window()
        self.window.connect("delete_event", self.delete_event)
        self.update = gtk.Button('Update')
        self.update.connect("clicked", self.update_click)
        self.window.add(self.update)
        self.window.show_all()
   
    def delete_event(self, widget, event, data=None):
        """Window closing"""
        gtk.main_quit()
        return False
   
    def update_click(self, widget):
        gobject.timeout_add(2000, do_timer, self.update)

def main():
    """The main method - just opens the window"""
    sw = StationWindow()
    gtk.main()

if __name__ == '__main__':
    main()


Wenn die do_timer Funktion True zurückgibt, wird die Funktion alle 2 Sekunden aufgerufen, so, bei False nur einmal nach 2 Sekunden.
Doku zu Timeout und Idle findest Du hier: TimeoutsIOAndIdleFunctions und gobject-functions


Gruß

Dookie

Code: Alles auswählen

#!/usr/bin/env python
import this
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Samstag 12. Februar 2005, 11:46

Uhm, wo das Proglem gelöst ist (Danke! Danke! Danke!)...
wie kann man denn gtk.Buttons deaktivieren (also ausgrauen und Events ignorieren)?
Ich habe nur eine activate() Funktion gefunden, aber die ruft nur das Activate Event auf, also nicht das was ich will.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Beitragvon Dookie » Samstag 12. Februar 2005, 12:43

das geht mit button.set_sensitive(False)

Gruß

Dookie

Code: Alles auswählen

#!/usr/bin/env python
import this
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Samstag 12. Februar 2005, 13:36

Dookie hat geschrieben:das geht mit button.set_sensitive(False)

Vielen Dank! Interssant wie lange ich gebraucht hätte um darauf zu kommen. Eine Woche, zwei? Was würde ich wohl ohne dieses Forum machen?
My god, it's full of CARs! | Leonidasvoice vs Modvoice

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder