PyGI (GTK+ 3) - Threads/Nichtblockierende Oberfläche?

Programmierung für GNOME und GTK+, GUI-Erstellung mit Glade.
Antworten
ilike
User
Beiträge: 1
Registriert: Montag 5. September 2011, 15:19

Hallo,
ich traue mich fast nicht zu fragen, da das Problem mir recht elementar zu sein scheint. Allerdings komme ich mit der PyGI (Gtk 3 mit Python) Dokumentation (oder besser gesagt deren Abwesenheit) nicht wirklich zurecht und finde auch nicht wirklich etwas dazu im Netz. (Vorneweg, ich bin Python/Gtk/GUI-Neuling, habe sonst noch etwas C/C++-Erfahrung.)

Ich habe mal versucht, mich an GTK3 mit Python3 ranzuwagen und ein kleines Tool damit gemacht:
https://github.com/pylight/P-2-Config-Tool
Das Tool benutzt den Networkmanager um Perfect-Privacy VPN-Verbindungen herzustellen. Dabei habe nun folgendes Problem:

In dieser Funktion:

Code: Alles auswählen

def connect_vpn(self, button):
		self.stop_vpn(self)
		print("Connecting to VPN...")
		pCon = Popen("nmcli con up id " + mainconfig['General']['connection'], shell=True)

		stat = pCon.wait()

		if stat == 0:
			self.infolabel.set_label("Connected to VPN")
		else:
			self.infolabel.set_label("Error: Couldn't connect to server!")
Wird auf das Ende des Subprozesses (herstellen der VPN-Verbindung) gewartet mit pCon.wait(). Ich würde dieses "aktive Warten" gerne ändern, sodass die Oberfläche nicht blockiert, nach dem Beenden des Subprozesses aber ein Label geändert wird. Nun frage ich mich, wie das mit PyGI am Besten umsetzen kann. Sollte ich einen neuen Thread erstellen (falls ja, wie geht das bei PyGI?) oder eine Abfrage zur Gtk.main()-loop hinzufügen? Leider bezieht sich alles was im Netz finde dazu noch auf PyGtk, beispielsweise http://excid3.com/blog/pygtk-and-threads-part-2/. Wenn sich jemand hier mit PyGI auskennt oder weiß wo ich weitere Infos dazu finden kann, würde ich mich daher sehr über eine Antwort freuen!
Danke & Gruß
ilike
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Also das mit den Threads habe ich so hingewurschtelt:

Code: Alles auswählen

from threading import Thread
from contextlib import contextmanager
from gi.repository import Gtk, Gdk, GObject

@contextmanager
def gdk_lock():
    """ Replacement for gtk.lock() """
    Gdk.threads_enter()
    yield
    Gdk.threads_leave()

# Mainloop:
GObject.threads_init()
with gdk_lock():
    Gtk.main()

# *Im GTK-Mainloop* ausführen (z.B. durch Event):
GObject.idle_add(Thread(...))
Wichtig ist folgendes:
  • `GObject.threads_init()` muss ausgeführt werden bevor `Gtk.main()` aufgerufen wird
  • Alles, was Gdk/Gtk-Objekte manipuliert, muss in einem `gdk_lock` ausgeführt werden, weil dir sonst GTK um die Ohren fliegt
  • Alle Threads müssen vom GTK-Mainloop aus gestartet werden (hier bin ich mir nicht sicher, hat aber nicht anders bei mir geklappt)
Hoffe das hilft was. Apropos Doku: In den IRC-Channel gehen und beschweren.
Antworten