3

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
caveman
  • 422
  • 3
  • 17

1 Answers1

3

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.

caveman
  • 422
  • 3
  • 17
  • this is random but it seems like EventControllerKey cannot detect spacebar key presses. if you have any ideas I asked about this here https://stackoverflow.com/questions/73846699/detect-that-user-presses-spacebar-gtk4 – Colin D Sep 25 '22 at 18:12