Python3 GTK3 - Change button to insensitive immediately after click - python

Please take a look on my test code below:
import time
import subprocess
import os,re
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="test")
self.set_default_size(400, 190)
self.set_border_width(10)
fixed = Gtk.Fixed()
self.add(fixed)
self.button2 = Gtk.Button(label='press')
self.button2.connect("clicked", self.aaabbb)
self.button2.set_size_request(100, 20)
fixed.put(self.button2, 170, 10)
def aaabbb(self,widget):
self.button2.set_sensitive(False)
p = subprocess.run( ['/bin/bash','-c', '/bin/sleep 5'] )
print(p.returncode)
window = MyWindow()
window.connect("delete-event", Gtk.main_quit)
window.show_all()
Gtk.main()
If you run this simple application you will notice that button gets disabled only after 5 second, after subprocess finishes "sleep 5"
Question - how to make the button insensitive before subprocess starts?
Thank you in advance

That happens because the subprocess call isn't asynchronous and blocks the mainloop and the user interface as a consequence.
So, the approach is not correct.
The clicked signal requires a button to be pressed and released but you have other signals that you can use, eg. button-press-event and button-release-event. The callback prototypes vary from the clicked one and you'll have access to the event, if needed.
The answer to your question would be, set a callback to the button press event, BUT this will not solve your problem! The call should be async and to achieve that you can use GLib spawn async method.

Related

How to make the window behind a dialog not clickable?

i want to set blocked the window behind dialog to prevent the user do click or modify any content of the window while the dialog are running, and when the user close de dialog then set unlocked the window behind dialog.
import gtk;
window = gtk.Window();
window.set_title("Window Behind Dialog");
window.set_default_size(426,240);
textentry = gtk.TextView();
window.add(textentry);
window.show_all();
dialog = gtk.Window();
dialog.set_title("Dialog");
dialog.set_default_size(256,144);
label = gtk.Label("Unlock the window behind when this dialog get close");
dialog.add(label);
dialog.show_all();
gtk.main();
Which method is used for it, in Gtk or PyGtk?, for example:
window.set_disabled_to_all_events();
or
window.set_disabled();
or
window.events_disabled(True);
or
window.set_blocked(True);
If you have a window manager that honors modal windows, you could use set_modal on the dialog window.
If not, you could use set_sensitive on the parent window. Call this with False when the dialog is shown, and with True when the dialog is hidden or destroyed.
I've added Gtk3 examples below. I recommend that you switch to PyGObject and Python 3 before investing too much effort in a deprecated toolkit.
Modal window example:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
window = Gtk.Window(title="Hello World")
window.connect("destroy", Gtk.main_quit)
window.add(Gtk.TextView())
window.show_all()
dialog = Gtk.Window(title="Dialog")
dialog.set_transient_for(window)
dialog.set_modal(True)
dialog.show()
Gtk.main()
Or using explicit set_sensitive:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
window = Gtk.Window(title="Hello World")
window.connect("destroy", Gtk.main_quit)
window.add(Gtk.TextView())
window.show_all()
dialog = Gtk.Window(title="Dialog")
dialog.set_transient_for(window)
window.set_sensitive(False)
def destroy_cb(widget, data):
data.set_sensitive(True)
dialog.connect("destroy", destroy_cb, window)
dialog.show()
Gtk.main()

Stop Python Gtk.Application using Ctrl+C

I am creating an application. Previously, I were using Gtk.Main() to start my application, and created some hooks to stop the application from the command line using Ctrl+C. Now, I have migrated the application to a more "standard" Gtk.Application, but can't get it to stop using Ctrl+C.
This is a very simple Gtk.Application, that when is run from the command line, it can't be stopped using Ctrl+C:
from gi.repository import Gtk
import sys
# a Gtk ApplicationWindow
class MyWindow(Gtk.ApplicationWindow):
# constructor: the title is "Welcome to GNOME" and the window belongs
# to the application app
def __init__(self, app):
Gtk.Window.__init__(self, title="Welcome to GNOME", application=app)
class MyApplication(Gtk.Application):
# constructor of the Gtk Application
def __init__(self):
Gtk.Application.__init__(self)
# create and activate a MyWindow, with self (the MyApplication) as
# application the window belongs to.
# Note that the function in C activate() becomes do_activate() in Python
def do_activate(self):
win = MyWindow(self)
# show the window and all its content
# this line could go in the constructor of MyWindow as well
win.show_all()
# start up the application
# Note that the function in C startup() becomes do_startup() in Python
def do_startup(self):
Gtk.Application.do_startup(self)
# create and run the application, exit with the value returned by
# running the program
app = MyApplication()
exit_status = app.run(sys.argv)
sys.exit(exit_status)
import signal
from gi.repository import GLib
...
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, app.quit)
This worked with Gtk 3.0:
import signal
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import GLib
app = Application()
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, Gtk.main_quit)
You can use Ctrl+Z to stop the execution of script.

