I have a widget on which I am drawing in a python-gtk3 application, and clicking on it triggers a specific action. I want to show some visual feedback on hover, to indicate the widget is interactive. After figuring out cursors are not the way in Gtk3, I am trying to use a border, similar to what happens when hovering buttons.
After a lot of playing around, what I have seems to work when I query the widgets and CSS for what color they should have -- however the visuals are never updated. Here’s a minimal working example:
import gi
import cairo
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
# Event handlers
def on_da_click(widget, event):
print('Clicked!')
def on_da_hover(widget, event):
# Set widget state as this does not happen by default for DrawingArea
context = widget.get_style_context()
context.set_state(Gtk.StateFlags.PRELIGHT if event.type == Gdk.EventType.ENTER_NOTIFY else
Gtk.StateFlags.NORMAL)
# Check the color changed
print('Border color should now be', context.get_property('border-color', context.get_state()))
# ----- ISSUE IS HERE ----- #
# Tried various things to get the visual to update, none seem to work:
context.emit('changed')
widget.queue_draw()
widget.show_all()
# Create some widgets
da = Gtk.DrawingArea()
da.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK |
Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK)
da.connect('button-release-event', on_da_click)
da.connect('touch-event', on_da_click)
da.connect('enter-notify-event', on_da_hover)
da.connect('leave-notify-event', on_da_hover)
frame = Gtk.AspectFrame()
frame.set(.5, .5, 16/9, False)
frame.set_shadow_type(Gtk.ShadowType.NONE)
frame.get_style_context().add_class('grid-frame')
frame.add(da)
# Create a Window
win = Gtk.Window(title='Hello World')
win.set_default_size(400, 400)
win.connect('destroy', Gtk.main_quit)
win.add(frame)
win.show_all()
# Load a stylesheet for the whole app
css_loader = Gtk.CssProvider.new()
css_loader.load_from_data('''
.grid-frame > * {
border-style: solid;
border-width: 2px;
border-color: @theme_selected_bg_color;
}
.grid-frame > *:hover {
border-color: @theme_bg_color;
}
'''.encode())
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), css_loader,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
# Run
Gtk.main()
When I enter/exit the area I get the expected alternating colors in my messages:
Border color should now be Gdk.RGBA(red=0.000000, green=0.000000, blue=0.196078, alpha=1.000000)
Border color should now be Gdk.RGBA(red=0.000000, green=0.000000, blue=0.913725, alpha=1.000000)
Border color should now be Gdk.RGBA(red=0.000000, green=0.000000, blue=0.196078, alpha=1.000000)
Border color should now be Gdk.RGBA(red=0.000000, green=0.000000, blue=0.913725, alpha=1.000000)
However visually the border never changes color. How can I trigger the updated? The usual queue_draw
etc. do not work. My current gtk3 version is 3.24.35, but I’d like this to work over all Gtk 3.x.