Search code examples
python-3.xpygtk

Prevent manual text entry in a PyGTK SpinButton


Using Python 3.8, GTK 3.0, I would like to prevent the user from manually entering text in a Gtk.SpinButton(), while leaving the +/- / up/down portion of the SpinButton functional. Is this possible?

I tried set_editable(False), but that disables the entire widget, including the up/down arrows.

I thought maybe there's a way to access the Gtk.Entry() portion of the SpinButton, and call set_editable(False) only on that child, but have not found it yet.

EDIT: Here is some demo code

The goal is to have the text entry field of spin1 disabled (ideally insensitive, so the cursor cannot appear when clicked), while the +/- buttons still work, and still update the value. spin2 & spin3 go too far, as even the +/- buttons don't work.

import gi

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


class SpinButtonWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="SpinButton Demo")
        self.set_border_width(10)

        grid = Gtk.Grid()
        grid.set_column_spacing(6)
        grid.set_row_spacing(4)
        self.add(grid)

        adj1 = Gtk.Adjustment()
        adj1.configure(0, 0, 100, 10, 10, 0)
        spin1 = Gtk.SpinButton()
        spin1.set_adjustment(adj1)
        grid.attach(spin1, 0, 0, 1, 1)

        adj2 = Gtk.Adjustment()
        adj2.configure(0, 0, 100, 10, 10, 0)
        spin2 = Gtk.SpinButton()
        spin2.set_adjustment(adj2)
        spin2.set_editable(False)
        grid.attach(spin2, 1, 0, 1, 1)

        adj3 = Gtk.Adjustment()
        adj3.configure(0, 0, 100, 10, 10, 0)
        spin3 = Gtk.SpinButton()
        spin3.set_adjustment(adj3)
        spin3.set_sensitive(False)
        grid.attach(spin3, 2, 0, 1, 1)

        label1 = Gtk.Label(label='Basic Spin')
        label1.set_halign(Gtk.Align.CENTER)
        grid.attach(label1, 0, 1, 1, 1)

        label2 = Gtk.Label(label='Editable=False')
        label2.set_halign(Gtk.Align.CENTER)
        grid.attach(label2, 1, 1, 1, 1)

        label3 = Gtk.Label(label='Sensitive=False')
        label3.set_halign(Gtk.Align.CENTER)
        grid.attach(label3, 2, 1, 1, 1)


win = SpinButtonWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

Solution

  • You can configure spin1 to ignore most key presses.

    Change the imports:

    from gi.repository import Gtk, Gdk
    

    Add the following method to SpinButtonWindow class:

    def key_handler(self, widget, event):
        key = Gdk.keyval_name(event.keyval)
        if key in ['Up', 'Down', 'Page_Up', 'Page_Down']:
            return widget.im_context_filter_keypress(event)
        # Ignore other keys.
        return True
    

    Connect this method to the spinbox:

    spin1 = Gtk.SpinButton()
    spin1.connect("key-press-event", self.key_handler)