How to update widget dynamically in GTK3 (PyGObject)? - python

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.

Related

How to pass/return data from Gtk dialog to main application class

I have an application in Python Gtk. I have my main Application class in my main file. I then have all my dialogs in a different file. I need to be able to pass/return custom data from the dialog to the main application class other than the standard Gtk response codes, here is some basic example code as my own code is very long:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class DialogWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Dialog Example")
self.set_border_width(6)
button = Gtk.Button("Open dialog")
button.connect("clicked", self.on_button_clicked)
self.add(button)
def on_button_clicked(self, widget):
dialog = DialogExample(self)
response = dialog.run()
if response == Gtk.ResponseType.OK:
print("The OK button was clicked")
elif response == Gtk.ResponseType.CANCEL:
print("The Cancel button was clicked")
dialog.destroy()
win = DialogWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
The dialog window in a separate file:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class DialogExample(Gtk.Dialog):
def __init__(self, parent):
Gtk.Dialog.__init__(self, "My Dialog", parent, 0,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK))
self.set_default_size(150, 100)
label = Gtk.Label("This is a dialog to display additional information")
box = self.get_content_area()
box.add(label)
self.show_all()
As standard we apply the Gtk.ResponseType to the buttons. But what if we want to return some custom data - not just a simple response code - as a further code example:
class DialogExample(Gtk.Dialog):
def __init__(self, parent):
Gtk.Dialog.__init__(self, "My Dialog", parent, 0)
self.set_default_size(150, 100)
label = Gtk.Label("This is a dialog to display additional information")
button = Gtk.Button("Return something")
button.connect("clicked", self.on_button_clicked)
box = self.get_content_area()
box.add(label)
self.show_all()
def on_button_clicked(self, widget):
if SOME_CONDITION:
return <CUSTOM_RESPONSE>
else:
return <ALT_CUSTOM_RESPONSE>
When I do the last example the dialog does not return anything, I would like to do something like:
class DialogWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Dialog Example")
self.set_border_width(6)
button = Gtk.Button("Open dialog")
button.connect("clicked", self.on_button_clicked)
self.add(button)
def on_button_clicked(self, widget):
dialog = DialogExample(self)
response = dialog.run()
if response == <CUSTOM_RESPONSE>:
#do something with <CUSTOM_RESPONSE>
elif response == <ALT_CUSTOM_RESPONSE>:
#do something different with <ALT_CUSTOM_RESPONSE>
dialog.destroy()
win = DialogWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
The DialogExample window does not destroy/close and nothing is returned and the application basically just pauses as it thinks there are no more methods to run - although there is much to be done after the return of the custom data (I need to then start adding records to a database).
[UPDATE]
I have now tried so many various things to solve this issue I could not possibly list them all here. I have searched endlessly for some kind of answer and it would seem this is not something that is done by anyone on the Internet.
The C version of gtk_dialog_run is limited to return integers, you can set custom values but nothing like strings or objects. You can workaround this by setting a value on the "response" signal and then get it after the run function returns.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class DialogExample(Gtk.Dialog):
def __init__(self, parent):
Gtk.Dialog.__init__(self, "My Dialog", parent, 0,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK))
self.result = ""
self.set_default_size(150, 100)
self.connect("response", self.on_response)
label = Gtk.Label(label="Type something")
self.entry = Gtk.Entry()
box = self.get_content_area()
box.add(label)
box.add(self.entry)
self.show_all()
def on_response(self, widget, response_id):
self.result = self.entry.get_text ()
def get_result(self):
return self.result
class DialogWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Dialog Example")
self.set_border_width(6)
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
self.add(box)
button = Gtk.Button(label="Open dialog")
button.connect("clicked", self.on_button_clicked)
box.add(button)
self.label = Gtk.Label()
box.add(self.label)
def on_button_clicked(self, widget):
dialog = DialogExample(self)
response = dialog.run()
if response == Gtk.ResponseType.OK:
self.label.set_text(dialog.get_result())
print("The OK button was clicked")
elif response == Gtk.ResponseType.CANCEL:
print("The Cancel button was clicked")
dialog.destroy()
win = DialogWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

