I'm developing a graphical interface with pygtk 3, In parallel with this interface, I'm running a function in a 2nd thread, which reads a file that is updated by an external program.
When the value in this file exceeds a certain value, I'd like to display a popup window to warn the user that this value has been reached.
The problem is that when the popup window is displayed, the program freeze.
After looking at several similar questions, I've understood that you can't launch another gtk window in a second thread, but no matter how hard I look, I can't figure out how to do it...maybe by emitting a signal from the thread that would be picked up by gtk main loop? but I haven't figured out how to do it properly.
here is a simplified code(i didn't put all the code of the GUI it's to big and no relevent for this issue), so just a main gtk window, a popup window and the function reading the file.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from threading import Thread
import time
#The Popup window classe
class DeepMonitorWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Sounder")
self.set_border_width(10)
label=Gtk.Label(label="som popup message")
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
hbox.pack_start(label,True,True,6)
button=Gtk.Button.new_with_label("OK")
button.connect("clicked",self.on_click)
hbox.pack_start(button,True,True,6)
self.add(hbox)
def on_click(self,event):
self.destroy()
#the function that run ine the thread
def DeepMonitor():
flagUpDown=True
while(1):
with open("seasave_shared.txt","r") as f:
depth=f.readlines()[-1]
print(float(depth.lstrip().strip("\n")))
if float(depth.lstrip().strip("\n")) > 150 and flagUpDown==True :
print("deep reached 150m")
window=DeepMonitorWindow()
window.show_all()
flagUpDown=False
if float(depth.lstrip().strip("\n")) < 150 and flagUpDown==False:
print("deep reached 150m")
window=DeepMonitorWindow()
window.show_all()
flagUpDown=True
break
time.sleep(1)
#the main window
class StationSheet():
def __init__(self):
self.window=Gtk.Window()
self.window.show_all()
self.window.connect("destroy", Gtk.main_quit)
#the thread
t=Thread(target=DeepMonitor)
t.start()
def main():
app = StationSheet()
Gtk.main()
if __name__ == "__main__":
main()
I finally found a way to make it work! I got my inspiration from the following link: https://pygobject.readthedocs.io/en/latest/guide/threading.html
use lang-python GLib.idle_add(function)
to display the window and use lang-python thread.deamon()
before launching the thread.
I've also created a function to display the popup window.
here's the working code
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from threading import Thread
import time
#The Popup window classe
class DeepMonitorWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Sounder")
self.set_border_width(10)
label=Gtk.Label(label="som popup message")
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
hbox.pack_start(label,True,True,6)
button=Gtk.Button.new_with_label("OK")
button.connect("clicked",self.on_click)
hbox.pack_start(button,True,True,6)
self.add(hbox)
def on_click(self,event):
self.destroy()
#the main window
class StationSheet():
def __init__(self):
self.window=Gtk.Window()
self.window.show_all()
self.window.connect("destroy", Gtk.main_quit)
#the thread
t=Thread(target=self.DeepMonitor)
t.daemon=True
t.start()
#the function that run ine the thread
def show_popup(self):
p=DeepMonitorWindow()
p.set_transient_for(self.window)
p.show_all()
def DeepMonitor():
flagUpDown=True
while(1):
with open("seasave_shared.txt","r") as f:
depth=f.readlines()[-1]
print(float(depth.lstrip().strip("\n")))
if float(depth.lstrip().strip("\n")) > 150 and flagUpDown==True :
print("deep reached 150m")
window=DeepMonitorWindow()
window.show_all()
flagUpDown=False
if float(depth.lstrip().strip("\n")) < 150 and flagUpDown==False:
print("deep reached 150m")
window=DeepMonitorWindow()
window.show_all()
flagUpDown=True
break
time.sleep(1)
def main():
app = StationSheet()
Gtk.main()