Adding widget in callback in GTK - python

How can I add a new widget from a callback function within a class? For example, I have a Gtk.Box and Gtk.Button and I want to add Gtk.Label to the Gtk.Box from callback function connected to button click. (this code doesn't work)
import gi
import os
gi.require_version("Gtk", "3.0")
from gi.repository import GLib, Gtk, GObject, Gio
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Delete Screenshots")
self.main_grid = Gtk.Grid()
self.main_grid.set_row_homogeneous(True)
self.add(self.main_grid)
self.screen_label = Gtk.Label()
self.screen_label.set_text("Test Label")
self.screen_label2 = Gtk.Label()
self.screen_label2.set_text("Test Label2")
self.label_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.label_box.homogeneous = True
self.button_search = Gtk.Button(label="Search")
self.button_search.connect("clicked", self.on_button_search_clicked)
self.button_delete = Gtk.Button(label="Delete")
self.button_delete.connect("clicked", self.on_button_delete_clicked)
self.main_grid.add(self.button_search);
self.main_grid.attach(self.button_delete, 1, 0, 1, 1);
self.main_grid.attach(self.label_box, 0, 1, 1, 1)
def on_button_search_clicked(self, widget):
self.label_box.pack_start(self.screen_label, True, True, 0)
def on_button_delete_clicked(self, widget):
print("Delete")
win = MainWindow()
win.set_default_size(50, 30)
win.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
How to add something to label_box from on_button_search_clicked?

Your code is basically correct. However all widgets need to be shown by either calling show() on them or show_all() on a parent widget. In your code, show_all() is called on the MainWindow instance. At that time, the widget you are adding in your callback is not attached to the window or any of its children. It will thus not be included in the show_all() call.
To fix this, simply call show() on your label in the callback:
...
def on_button_search_clicked(self, widget):
self.label_box.pack_start(self.screen_label, True, True, 0)
self.screen_label.show()
...

Related

python Gtk3 - Set label of button to default value of None

I am trying to reset a label of a button to its initial (default) value of None, which does not work as expected. Here's the minimal example:
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import Gtk
class GUI(Gtk.Window):
def __init__(self):
super().__init__()
self.connect('destroy', Gtk.main_quit)
self.set_position(Gtk.WindowPosition.CENTER)
self.grid = Gtk.Grid(hexpand=True, vexpand=True)
self.add(self.grid)
button = Gtk.Button(hexpand=True, vexpand=True)
self.grid.attach(button, 0, 0, 1, 1)
button.connect('clicked', self.on_button_clicked)
def on_button_clicked(self, button: Gtk.Button) -> None:
print(label := button.get_label(), type(label))
button.set_label(label)
def main() -> None:
win = GUI()
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()
Result:
$ python example.py
None <class 'NoneType'>
Traceback (most recent call last):
File "/home/neumann/example.py", line 21, in on_button_clicked
button.set_label(label)
TypeError: Argument 1 does not allow None as a value
What's the correct way to do this?
Note: Before somebody suggests it: I do not want to set the label to an empty string, since that will change the size of the button, which is noticeable on a larger grid of buttons:
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import Gtk
class GUI(Gtk.Window):
def __init__(self):
super().__init__()
self.connect('destroy', Gtk.main_quit)
self.set_position(Gtk.WindowPosition.CENTER)
self.grid = Gtk.Grid(hexpand=True, vexpand=True)
self.add(self.grid)
for x in range(3):
button = Gtk.Button(hexpand=True, vexpand=True)
button.connect('clicked', self.on_button_clicked)
self.grid.attach(button, x, 0, 1, 1)
def on_button_clicked(self, button: Gtk.Button) -> None:
print(label := button.get_label(), type(label))
button.set_label('')
def main() -> None:
win = GUI()
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()
I'm not sure what your use case is, but you can try adding a GtkLabel child and set the string there:
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import Gtk
class GUI(Gtk.Window):
def __init__(self):
super().__init__()
self.connect('destroy', Gtk.main_quit)
self.set_position(Gtk.WindowPosition.CENTER)
self.grid = Gtk.Grid(hexpand=True, vexpand=True)
self.add(self.grid)
for x in range(3):
button = Gtk.Button(hexpand=True, vexpand=True)
label = Gtk.Label()
button.add(label)
button.connect('clicked', self.on_button_clicked)
self.grid.attach(button, x, 0, 1, 1)
def on_button_clicked(self, button: Gtk.Button) -> None:
label = button.get_child()
print(text := label.get_label(), type(text))
label.set_label('')
# or hide it if you want
# label.hide()
def main() -> None:
win = GUI()
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()
GtkButton may be creating the internal GtkLabel child only when a label is set (which should be a valid string). And since the hexpand and vexpand for the GtkButton are set to True, they may be getting propagated to the internal GtkLabel.
If you simply want all the buttons to have same width and height, you may only need grid.set_row_homogeneous() and grid.set_column_homogeneous()

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 remove border around Gtk Widgets and Window?

I'm making a Gtk.Window using PyGi Gtk3 and It adds an annoying border around widgets and the main window:
The border is this grey border between the two images and in the outside of the window. Anyone knows how to completely remove it? So the two images could be seamless joint together.
This is my code:
#!/usr/bin/python3
#encoding:utf-8
from gi.repository import Gtk, Gdk
class TestMainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Test Window")
self.set_resizable(False)
self.box = Gtk.Box(orientation='vertical')
self.add(self.box)
self.album_cover = Gtk.Image()
self.album_cover.set_from_file('../reference/album-cover.jpg')
self.box.pack_start(self.album_cover, True, True, 0)
self.album_cover2 = Gtk.Image()
self.album_cover2.set_from_file('../reference/album-cover.jpg')
self.box.pack_end(self.album_cover2, True, True, 0)
def main():
win = TestMainWindow()
win.connect('delete-event', Gtk.main_quit)
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()
Give a try at setting the "margins" property inherited from GtkWidget to FALSE. In C this is done using g_object_set.

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