How to properly show and hide GTK window in 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()

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()

Python Gtk3 Box doesn't hide

I'm writing an application. It has a sidebar, which I want to be shut on startup. I have tried using self.sidebarbox.hide(). This only seems to work when I put it in a function that is linked to a button. When I press the button it shows/hides. How can I fix this?
Here is my code (It's written in python3 but will run in python2.):
from gi.repository import Gtk, Gio
from gi.repository import WebKit
HEIGHT = 500
WIDTH = 800
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Resolution")
self.set_border_width(0)
self.set_default_size(WIDTH, HEIGHT)
hb = Gtk.HeaderBar()
hb.props.show_close_button = True
hb.props.title = "Resolution"
hb.props.subtitle = "Digital Maths Revision Guide"
self.set_titlebar(hb)
button = Gtk.Button()
icon = Gio.ThemedIcon(name="emblem-system-symbolic")
image = Gtk.Image.new_from_gicon(icon, 1)
button.add(image)
button.connect("clicked", self.sidebarShowHide)
button.set_focus_on_click(False)
hb.pack_start(button)
self.sidebarbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
toplevelbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
self.add(toplevelbox)
toplevelbox.pack_start(self.sidebarbox, False, False, 0)
self.searchentry = Gtk.SearchEntry()
self.searchentry.connect("search-changed", self.search_changed)
self.sidebarbox.pack_start(self.searchentry, False, False, 0)
label = Gtk.Label("Contents Selector")
self.sidebarbox.pack_start(label, True, True, 0)
scroller = Gtk.ScrolledWindow()
content = WebKit.WebView()
scroller.add(content)
toplevelbox.pack_start(scroller, True, True, 0)
content.open("/home/oliver/resolution/placeholder.html")
#This should make the sidebar hide.
self.sidebarbox.hide()
#This works. The sidebar does show/hide.
def sidebarShowHide(self, button):
if self.sidebarbox.get_visible():
self.sidebarbox.hide()
else:
self.sidebarbox.show()
def search_changed(self, searchentry):
pass
win = MainWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
You're calling show_all() which changes the state of all contained widgets to visible, including the sidebar.
If you still like to use it (it's convenient after all) one way is you're own method, which will hide the sidebar after showing all, e.g:
from gi.repository import Gtk, Gio
from gi.repository import WebKit
HEIGHT = 500
WIDTH = 800
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Resolution")
self.set_border_width(0)
self.set_default_size(WIDTH, HEIGHT)
hb = Gtk.HeaderBar()
hb.props.show_close_button = True
hb.props.title = "Resolution"
hb.props.subtitle = "Digital Maths Revision Guide"
self.set_titlebar(hb)
button = Gtk.Button()
icon = Gio.ThemedIcon(name="emblem-system-symbolic")
image = Gtk.Image.new_from_gicon(icon, 1)
button.add(image)
button.connect("clicked", self.sidebarShowHide)
button.set_focus_on_click(False)
hb.pack_start(button)
self.sidebarbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
toplevelbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
self.add(toplevelbox)
toplevelbox.pack_start(self.sidebarbox, False, False, 0)
self.searchentry = Gtk.SearchEntry()
self.searchentry.connect("search-changed", self.search_changed)
self.sidebarbox.pack_start(self.searchentry, False, False, 0)
label = Gtk.Label("Contents Selector")
self.sidebarbox.pack_start(label, True, True, 0)
scroller = Gtk.ScrolledWindow()
content = WebKit.WebView()
scroller.add(content)
toplevelbox.pack_start(scroller, True, True, 0)
content.open("/home/oliver/resolution/placeholder.html")
def inital_show(self):
win.show_all()
self.sidebarbox.hide();
#This works. The sidebar does show/hide.
def sidebarShowHide(self, button):
if self.sidebarbox.get_visible():
self.sidebarbox.hide()
else:
self.sidebarbox.show()
def search_changed(self, searchentry):
pass
if __name__ == '__main__':
win = MainWindow()
win.connect("delete-event", Gtk.main_quit)
win.inital_show()
Gtk.main()
Note the initial_show() method, and calling it from the main section.

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