I'm trying to write a simple GUI using Gtk4 (in Python), but I'm having trouble with getting rid of padding (and I don't understand why the padding is there).
The goal is pretty simple - I need a Gtk.Grid showing a bunch of images with some basic metadata. AFAICS a good way to do that is Window -> ScrollWindow -> Grid -> Box -> (Image + Label). And in general this works, except that the images have a lot of top/bottom padding, so the labels have a lot of empty space around, which I don't like but can't get rid of it :-(
See this screenshot
Here's a simple example demonstrating this:
import gi
import sys
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GdkPixbuf
def create_image(file_name, img_width, cssProvider = None):
info = 'file:' + file_name
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
# box.get_style_context().add_provider(cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
# box.add_css_class('thumbnail')
box.set_hexpand(True)
# add image to top
pixbuf = GdkPixbuf.Pixbuf.new_from_file(file_name)
# calculate height to keep width and aspect ratio
img_height = pixbuf.get_height() * img_width / pixbuf.get_width()
image = Gtk.Image.new_from_pixbuf(pixbuf)
image.set_size_request(img_height, img_width)
# image.get_style_context().add_provider(cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
# image.add_css_class('thumbnail-image')
box.append(image)
# add label to bottom
label = Gtk.Label(label=info)
# label.get_style_context().add_provider(cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
# label.add_css_class('thumbnail-label')
box.append(label)
return box
class MainWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.cssProvider = None
# self.cssProvider = Gtk.CssProvider()
# self.cssProvider.load_from_data(b"""
#.thumbnail {background-color: white; color: black; border: 1px solid #ddd; margin: 5px; padding: 0; }
#.thumbnail-label { font-size: 12pt; margin: 0; padding: 0; }
#.thumbnail-image { margin: 0; padding: 0; }
#.green { background-color: #bfb; }""")
self.set_default_size(900, 600)
self.set_title("MyApp")
self.grid = Gtk.Grid()
self.window = Gtk.ScrolledWindow()
self.window.set_child(self.grid)
self.set_child(self.window)
idx = 0
prev = None
for idx in range(0,20):
# 4 columns
i = int(idx / 4)
j = int(idx % 4)
image = create_image('frog.jpg', 1920/4 - 10, self.cssProvider)
self.grid.attach(image, j, i, 1, 1)
class MyApp(Gtk.Application):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.connect('activate', self.on_activate)
def on_activate(self, app):
self.win = MainWindow(application=app)
self.win.present()
app = MyApp(application_id="com.example.GtkApplication")
app.run(sys.argv)
This needs an image called 'frog.jpg', e.g. this one.
The sizes are meant to work on 1920x1080, with 4 columns. I'm sure it could be done more dynamic (i.e. to work better with resized windows etc.), but I believe that's a separate issue.
I've tried a bunch of things, including styling using CSS, etc. (which is commented-out in the sample).
I also experimented with setting hexpand/vexpand on different widgets, not adding the label, and various similar things.