PyGTK: Button Klick verhalten und Prozesse

Programmierung für GNOME und GTK+, GUI-Erstellung mit Glade.
Treehouse
User
Beiträge: 39
Registriert: Freitag 14. Dezember 2007, 00:40

Meinst du das so Trundle ? :

Code: Alles auswählen

	def on_search(self, data):
		text = self.search_entry.get_text() 
		self.aur.clear_information()       
		gtk.gdk.threads_enter()
		self.aur.search(text)
		gtk.gdk.threads_leave()
		if self.aur.is_package():          
			self.on_information()
		else:
			self.no_pack_dialog()
Falls du das so meinst, muss ich leider sagen das das Programm so hängt. Es friert ein.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Mit dem `[mod]threading[/mod]`-Modul kann man neue Threads starten. Das könnte dann vllt so irgendwie aussehen:

Code: Alles auswählen

from threading import Thread

def search_function(text):
    # Anstatt search_function eben die richtige Suchfunktion
    import time
    time.sleep(10)

def on_search(self, data):
    text = self.search_entry.get_text()
    search = Thread(target=search_function, args=[text])
    search.start()
    gobject.timeout_add(100, lambda: self.progressbar.pulse() or search.isAlive())
Bevor man dann `gtk.main` aufruft, sollte man dann noch `gtk.gdk.threads_init` aufrufen.
Treehouse
User
Beiträge: 39
Registriert: Freitag 14. Dezember 2007, 00:40

huii das sieht super aus ich teste das mal eben an ob es so geht.

Ich danke dir aber schonmal für deine Mühe
Treehouse
User
Beiträge: 39
Registriert: Freitag 14. Dezember 2007, 00:40

Hey super es klappt !!! :wink:

Ein Problem noch...... ich muss warten darauf das die Suche beendet ist. Weil je nachdem ob die Suche erfolgreich war folgen Funktionen.
Ich habe es schon mit os.wait() probiert aber das ist nur für forks wie mir scheint.
Ist es nun auch möglich auf den Thread zu warten ?
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Das ginge schon (im konkreten Fall mit ``search.join()``). Aber dann wäre ja genau wieder das Problem, dass die GUI "blockiert" wird (eben weil die `on_search`-Methode erst nach geraumer Zeit wieder zurückkehrt) und du könntest den Thread auch einfach weglassen. Einfach die Funktionen im Suche-Thread aufrufen, nach der Suche eben. Jedoch dürfen die Funktionen dann nicht direkt auf die GUI zugreifen (weil anderer Thread), sondern müssen dies z.B. über `gobject.idle_add` tun.

Beispiel (angenommen, das steht in einer Klasse):

Code: Alles auswählen

def suche(self, word):
    # Such-Code eben
    # Jetzt soll das ergebnis angezeigt werden
    ergebnis = 'Spam'
    gobject.idle_add(self.ausgabe, ergebnis)

def ausgabe(self, ergebnis):
    # Hier könnte man jetzt auf die GUI zugreifen
    self.resultentry.set_text(ergebnis)
Treehouse
User
Beiträge: 39
Registriert: Freitag 14. Dezember 2007, 00:40

Also so meinst du das nun hoffe ich....

Code: Alles auswählen

	def on_search(self, data):
		text = self.search_entry.get_text()
		self.aur.clear_information()         
		self.aur.search(text)
		gobject.idle_add(self.after_search)		

	def after_search(self):
		gobject.timeout_add(100, self.bar_searching)
		if self.aur.is_package():          
			self.on_information()
		else:
			self.no_pack_dialog()
Ich will keine GUI Funktionen in der Klasse für Suchverwaltung haben. Ich trenne meine Programme immer nach GUI und funktionalität. So kann ich immer mehr oder weniger schnell das Toolkit wechseln.

Aber ich hätte nie gedacht das ein so kleines Feature so viel Aufwand sein kann.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Treehouse hat geschrieben:Also so meinst du das nun hoffe ich....
Vermutlich nicht.. damit setzt du die ProgressBar ja erst auf pulsierend, wenn die Suche bereits um ist.

Angenommen, `self.aur.search` ist deine Suchfunktion, die etwas länger zum Suchen braucht, dann würde ich das vermutlich so irgendwie lösen:

Code: Alles auswählen

from threading import Thread

def on_search(self, data):
    text = self.search_entry.get_text()
    self.aur.clear_information()
    search = Thread(target=self.aur.search, args=[text])
    search.start()
    self.progressbar.set_text('Searching...')
    gobject.timeout_add(100, self.bar_searching, search)

def bar_searching(self, search):
    self.progressbar.pulse()
    if search.isAlive():
        return True
    else:
        if self.aur.is_package():
            self.on_information()
        else:
            self.no_pack_dialog()
Treehouse
User
Beiträge: 39
Registriert: Freitag 14. Dezember 2007, 00:40

Hallo Trundle,

danke das du dir nochmal die Mühe gemacht hast mir den Sachverhalt zu erklären. Ich bin gestern morgen auf die Lösung gekommen. Hatte aber bis jetzt leider noch keine Gelegenheit dir das mit zuteilen (kennst ja vielleicht diesen Osterwahn :lol:).

Ich verwende jetzt doch einen Thread aber ich habe eine after_search Methode eingebaut, die auch noch als Wahrheitsabfrage beim lambda mit rein kommt.

Hier mal die Lösung meines Problems

Code: Alles auswählen

	def on_search(self, data):
		text = self.search_entry.get_text() 
		self.aur.clear_information()        
		search = Thread(target=self.aur.search, args=[text])
		search.start()
		self.rider = gobject.timeout_add(100, lambda:self.bar_searching() or search.isAlive() or self.after_search())

	def after_search(self):
		if self.aur.is_package():          
			self.on_information()
		else:
			self.no_pack_dialog()
		self.bar_done()
		gobject.source_remove(self.rider)
So funktionierts jetzt einwandfrei.

Ich danke dir nochmal vielmals für deine Mühe mir die Dinge zu erklären. Aber manchmal hat man einfach ein Problem in das man sich verrennt, wo man den Wald vor lauter Bäumen nicht sieht.

Gruß

Treehouse
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Wobei man das Timeout-Event nicht unbedingt explizit entfernen muss, da `after_search` `None` zurückgibt und das lambda somit None zurückgibt, was dazu führt, dass das Timeout automatisch entfernt wird.
Antworten