wxPython popup from calling imported function

I have a GUI made with wxPython that calls a function that I imported from a separate Python file when I press a button, and shows the output of that function in a text box. I want to improve it so that if the function asks for user input mid-execution (like a raw_input()), I want a new popup window to appear instead of the raw_input waiting in the text box. I've been looking through the wxPython documentation but can't seem to find anything that resembles what I want, so I was wondering if anyone here could give me any pointers.
GUI code:
import sys
import os
import re
import subprocess
import threading
import wx
import errno, os, stat, shutil
import extern_func
#this object redirects the external function output to the text box
class RedirectText(object):
def __init__(self,aWxTextCtrl):
self.out=aWxTextCtrl
def write(self,string):
self.out.WriteText(string)
#GUI code here
class progFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, title="functionGUI", size=(800, 600), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
panel = wx.Panel(self)
#more things....
self.runButton = wx.Button(panel, wx.ID_OK, "Run", pos=(200, 300))
self.out=wx.TextCtrl(panel, style=wx.TE_MULTILINE|wx.VSCROLL|wx.TE_READONLY, pos = (300, 50), size=(500, 200))
#Run button event
self.Bind(wx.EVT_BUTTON, self.OnRun, self.runButton)
#command prompt output to frame
redir=RedirectText(self.out)
sys.stdout=redir
self.Show()
def OnRun(self, event):
t=threading.Thread(target=self.__run)
t.start()
#external function call
def __run(self):
externFunc()
if __name__ == '__main__':
app = wx.App(False)
progFrame(None)
app.MainLoop()
External function code:
import sys
def externFunc():
print "Starting execution..."
#a bunch of code...
cont = raw_input("Something has gone wrong. Do you still want to continue?")
if(cont.lower() == "n")
sys.exit(0)
#more function code...
print "Success!"
I would call the external function via a button event. Instead of raw_input, I would just use a wx.MessageDialog with a yes or no button on it. You can check which button the user pressed and continue or not accordingly. Here are some links on that dialog and others:
http://wxpython.org/Phoenix/docs/html/MessageDialog.html
http://www.blog.pythonlibrary.org/2010/06/26/the-dialogs-of-wxpython-part-1-of-2/
http://zetcode.com/wxpython/dialogs/
If this piece of code you are running takes a long time (i.e. greater than a second), then it is probably going to block wx's mainloop and cause the application to become unresponsive. If that is the case, then you'll need to move this code into a thread. The following articles will help you with that course of action:
http://wiki.wxpython.org/LongRunningTasks
http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/

How to deiconify a window after the click of minimize button in GTK

Here is my test code (running on Ubuntu 14.04):
try:
from gi.repository import Gtk,Gdk,GObject
except ImportError:
import gtk as Gtk
import gtk.gdk as Gdk
import gobject as GObject
def deiconify( widget ):
print 'deiconifying the window'
widget.deiconify()
return True
win = Gtk.Window()
win.show_all()
#win.iconify()
GObject.timeout_add( 2000, deiconify, win)
Gtk.main()
I just want to deiconify (redisplay) the window after I click the minimize button, but it doesn't work using the codes here. But if I uncomment this line #win.iconify() instead of clicking the minimize button, it will redisplay the window (after that, it still can not deiconify the window if I click the minimize button). Did I miss calling some other functions here? Any help will be appreciated.
I have the same issue with deiconify.
Then I found another function which work as expected.
def deiconify( widget ):
print 'deiconifying the window'
widget.present()
return True

Python garbage collection and gtk windows

In the following program I have a button that spawns a popup. Simple enough. Now I connect the main window's delete-event to Gtk.main_quit() so that closing the main window closes the program.
Without that it will keep running until I kill the process (As evidenced by the occupied CLI prompt) The question then is: What happens to the popup window when I click it away?
Is the window itself automatically being destroyed at the delete-event or does it just hide itself and linger somewhere in memory until the program ends?
#!/usr/bin/python3
from gi.repository import Gtk
class MainWin(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
button = PopupButton()
self.add(button)
self.show_all();
self.connect("delete-event", Gtk.main_quit)
class PopupButton(Gtk.Button):
def __init__(self):
Gtk.Button.__init__(self, label="Popup")
self.connect("clicked", self.clicked)
def clicked(self, widget):
win = PopupWindow()
win.set_transient_for(self.get_toplevel())
win.show()
class PopupWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.add(Gtk.Label(label="Popups! Popups for everyone!"))
self.show_all()
win = MainWin()
win.show()
Gtk.main()
The default response to the delete-event signal is to destroy the window. So, unless you're handling that signal, the popup window is destroyed.

Categories