What:
Gtk+ 3 with PyGObject bindings and Python 2.7.
Question:
How can I get the value of a GParamObject? I assume it has a value, (otherwise what would be the point of it?) but I have spent several hours googling and experimenting and have not been able find the answer to this seemingly simple question. Maybe my assumption that is has a value is unfounded.
Background: I have a Gtk.Stack, and I have connected a callback to the "notify::visible-child" signals that does some stuff when the visible-child changes. Something like this
stack.connect("notify::visible-child", on_stack_changed)
def on_stack_changed(stack, param):
print "stack's visible child changed"
print param # Prints: <GParamObject 'visible-child'>
Now, since the GTK.Stack docs indicate that the visible_child property's value is the visible child widget, I expect to be able to get a reference to the widget from the param passed to my callback. But I have not been able to figure out how to get any value from the GParam object.
I have tried every variation of things like param.value, param.get_value() etc. that I could think of, but to no avail.
Of course, since the stack object is also passed to my callback, I could always do stack. get_visible_child(), but that is no fun, is it? :D
So, any explanation of the GParamObject, its intended use, or links to examples of its use would be greatly appreciated.
Edit: Here is a standalone example.
#!/usr/bin/env python
import os, gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk, Gdk
def on_stack_changed(stack, param):
for attr in dir(param):
print "{}: {}".format(attr, getattr(param, attr))
stack = Gtk.Stack()
stack.add_titled(Gtk.Label('Child 1'), 'child1', 'Child 1')
stack.add_titled(Gtk.Label('Child 2'), 'child2', 'Child 2')
stack.connect("notify::visible-child", on_stack_changed)
stack_switcher = Gtk.StackSwitcher(stack=stack)
header_bar = Gtk.HeaderBar(custom_title=stack_switcher, show_close_button=True)
window = Gtk.Window()
window.set_default_size(500, 250)
window.set_titlebar(header_bar)
window.add(stack)
window.connect('destroy', Gtk.main_quit)
window.show_all()
Gtk.main()
As suggested by liberforce, I tried print dir(param) which results in this output:
__doc__: The widget currently visible in the stack
__gtype__: <GType GParamObject (94151103218704)>
blurb: The widget currently visible in the stack
flags: 1073742051
name: visible-child
nick: Visible child
owner_type: <GType GtkStack (94151105445744)>
value_type: <GType GtkWidget (94151104851072)>
This helps a great deal in understanding what information is available from the GParamObject. As expected the value_type is a GtkWidget, but I still don't see how to get the value itself.
I think it's because it doesn't exist there. What you get in param seems to be a GParamSpec which is just metadata about a parameter, holding its name, type, flags... I can't find a reference on GParamObject in the PyGObject documentation. But If I look the C documentation of the notify signal, indeed, thats a GParamSpec that is passed there, so that may be a GObject.ParamSpecObject
So I think your get_visible_child is the way to go. You may get the same result in a more flexible way using using the GParamSpec with stack.get_property(param.name).
UPDATE:
Here's the standalone example modified:
In the callback, I use 3 different ways of getting the visible child, all working. They all return the same object instance, as confirmed by id.
#!/usr/bin/env python
import os, gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk, Gdk
def on_stack_changed(stack, param):
print 'stack.get_visible_child(): {}'.format(id(stack.get_visible_child()))
print 'stack.get_property(param.name): {}'.format(id(stack.get_property(param.name)))
print 'stack.props.visible_child: {}'.format(id(stack.props.visible_child))
stack = Gtk.Stack()
stack.add_titled(Gtk.Label('Child 1'), 'child1', 'Child 1')
stack.add_titled(Gtk.Label('Child 2'), 'child2', 'Child 2')
stack.connect("notify::visible-child", on_stack_changed)
stack_switcher = Gtk.StackSwitcher(stack=stack)
header_bar = Gtk.HeaderBar(custom_title=stack_switcher, show_close_button=True)
window = Gtk.Window()
window.set_default_size(500, 250)
window.set_titlebar(header_bar)
window.add(stack)
window.connect('destroy', Gtk.main_quit)
window.show_all()
Gtk.main()
Using print vars(param) may help you see what is really in your object.
Related
I'm new to GTK3 so I thought it would be a good idea to use type checking to have instant access to the docs. However I can't make it work. This is the code I'm using to test if it works.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib
mainBox: Gtk.Box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=1)
Box is defined inside Gtk.pyi and Pycharm says it is overriden by ToolbarGTK3 but when I run the above code the runtime type is gi.override.Gtk.Box and this is confusing to me. Thanks in advance!
I have been trying to make a simple Gtk application that includes a Side Bar similar to the side bar in the Lollypop music player (as seen here https://youtu.be/2IhJCrKz3N4 ), I don't which layout container is the best for such a thing , I tried Gtk.Box with vertical orientation but the result similar to what I want. can someone suggest a better solution for this and a way to place this side bar on the window while keeping it's side fixed.
For new developer it may be difficult to dig into source code of some software, but it is really helps you in long run. Please check out source code of Lollypop at https://gitlab.gnome.org/World/lollypop for functionality you are taking about.
Apart from that, in below code I try to give you head start from what I understood from your question.
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="Side Bar")
self.hbox = Gtk.HBox();
self.vbox = Gtk.VBox();
self.button1 = Gtk.Button(label="1")
self.button1.connect("clicked", self.on_button_clicked)
self.button2 = Gtk.Button(label="2")
self.button2.connect("clicked", self.on_button_clicked)
self.button3 = Gtk.Button(label="3")
self.button3.connect("clicked", self.on_button_clicked)
self.button4 = Gtk.Button(label="4")
self.button4.connect("clicked", self.on_button_clicked)
self.vbox.add(self.button1);
self.vbox.add(self.button2);
self.vbox.add(self.button3);
self.vbox.add(self.button4);
self.entry = Gtk.Entry();
self.entry.set_text("1");
self.hbox.add(self.vbox);
self.hbox.add(self.entry);
self.add(self.hbox);
self.maximize()
def on_button_clicked(self, widget):
self.entry.set_text(widget.get_label());
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
Implementation of Lollypop may be very different from above one, because it may need to handle many more things like responsive size of button while resizing, look and feel with different themes, etc.
ADVISE: Keep digging and contributing to open source software to learn more.
You may run GTK_DEBUG=interactive your-app to use gtk-inspector. It lets you examine an existing user-interface, like lollypop, and check how the widgets are bound together.
Please read the interactive debugging section of the documentation.
For more detail, as Mathan Tilva said, you can give a look to the source code.
I want to make keyboard shortcuts like t, that would work, when the main window is closed (but process is running, as the programme has a unity appindicator). I saw a package keybinder, but it seems, one can't use it with Gtk3 and pygobject. Or can? Then how? If not, is there any other way to do that?
The application is for linux (ubuntu), I use python 2.7.
Keybinder works fine with python3, Gtk3, and pygi. There just wasn't a working example in the source tree.
#!/usr/bin/env python3
"""
example-gi-py3.py
Looked at a pull request that was built for py2.x, but
overwrote the original py instead of making a separate example.
I wouldn't have accepted that pull request either.
The keybinder.init() part wasn't in the original example.
aking1012.com#gmail.com
public domain
"""
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Keybinder', '3.0')
from gi.repository import Gtk
from gi.repository import Keybinder
def callback(keystr, user_data):
print ("Handling", user_data)
print ("Event time:", Keybinder.get_current_event_time())
Gtk.main_quit()
if __name__ == '__main__':
keystr = "<Ctrl><Alt>M"
Keybinder.init()
Keybinder.bind(keystr, callback, "keystring %s (user data)" % keystr)
print ("Press", keystr, "to handle keybinding and quit")
Gtk.main()
Notes:
Not thoroughly tested, but as a simple example it seems to work.
I use also Keybinder to activate a search entry field in a Gtk3 app:
from gi.repository import Keybinder
…
class MyApp:
…
Keybinder.init()
Keybinder.bind("<Ctrl>F", self.set_search_entry_focus)
…
def set_search_entry_focus(self, keystring):
self.search_entry.grab_focus()
http://lazka.github.io/pgi-docs/Keybinder-3.0/
But be aware, this will also steal focus if if you are using another app and your app is running in the background.
With introduction of GObject introspection the way to access theme colors through widget.get_style() method is gone. I am interested on how to get theme colors when GTK+ is used through GOBject introspection. The solution should preferably work with both versions (2 and 3) but a solution for each of these is acceptable as well.
I'm not sure how to get it from gtk+-2.0, unless your using a pure gtk+-2.0 environment, in which case I think the old GtkStyle methods work. for example, assuming your not running a Gtk-3.0 environment like gnome-shell
import gi
# make sure you use gtk+-2.0
gi.require_version('Gtk', '2.0')
from gi.repository import Gtk
window = Gtk.Window()
...
style = window.get_style()
print style.lookup_color('fg_color')
I think that should still work under a gtk+-2.0 environment. I don't know for sure as my system is running gnome-shell, and can't easily try this out.
However this method has been deprecated and replaced by GtkStyleContext. If I use the above code in a gtk+-3.0 environment like gnome-shell it will run, but does not give me the information I'm after. What I get is
(False, <Gdk.Color(red=0, green=0, blue=0)>)
EDIT: Looking back at this, I think the above is still giving the correct info. The colour for fg_color is not found, as indicated by the first entry in the tuple result, which is False. Also the window must be visible for the colours to be found.
If I want colour information I want to use the new GtkStyleContext, for example
import gi
# make sure you use gtk+-3.0
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
window = Gtk.Window()
...
style_context = window.get_style_context()
print style_context.lookup_color('fg_color')
this will give me some real data, which is telling me the 'fg_color' has been found, due to the first entry in the tuple is True.
(True, <Gdk.Color(red=0.000000, green=0.000000, blue=0.000000, alpha=1.000000)>)
I hope this answers your question.
I'm trying to keep dependencies to a minimum for a program I contribute to, it's a small text editor.
GTK Textview doesn't seem to come with a built-in undo function. Is there any reference implementation I've been missing on so far? Is everyone writing their own undo function for their TextView widgets?
I'll be happy about any sample code - most happy about python sample code, as our project is in python.
as a follwow-up: I ported gtksourceview's undo mechanism to python: http://bitbucket.org/tiax/gtk-textbuffer-with-undo/
serves as a drop-in replacement for gtksourceview's undo
(OP here, but launchpad open-id doesn't work anymore)
As far as I know, GTK TextView doesn't include an undo function. So while I am not familiar with Python's GTK library, I would think it doesn't have one.
The Ruby-GNOME2 project has a sample text editor that has undo/redo functionality. Basically they are connecting to the insert_text and delete_range signals of the TextView widget and recording the events and associated data in a list.
Depending on just how dependency-averse you are, and what kind of text editor you're building, GtkSourceView adds undo/redo among many other things. Very worth looking at if you want some of the other features it offers.
Use GtkSource
https://wiki.gnome.org/Projects/GtkSourceView
https://lazka.github.io/pgi-docs/GtkSource-3.0/
https://lazka.github.io/pgi-docs/GtkSource-3.0/classes.html
.
[Cmnd] + [Z] for undo (default)
[Cmnd] + [Shift] + [Z] for redo (default)
[Cmnd] + [Y] for redo (added manually)
example:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
gi.require_version('GtkSource', '3.0')
from gi.repository import GtkSource
import os
class TreeviewWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="TreeviewWindow")
self.set_size_request(300, 300)
self.connect("key-press-event", self._key_press_event)
self.mainbox = Gtk.VBox(spacing=10)
self.add(self.mainbox)
self.textbuffer = GtkSource.Buffer()
textview = GtkSource.View(buffer=self.textbuffer)
textview.set_editable(True)
textview.set_cursor_visible(True)
textview.set_show_line_numbers(True)
self.mainbox.pack_start(textview, True, True, 0)
self.show_all()
def _key_press_event(self, widget, event):
keyval_name = Gdk.keyval_name(event.keyval)
ctrl = (event.state & Gdk.ModifierType.CONTROL_MASK)
if ctrl and keyval_name == 'y':
if self.textbuffer.can_redo():
self.textbuffer.do_redo(self.textbuffer)
def main(self):
Gtk.main()
if __name__ == "__main__":
base = TreeviewWindow()
base.main()