Как ограничить самую правую ширину Gtk.TreeViewColumn внутри Gtk.ScrolledWindow?
Я не могу предотвратить расширение правого столбца a.
Как настоящийGtk.TreeView
может отображать большее количество строк, что обычно несколько превышает высоту экрана, он встроен в файл . Это требуется . Без этого добавление пустой сетки справа от древовидной структуры, расширяющейся по горизонтали, решило бы проблему. Основываясь на этой идее, я попробовал обходной путь, который создает еще одну трудность (см. ниже).
Я построил минимальный рабочий пример из примера из https://python-gtk-3-tutorial.readthedocs.io/en/latest/treeview.html#filtering , без фильтрации и кнопок; и столбцы имеют ширину не менее 80 пикселей (это работает), а их содержимое центрировано по горизонтали. Эта последняя деталь делает видимым горизонтальное расширение самого правого столбца. В исходном примере он тоже расширяется, но, поскольку все выровнено по левому краю, этого не видно. Мне бы хотелось, чтобы содержимое столбцов было центрировано, а правый край не расширялся.
Этот пример минимален, но содержит некоторые полезные функции: вы найдете интерактивные заголовки столбцов, которые будут отображать некоторую информацию о выбранном столбце в консоли; кнопка удаления (отлично работает, удаляет выбранные строки) и кнопка вставки, которая позволяет вставлять новые строки из выделения (например, из выбранных строк из электронной таблицы, но нет ничего, чтобы проверить правильность данных, если вы вставляете что-то, что делает не конвертировать в int, он просто рухнет).
Обходной путь
Обходной путь, который я пробовал, состоит в том, чтобы собрать как древовидную структуру, так и горизонтально расширяющуюся пустую правую сетку справа от нее внутри сетки, которая будет помещена в файл . Это работает, но вызывает другие тонкие проблемы: в некоторых ситуациях древовидное представление не обновляется (это происходит через некоторое время), но ничто не мешает основному циклу обновить представление (например, в фоновом режиме нет другой обработки). Чтобы поэкспериментировать с этим обходным путем: закомментируйте и раскомментируйте строки, как описано в приведенном ниже коде; запустить программу черезpython script.py
(если вам нужно установить pygobject в venv, см. здесь ), обратите внимание, что самый правый столбец больше не расширяется вправо, выберите 3 первых строки и нажмите «удалить», затем в электронной таблице выберите 3 строки фиктивных целые числа, как показано ниже, а затем нажмите «вставить». Прокрутите вниз до последних строк: в большинстве случаев вы увидите , что 3 вставленные строки не отображаются, даже если можно прокрутить последнюю строку. Возможно, через какое-то время появится один из них, затем другой... (или просто выберите строку, и они появятся). Как ни странно, это происходит, если вы только что удалили столько строк, сколько хотите вставить после удаления (3 удалены, 3 вставлены или 4 удалены, 4 вставлены и т. д.).
Пример выбора таблицы:
Вопрос
Итак, я бы предпочел избежать обходного пути (боюсь, я могу найти другие ситуации, вызывающие плохое обновление дерева), которые я не мог исправить (например, установкаself.scrollable_treelist.set_propagate_natural_height(True)
оказался бесполезным, может быть, я не правильно его использую?) и только прикрепляю само дерево прямо вGtk.ScrolledWindow
. Тогда как предотвратить расширение самого правого столбца?
(Я пытался использовать достаточное количество сеттеров и свойств средств визуализации ячеек, древовидного представления, столбцов древовидного представления, прокручиваемого окна, но безрезультатно. Некоторые из них все еще находятся в приведенном ниже коде.)
Однако любое решение, использующее и исправляющее обходной путь, описанный выше, будет принято.
В любом случае древовидную структуру можно прокручивать, а строки добавлять и удалять из нее без проблем с обновлением.
Исходный код
import gi
try:
gi.require_version('Gtk', '3.0')
except ValueError:
raise
else:
from gi.repository import Gtk, Gdk
# ints to feed the store
data_list = [(i, 2 * i, 3 * i, 4 * i, 5 * i) for i in range(40)]
class AppWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Treeview Columns Size Demo")
self.set_border_width(10)
# Setting up the self.grid in which the elements are to be positioned
self.grid = Gtk.Grid()
self.grid.set_column_homogeneous(True)
self.grid.set_row_homogeneous(True)
self.add(self.grid)
# Creating the ListStore model
self.store = Gtk.ListStore(int, int, int, int, int)
for data_ref in data_list:
self.store.append(list(data_ref))
# creating the treeview and adding the columns
self.treeview = Gtk.TreeView(model=self.store)
rend = Gtk.CellRendererText()
rend.set_alignment(0.5, 0.5)
for i, column_title in enumerate([f'n×{p}' for p in [1, 2, 3, 4, 5]]):
column = Gtk.TreeViewColumn(column_title, rend, text=i)
column.set_min_width(80)
# column.set_max_width(80)
# column.set_fixed_width(80)
# column.set_sizing(Gtk.TreeViewColumnSizing(1))
column.set_alignment(0.5)
column.set_clickable(True)
column.connect('clicked', self.on_column_clicked)
self.treeview.append_column(column)
self.treeview.set_hexpand(False)
self.treeview.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
# Put the treeview in a scrolled window
self.scrollable_treelist = Gtk.ScrolledWindow()
self.scrollable_treelist.set_vexpand(True)
self.grid.attach(self.scrollable_treelist, 0, 0, 8, 10)
self.scrollable_treelist.add(self.treeview)
# WORKAROUND
# Alternatively, embed the treeview inside a grid containing an
# empty grid to the right of the treeview
# To try it: comment out the previous line; uncomment next lines
# scrolled_grid = Gtk.Grid()
# empty_grid = Gtk.Grid()
# empty_grid.set_hexpand(True)
# scrolled_grid.attach(self.treeview, 0, 0, 8, 10)
# scrolled_grid.attach_next_to(empty_grid, self.treeview,
# Gtk.PositionType.RIGHT, 1, 1)
# self.scrollable_treelist.add(scrolled_grid)
# self.scrollable_treelist.set_propagate_natural_height(True)
# Buttons
self.remove_button = Gtk.Button(label='Remove')
self.remove_button.connect('clicked', self.on_remove_clicked)
self.paste_button = Gtk.Button(label='Paste')
self.paste_button.connect('clicked', self.on_paste_clicked)
self.grid.attach_next_to(self.remove_button, self.scrollable_treelist,
Gtk.PositionType.TOP, 1, 1)
self.grid.attach_next_to(self.paste_button, self.remove_button,
Gtk.PositionType.RIGHT, 1, 1)
self.set_default_size(800, 500)
self.show_all()
# Clipboard (to insert several rows)
self.clip = Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY)
self.clip2 = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
def on_column_clicked(self, col):
print(f'col.get_sizing()={col.get_sizing()}')
print(f'col.get_expand()={col.get_expand()}')
print(f'col.get_width()={col.get_width()}')
print(f'col.get_min_width()={col.get_min_width()}')
print(f'col.get_max_width()={col.get_max_width()}')
print(f'col.get_fixed_width()={col.get_fixed_width()}')
def on_remove_clicked(self, widget):
model, paths = self.treeview.get_selection().get_selected_rows()
refs = []
for path in paths:
refs.append(Gtk.TreeRowReference.new(model, path))
for ref in refs:
path = ref.get_path()
treeiter = model.get_iter(path)
model.remove(treeiter)
# print(f'AFTER REMOVAL, REMAINING ROWS={[str(r[0]) for r in model]}')
def on_paste_clicked(self, widget):
text = self.clip.wait_for_text()
if text is None:
text = self.clip2.wait_for_text()
if text is not None:
lines = text.split('\n') # separate the lines
lines = [tuple(L.split('\t')) for L in lines] # convert to tuples
print(f'PASTE LINES={lines}')
for line in lines:
if len(line) == 5:
line = tuple(int(value) for value in line)
self.store.append(line)
win = AppWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()