How to properly show and hide GTK window in python - python

So I have the following code (python 2.7) that checks for a combination of keypresses and shows/hides a gtk window with a few gtk entry boxes. The show/hide works until the window locks up and stops responding, and the inner part of the window turns black. I have to kill the process and start it up again once that window turns black. I've tried all different combinations of show_all() and returning True after hiding the window to no avail. I'm not sure what I'm doing wrong here.
In the end I'd like to be able to press this key combination and show/hide this window without the contents going away.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
import pyxhook
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Configurator")
self.box = Gtk.Box(spacing=6)
self.add(self.box)
self.ipEntry = Gtk.Entry()
self.ipEntry.set_text("IP Address")
self.maskEntry = Gtk.Entry()
self.maskEntry.set_text("NetMask")
self.gatewayEntry = Gtk.Entry()
self.gatewayEntry.set_text("gatewayEntry")
self.button1 = Gtk.Button(label="Save")
self.button1.connect("clicked", self.on_button1_clicked)
self.box.pack_start(self.ipEntry, True, True, 0)
self.box.pack_start(self.maskEntry, True, True, 0)
self.box.pack_start(self.gatewayEntry, True, True, 0)
self.box.pack_start(self.button1, True, True, 0)
#catch window destroy event and stop it from happening
self.connect('delete-event', self.on_destroy)
def on_button1_clicked(self, widget):
print("Hello")
def on_destroy(self, widget=None, *data):
print("tried to destroy")
self.hide()
return True
#list of ascii keypresses to test if a certain combination of keys is pressed
keypresses = []
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
win.set_keep_above(True)
def OnKeyboardEvent(event):
#ascii 227 is l_control, ascii 225 is l_shift, ascii 120 is x
#bring the following external variables into the scope of this function
global keypresses
global win
#check if gtk window is hidden or visible
isVisible = win.get_property("visible")
#store our keypress if it is worthy of being stored (we started with a control character)
if event.Ascii == 227 or ( len(keypresses) >= 1 and keypresses[0] == 227 ):
print("here" + str(len(keypresses)))
keypresses.append(event.Ascii)
#check if we have three items in keypresses to compare, then see if it's the right combination
if len(keypresses) == 3 and keypresses[0] == 227 and keypresses[1] == 225 and keypresses[2] == 120:
#show/hide our window
if isVisible:
win.hide()
del keypresses[:]
keypresses = []
else:
win.show_all()
#clear out our list to compare again
del keypresses[:]
keypresses = []
elif len(keypresses) >= 3:
del keypresses[:]
keypresses = []
#create instance of hook manager
HookManager = pyxhook.HookManager()
#define our callback to fire when a key is pressed
HookManager.KeyDown = OnKeyboardEvent
#hook the keyboard
HookManager.HookKeyboard()
#start our listener
HookManager.start()
Gtk.main()
#close the hook listener when gtk main loop exits
HookManager.cancel()

Here is a small hack that tests the window show/hide when pressing F5. When you press it a second window will show or hide and i've tested for sometime without problems. Maybe it's the HookManager that somehow is messing with the Gtk/Glib mainloop. Nonetheless my method only works if there is a window to grab the key presses, so you will need, indeed, some form of grabbing key presses if your goal is to have no GUI:
#!/usr/bin/python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
#import pyxhook
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Configurator")
self.box = Gtk.Box(spacing=6)
self.add(self.box)
self.ipEntry = Gtk.Entry()
self.ipEntry.set_text("IP Address")
self.maskEntry = Gtk.Entry()
self.maskEntry.set_text("NetMask")
self.gatewayEntry = Gtk.Entry()
self.gatewayEntry.set_text("gatewayEntry")
self.button1 = Gtk.Button(label="Save")
self.button1.connect("clicked", self.on_button1_clicked)
self.box.pack_start(self.ipEntry, True, True, 0)
self.box.pack_start(self.maskEntry, True, True, 0)
self.box.pack_start(self.gatewayEntry, True, True, 0)
self.box.pack_start(self.button1, True, True, 0)
#catch window destroy event and stop it from happening
self.connect('delete-event', self.on_destroy)
self.connect('key-press-event', self.on_keypress)
def on_keypress(self, widget, event):
global w
if event.keyval == Gdk.KEY_F5:
isVisible = w.get_property("visible")
if (isVisible):
w.hide()
else:
w.show()
print("Keypress")
def on_button1_clicked(self, widget):
print("Hello")
def on_destroy(self, widget=None, *data):
print("tried to destroy")
self.hide()
return False
w = MyWindow()
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
win.set_keep_above(True)
Gtk.main()

Related

How to update widget dynamically in GTK3 (PyGObject)?

