If I want to make a Gtk.TreeView scrollable, I embed it in a Gtk.ScrolledWindow. Embedding the TreeView produces a cursor which is out of scale (way too large).
There are 7 more rows in the TreeView, below the 3 shown. I would expect the scrollbar cursor to scale to 1/3 allowing me to scroll comfortably.
I can scroll normally with the scroll wheel on the mouse, and scrolling with the arrow keys on the keyboard.
This is the code that creates the TextView:
self.segment_store = Gtk.ListStore(str, str, str, str, str, str)
self.segment_view = Gtk.TreeView(model = self.segment_store,
hexpand = True)
self.segment_scroller = Gtk.ScrolledWindow()
self.segment_scroller.add(self.segment_view)
The ScrolledWindow itself is packed into a Gtk.Grid.
I suspected that there was a property in the scrollbar specifying a minimum size, and tried to modify the page size - again no luck.
Here's a complete minimum example. The if True
in MainWindow can
be changed to False, to enable/disable the use of a ScrollWindow.
The three lines mentioning vadj in create_segment_table
can be commented
out to disable my page size limiting experiment.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# test_embedded_treeview.py
#
# Copyright 2023 John Coppens <john@jcoppens.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
#
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MainWindow(Gtk.Window):
def __init__(self):
super(MainWindow, self).__init__()
self.connect("destroy", lambda x: Gtk.main_quit())
self.set_default_size(400, 300)
self.create_segment_table()
for i in range(10):
self.segment_store.append( ('0', )*6 )
if True:
grid = Gtk.Grid()
grid.attach(self.segment_scroller, 1, 1, 1, 1)
self.add(grid)
else:
self.add(self.segment_scroller)
self.show_all()
def run(self):
Gtk.main()
def create_segment_table(self):
self.segment_store = Gtk.ListStore(str, str, str, str, str, str)
self.segment_view = Gtk.TreeView(model = self.segment_store,
hexpand = True)
# La tabla puede crecer demasiado, asi que agregamos un 'scroller'
self.segment_scroller = Gtk.ScrolledWindow()
self.segment_scroller.add(self.segment_view)
# Trying to change the page size of the scrollbar
vadj = self.segment_scroller.get_vadjustment()
vadj.set_page_size(20)
self.segment_scroller.set_vadjustment(vadj)
# Creamos las columnas para la tabla
for colnr, header in enumerate( ('X0', 'Y0', 'Z0', 'X1', 'Y1', 'Z1') ):
renderer = Gtk.CellRendererText(editable = True)
# ~ renderer.connect('edited', self.on_cell_edited, colnr)
col = Gtk.TreeViewColumn(header, renderer, text = colnr)
col.set_expand(True)
self.segment_view.append_column(col)
def main(args):
mainwdw = MainWindow()
mainwdw.run()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
EDIT:
Sylvester's excellent answer below is great solution for the issue. Because this is a correction for a deficiency in the widget, and not a style issue, I decided against using an external .CSS file, which would somewhat complicate maintenance. So I included the CSS in the code itself (note that load_from_data
requires a byte string):
style_provider = Gtk.CssProvider()
style_provider.load_from_data(b"slider {min-height: 10px; }"
b"trough {min-height: 50px; }")
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER
)
The problem here of course is that the scrollbar's slider is so big that it can't be moved. In order to fix that, you need to change the slider's minimum height. If the slider can be smaller, it'll have more room to move around.
You can use CSS to change the slider's minimum height. However, if you change the slider's height, you also need to change the trough's height. If you don't, the ScrolledWindow
will just shrink to fit the slider, and you'll be back to where you started.
So create a CSS file and put this inside:
slider {
min-height: 10px;
}
trough {
min-height: 50px;
}
This will set the slider's minimum height to 10 pixels, and the trough's minimum height to 50 pixels. This makes sure that the slider has enough room to move around in the trough, even at minimum height. You can adjust these values to suit your preference.
Now you just need to load the CSS. In order to do that, you can use Gtk.CSSProvider
and Gtk.StyleContext
:
style_provider = Gtk.CssProvider()
style_provider.load_from_path("/path/to/theme.css")
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER
)
Note that you will have to import Gdk
in order for this to work.
Here is a complete reproducible example using your code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# test_embedded_treeview.py
#
# Copyright 2023 John Coppens <john@jcoppens.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
#
import gi
gi.require_version('Gdk', '3.0')
gi.require_version('Gtk', '3.0')
from gi.repository import Gdk # Import Gdk
from gi.repository import Gtk
class MainWindow(Gtk.Window):
def __init__(self):
super(MainWindow, self).__init__()
self.connect("destroy", lambda x: Gtk.main_quit())
self.set_default_size(400, 300)
self.create_segment_table()
for i in range(10):
self.segment_store.append( ('0', )*6 )
######################################
# Load the CSS to change the slider
style_provider = Gtk.CssProvider()
style_provider.load_from_path("/path/to/theme.css")
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER
)
######################################
if True:
grid = Gtk.Grid()
grid.attach(self.segment_scroller, 1, 1, 1, 1)
self.add(grid)
else:
self.add(self.segment_scroller)
self.show_all()
def run(self):
Gtk.main()
def create_segment_table(self):
self.segment_store = Gtk.ListStore(str, str, str, str, str, str)
self.segment_view = Gtk.TreeView(model = self.segment_store,
hexpand = True)
# La tabla puede crecer demasiado, asi que agregamos un 'scroller'
self.segment_scroller = Gtk.ScrolledWindow()
self.segment_scroller.add(self.segment_view)
# Creamos las columnas para la tabla
for colnr, header in enumerate( ('X0', 'Y0', 'Z0', 'X1', 'Y1', 'Z1') ):
renderer = Gtk.CellRendererText(editable = True)
# ~ renderer.connect('edited', self.on_cell_edited, colnr)
col = Gtk.TreeViewColumn(header, renderer, text = colnr)
col.set_expand(True)
self.segment_view.append_column(col)
def main(args):
mainwdw = MainWindow()
mainwdw.run()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
Note that I removed the code that was trying to change the page size, as it is not part of the solution. I hope this helps!