caveman
caveman

Reputation: 444

How to bind a key press to a speccific action in GTK4?

This is an example from here:

import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk

def on_activate(app):
    win = Gtk.ApplicationWindow(application=app)
    btn = Gtk.Button(label="Hello, World!")
    btn.connect('clicked', lambda x: win.close())
    win.set_child(btn)
    win.present()

app = Gtk.Application(application_id='org.gtk.Example')
app.connect('activate', on_activate)
app.run(None)

My goal is to make the application close itself upon pressing key q anywhere in that window. This is also my question: how to achieve this with GTK4?


My attempts

1.

import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk

def on_activate(app):
    win = Gtk.ApplicationWindow(application=app)
    win.connect('key-pressed', lambda x,y: win.close())
    btn = Gtk.Button(label="Hello, World!")
    btn.connect('clicked', lambda x: win.close())
    win.set_child(btn)
    win.present()

app = Gtk.Application(application_id='org.gtk.Example')
app.connect('activate', on_activate)
app.run(None)

Running that code with python file.py gives this error:

Traceback (most recent call last):
  File "/home/caveman/lol/file.py", line 7, in on_activate
    app.connect('key-pressed', lambda x,y: win.close())
TypeError: <Gtk.Application object at 0x7fcd657fe600 (GtkApplication at 0x55bdc34c5210)>: unknown signal name: key-pressed

2.

import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk

class PressableWindow(Gtk.ApplicationWindow, Gtk.EventControllerKey):
    def __init__(self, app):
        super().__init__(application=app)

def on_activate(app):
    win = PressableWindow(app)
    win.connect('key-pressed', lambda x,y: win.close())
    btn = Gtk.Button(label="Hello, World!")
    btn.connect('clicked', lambda x: win.close())
    win.set_child(btn)
    win.present()

app = Gtk.Application(application_id='org.gtk.Example')
app.connect('activate', on_activate)
app.run(None)

Gives error:

Traceback (most recent call last):
  File "/home/caveman/lol/file.py", line 11, in on_activate
    win.connect('key-pressed', lambda x,y: win.close())
TypeError: <__main__.PressableWindow object at 0x7f8838b5f8c0 (__main__+PressableWindow at 0x555bddea82f0)>: unknown signal name: key-pressed

Upvotes: 3

Views: 1287

Answers (1)

caveman
caveman

Reputation: 444

This solves it. Apparently this is the GTK4 approach.

import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk

def lol(keyval, keycode, state, user_data, win):
    if keycode == ord('q'):
        win.close()

def on_activate(app):
    win = Gtk.ApplicationWindow(application=app)

    # new part
    keycont = Gtk.EventControllerKey()
    keycont.connect('key-pressed', lol, win)
    win.add_controller(keycont)

    btn = Gtk.Button(label="Hello, World!")
    btn.connect('clicked', lambda x: win.close())
    win.set_child(btn)
    win.present()

app = Gtk.Application(application_id='org.gtk.Example')
app.connect('activate', on_activate)
app.run(None)

Note 1. Apparently there is GtkAction which I guess can be used to create command bindings too. I'm still looking for that, since my scenario does not really require binding such actions to any GUI element. But as far as this question goes, this answers it.

Note 2. The whole code is very dirty and is taken from early examples from GTK's documentation. A better code would probably make use of classes, so I don't pass win manually.

Acknowledgements. Thanks to people in #gtk and #python in irc.gnome.org.

Upvotes: 4

Related Questions