In this example, I'm trying to add another button (or any widget) every time a button is pressed.
from gi.repository import Gtk
class ButtonWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Button Demo")
self.hbox = Gtk.HBox()
self.add(self.hbox)
button = Gtk.Button.new_with_label("Click Me")
button.connect("clicked", self.on_clicked)
self.hbox.pack_start(button, False, True, 0)
def on_clicked(self, button):
print("This prints...")
button = Gtk.Button.new_with_label("Another button")
self.hbox.pack_start(button, False, True, 0) # ... but the new button doesn't appear
win = ButtonWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
I have tried queue_draw() and other hacks, but nothing has worked so far.
Calling the show_all() method works to update widgets' children. Here is the code with show_all() used, and the added line marked accordingly:
from gi.repository import Gtk
class ButtonWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Button Demo")
self.hbox = Gtk.HBox()
self.add(self.hbox)
button = Gtk.Button.new_with_label("Click Me")
button.connect("clicked", self.on_clicked)
self.hbox.pack_start(button, False, True, 0)
def on_clicked(self, button):
print("This prints...")
button = Gtk.Button.new_with_label("Another button")
self.hbox.pack_start(button, False, True, 0)
self.hbox.show_all() ### ADDED LINE
win = ButtonWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
So, calling self.hbox.show_all() shows all the children of self.hbox.

How to print only blue characters in textview

I want to get the characters printed only in blue.
How to do it?
Here is the sample program code, which is a fragment of most of the program.
I would be very grateful for your help.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
class TextViewWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="awesome gui")
self.set_resizable(True)
self.set_default_size(700, 550)
self.grid = Gtk.Grid()
self.add(self.grid)
self.create_textview()
self.buffer = []
def create_textview(self):
scrolledwindow = Gtk.ScrolledWindow()
scrolledwindow.set_hexpand(True)
scrolledwindow.set_vexpand(True)
self.grid.attach(scrolledwindow, 0, 2, 80, 1)
self.textview = Gtk.TextView()
scrolledwindow.add(self.textview)
self.textbuffer = self.textview.get_buffer()
self.textview.set_editable(False)
self.textview.set_cursor_visible(False)
self.textview.connect("key-press-event", self.on_key_down)
def on_key_down(self, widget, event, data=None):
znak_p = event.string
end_iter_m = self.textbuffer.get_iter_at_line_offset(1, 1)
qwerty_tag = self.textbuffer.create_tag(None, editable=True, foreground="blue")
self.textbuffer.insert_with_tags(end_iter_m, znak_p, qwerty_tag)
win = TextViewWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
Your on_key_down handler is wrong:
you are creating an anonymous tag every time you're pressing a key
you are using an invalid string for the GtkTextTag:foreground property
you are not returning a value from the callback telling GTK whether you handled the event (and thus should stop the event propagation) or not.
The GtkTextTag:foreground property uses the same format as the gdk_rgba_parse() function; if you want a blue color, you should use rgba(0.0, 0.0, 1.0, 1.0) instead of "blue".
A correct handler is:
def on_key_down(self, widget, event, data=None):
znak_p = event.string
end_iter_m = self.textbuffer.get
self.textbuffer.insert_with_tags(end_iter_m, znak_p, self.qwerty_tag)
return True

How to block / unblock signal handlers in pyGTK? Why handler_block() is not working?

I'm writing application which consist of a window with TextView and lot of dialog windows. TextView must connect to key-release-event signal and this collides with behavior of dialog windows.
The problem is that each time when user ends dialog window with enter key, dialog box disappears and TextView widget executes handler for key-release-event.
How to block key-release-event from executing, but only just after user closed dialog window with enter key?
This is small application witch demonstrates problem and is ready for testing possible solutions.
#!/usr/bin/env python
import gtk
class TestDialog(gtk.Dialog):
def __init__(self, parent):
gtk.Dialog.__init__(self, 'test', parent, gtk.DIALOG_MODAL, (gtk.STOCK_OK, gtk.RESPONSE_OK))
self.get_action_area().set_sensitive(False)
test_entry = gtk.Entry()
test_entry.connect('activate', self.__on_entry_activate)
self.vbox.pack_start(gtk.Label('Select entry and press Enter'), False, False)
self.vbox.pack_start(test_entry, False, False)
self.show_all()
def __on_entry_activate(self, event):
self.response(gtk.RESPONSE_OK)
class TestApp(gtk.Window):
def __init__(self):
gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
self.set_size_request(640, 480)
self.connect('destroy', lambda e: gtk.main_quit())
vbox = gtk.VBox()
test_button = gtk.Button('Press me')
test_button.connect('clicked', self.__on_test_button)
vbox.pack_start(test_button, False, False)
self.__text_view = gtk.TextView()
self.__id = self.__text_view.connect('key-release-event', self.__on_textview_key_release)
vbox.pack_start(self.__text_view, True, True)
self.add(vbox)
self.show_all()
def __on_textview_key_release(self, widget, event):
buff = self.__text_view.get_buffer()
buff.set_text('You have failed! TextView has executed key-release-event :P')
def __on_test_button(self, event):
self.__text_view.handler_block(self.__id)
dlg = TestDialog(self)
if dlg.run() == gtk.RESPONSE_OK:
self.__text_view.grab_focus()
dlg.destroy()
self.__text_view.handler_unblock(self.__id)
def run(self):
gtk.main()
app = TestApp()
app.run()

