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.
Apparently using Gtk.Picture instead of Gtk.Image solves the issue - with Picture there's no unwanted empty space/padding. Seems a bit confusing, considering Picture/Image are often used as synonyms. Maybe it's in the gtk docs somewhere, but I don't see it - certainly not without reading between the lines. I see some discussion of "natural size" but I don't see how'd that imply this behavior. Anyway, if others face the same issue, try using Gtk.Picture.
When trying out the Material-UI basic example for Tree View (#mui/lab/TreeView), I do not know how to remove the horizontal scrollbar when using the overflowY: "auto" (The same effect even if I use overflow: "auto") option in the sx prop of the TreeView component. The horizontal scrollbar appears no matter how much space is available to the right. I want to keep the overflowY option in case of vertical overflow.
For example please see the basic tree view example from the official Material-UI page in StackBlitz or CodeSandbox.
How to remove the horizontal scrollbar when it's not needed?
This happens because the CSS classes .MuiTreeItem-content and its child .MuiTreeItem-label are set to 100% width by default, therefore, the .MuiTreeItem-content's 8px padding on x axis (also default) get in the way, adding 16px too many. You can easily override this by setting .MuiTreeItem-content's class padding to 0.
// ...
import MuiTreeItem from "#mui/lab/TreeItem";
import { styled } from "#mui/material/styles";
const TreeItem = styled(MuiTreeItem)(({ theme }) => ({
"& .MuiTreeItem-content": {
padding: 0,
},
}));
// ...
To remove the horizontal scrollbar completely you can hide the overflow over the X axis.
in css
.TreeView {
overflow-x: hidden;
}
or in jsx
<TreeView
sx={{ overflowX: "hidden" }}
...
>
I am trying to make a GUI program in Julia using Gtk. My program includes a large number of GtkEntry boxes. However, I am running into space issues because the Entry boxes have a lot of internal padding around the actual characters. I would like to reduce, at least, the top and bottom whitespace. I have tried to use the setproperty!() function to change the height-request value, but that seems to be only able to make the box bigger, not smaller. Additionally, the margin, margin-top, etc. fields are all set to 0 by default. Again, I can make them bigger but not smaller.
Is this possible to fix? I have included below a minimal working example, a screenshot, and a Julia REPL output displaying the available properties.
Edit:
I have also tried using a css file (test.css) with the contents
entry {
margin-top: 0;
margin-bottom: 0;
padding-top: 0;
padding-bottom: 0;
}
Julia 0.6.0 code:
using Gtk
win = GtkWindow("Example")
sb = GtkGrid()
function sb_entry(label)
frame = GtkFrame(label)
entry = GtkEntry()
setproperty!(entry, :input_purpose, 2)
push!(frame, entry)
return frame
end
sb_rows = sb_entry("rows")
sb_cols = sb_entry("cols")
sb_row_off = sb_entry("row off")
sb_col_off = sb_entry("col off")
sb[1,1] = sb_rows
sb[2,1] = sb_cols
sb[1,2] = sb_row_off
sb[2,2] = sb_col_off
setproperty!(sb, :column_homogeneous, true)
setproperty!(sb, :column_spacing, 5)
setproperty!(sb, :row_spacing, 5)
push!(win, sb)
### begin edit (css)
screen = Gtk.GAccessor.screen(win)
provider = GtkCssProviderLeaf(filename="/path/to/test.css")
ccall((:gtk_style_context_add_provider_for_screen, Gtk.libgtk), Void,
(Ptr{Void}, Ptr{GObject}, Cuint),
screen, provider, 1)
### end edit (css)
showall(win)
if !isinteractive()
c = Condition()
signal_connect(win, :destroy) do widget
notify(c)
end
wait(c)
end
julia> sb_row_off[1]
Gtk.GtkEntryLeaf(editing-canceled=FALSE, name="", parent, width-request=-1,
height-request=-1, visible=TRUE, sensitive=TRUE, app-paintable=FALSE,
can-focus=TRUE, has-focus=FALSE, is-focus=TRUE, focus-on-click=TRUE,
can-default=FALSE, has-default=FALSE, receives-default=FALSE, composite-child=FALSE,
style, events=0, no-show-all=FALSE, has-tooltip=FALSE, tooltip-markup=NULL,
tooltip-text=NULL, window, opacity=1.000000, double-buffered, halign=GTK_ALIGN_FILL,
valign=GTK_ALIGN_FILL, margin-left, margin-right, margin-start=0, margin-end=0,
margin-top=0, margin-bottom=0, margin=0, hexpand=FALSE, vexpand=FALSE,
hexpand-set=FALSE, vexpand-set=FALSE, expand=FALSE, scale-factor=2, buffer,
cursor-position=0, selection-bound=0, editable=TRUE, max-length=0, visibility=TRUE,
has-frame=TRUE, inner-border, invisible-char=9679, activates-default=FALSE,
width-chars=-1, max-width-chars=-1, scroll-offset=0, text="", xalign=0.000000,
truncate-multiline=FALSE, shadow-type, overwrite-mode=FALSE, text-length=0,
invisible-char-set=FALSE, caps-lock-warning=TRUE, progress-fraction=0.000000,
progress-pulse-step=0.100000, primary-icon-pixbuf, secondary-icon-pixbuf,
primary-icon-stock, secondary-icon-stock, primary-icon-name=NULL,
secondary-icon-name=NULL, primary-icon-gicon, secondary-icon-gicon,
primary-icon-storage-type=GTK_IMAGE_EMPTY,
secondary-icon-storage-type=GTK_IMAGE_EMPTY, primary-icon-activatable=TRUE,
secondary-icon-activatable=TRUE, primary-icon-sensitive=TRUE,
secondary-icon-sensitive=TRUE, primary-icon-tooltip-text=NULL,
secondary-icon-tooltip-text=NULL, primary-icon-tooltip-markup=NULL,
secondary-icon-tooltip-markup=NULL, im-module=NULL, placeholder-text=NULL,
completion, input-purpose=GTK_INPUT_PURPOSE_DIGITS, input-hints=GTK_INPUT_HINT_NONE,
attributes, populate-all=FALSE, tabs)
entry { min-height: 0px; } allows it to be as small as possible. Adjust size as required.
I'm using Vala with GTK+ and now I'm trying to add custom CSS to specified widget.
I can add fe. backgroudn to GtkWidget but not for #sidebar
#sidebar { //It doesn't work
color: white;
}
GtkWindow { // It works
background-color: red;
}
I'm adding class to widget like that:
sidebar = new Gtk.Label("Hello");
sidebar.set_name("sidebar");
And it's changes color to GtkWindow, but not for this label.
Any ideas?
I haven't programmed in Vala, but you should add class to StyleContext.
This is in C
sidebar = gtk_label_new ("Hello');
gtk_style_context_add_class ( gtk_widget_get_style_context ("mysidebar"), sidebar);
Also, style "sidebar", is already defined in GtkStyle. You should change the "sidebar" in CSS into something else (sidebar is used by views, toolbar etc)
But if you persist, the syntax should be:
.mysidebar {
#anything
}
function doGet() {
var app = UiApp.createApplication();
var flex = app.createFlexTable();
for (var i = 1; i<=30; i++)
flex.setWidget(i, 0, app.createButton('Button '+i).setId('Button'+i).setVisible(false));
app.getElementById('Button1').setVisible(true);
var submit = app.createButton('Submit');
app.add(flex).add(submit);
return app;
}
Produces this Ui.
How can we eliminate the empty space between the first visible button and the 'Submit' button?
The space is coming from the browser specific styling of the various HTML elements, which applies, for example, a 2px border-spacing to each hidden row. (I'm testing in Chrome; it may be different for other browsers.)
I'd suggest using a CSS reset to clear out all browser-specific styling. A simple one like this fixes your spacing issue (again, in Chrome):
div, table, tbody, tr, td {
margin: 0;
padding: 0;
border-spacing: 0;
border-collapse: collapse;
}