How to make progressbar works in python?

Imagine I want to make a simple program with GUI like this.
this is my code:
from gi.repository import Gtk
import gobject
class gui():
def __init__(self):
self.window = Gtk.Window()
self.window.connect('delete-event', Gtk.main_quit)
self.box = Gtk.Box()
self.window.add(self.box)
self.progressbar = Gtk.ProgressBar()
self.box.pack_start(self.progressbar, True, True, 0)
self.button = Gtk.Button(label='Start')
self.button.connect('clicked', self.on_button_clicked)
self.box.pack_start(self.button, True, True, 0)
self.window.show_all()
Gtk.main()
def on_button_clicked(self, widget):
self.task = self.iters(100000)
gobject.idle_add(self.task.next)
def iters(self, j):
i = j
while i > 0 :
i -= 1
print i
self.progressbar.set_fraction((j - float(i)) / j)
yield True
yield False
if __name__ == '__main__':
gui = gui()
I know how to make progressbar work if I put everything in one script like that.
But, what if I want to separate gui part from logic part? So, it would be like this:
GUI.py
from gi.repository import Gtk
class gui():
def __init__(self):
self.window = Gtk.Window()
self.window.connect('delete-event', Gtk.main_quit)
self.box = Gtk.Box()
self.window.add(self.box)
self.progressbar = Gtk.ProgressBar()
self.box.pack_start(self.progressbar, True, True, 0)
self.button = Gtk.Button(label='Start')
self.button.connect('clicked', self.on_button_clicked)
self.box.pack_start(self.button, True, True, 0)
self.window.show_all()
Gtk.main()
def on_button_clicked(self, widget):
//how to implement it
if __name__ == '__main__':
gui = gui()
Iteration.py
class Iteration():
def iters(self, j):
i = j
while i > 0 :
i -= 1
print i
EDIT:
One more thing, the first code above works, but why do I get this message:
/usr/lib/python2.7/dist-packages/gobject/constants.py:24: Warning: g_boxed_type_register_static: assertion `g_type_from_name (name) == 0' failed
import gobject._gobject
EDIT:
Okay, imagine I have one module like this one:
Works.py
def getImageFromInternet(uri):
#some code to get image from internet
this getImageFromInternet function is not iterable. What I want to do is processing this function in the background while updating the progressbar and doing other thing with gui. Do I need a thread for this?
Create a generator that updates the GUI and drives the underlying data model generator, and pass that to idle_add. For example (untested):
def on_button_clicked(self, widget):
cnt = 10000
task = self.iters(cnt)
def gui_iter():
for i, ignore in enumerate(task, 1):
self.progressbar.set_fraction(i / cnt)
yield True
yield False
gobject.idle_add(gui_iter().next)

How do I add colour to this and make it look better for the user?

I can Add boxs and Tables
Also the Quit button does not work can someone edit that part of the code please
import gtk
class helloworld:
def close(self,widget):
print "I'm outta here"
gtk.main_quit()
def printit(self,widget,lab1):
print lab1.get_text()
def filllab(self,widget,lab1):
lab1.set_text(widget.get_text())
def __init__(self):
window = gtk.Window()
window.set_size_request(300,400)
vbox = gtk.VBox()
window.add(vbox)
lab1 = gtk.Label("shazbut")
# entry widget
ent1 = gtk.Entry()
ent1.connect("activate",self.filllab,lab1)
# quit
quitb = gtk.Button("quit",gtk.STOCK_QUIT)
quitb.set_size_request(50,100)
quitb.connect("destroy", gtk.main_quit)
printb = gtk.Button("print")
printb.connect("clicked",self.printit,lab1)
# Pack widgets in the vbox
vbox.add(ent1)
vbox.add(lab1)
vbox.add(quitb)
vbox.add(printb)
window.show_all()
helloworld()
gtk.main()
The "quit" button doesn't work because you connected the "destroy" signal to the button instead of the clicked signal
quitb.connect("clicked", gtk.main_quit)
Also, you forgot to connect the window destroy event (so the program will never exit when you click the window close button). Add
window.connect("destroy", gtk.main_quit)
To change the label properties use the pango attributes
def _add_attributes_to_label(self,label):
attr = pango.AttrList()
fg_color = pango.AttrForeground(65535, 0, 0,0,-1)
strike = pango.AttrStrikethrough(True,0,-1)
size = pango.AttrSize(30000, 0, -1)
attr.insert(fg_color)
attr.insert(size)
attr.insert(strike)
label.set_attributes(attr)
In your init function call the previous function like this:
self._add_attributes_to_label(lab1)
Follow this tutorial to know more about pango attributes.

Categories