Autosize Python Gtk3 TreeViewColumn but make them resizable - python

I try to change the width of the columns. When I set them to autosize the having all a good size, but I cannot make them smaller.
Then I set the columns to fixed size but now the horizontal scrollbar no longer appears.
So maybe it is possible to start with autosize column width but also give the possibility to change the width later?
#!/usr/bin/env python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
window.set_size_request(400, 200)
mainbox = Gtk.VBox()
window.add(mainbox)
scrolled_window = Gtk.ScrolledWindow()
mainbox.pack_start(scrolled_window, True, True, 0)
transactions_liststore = Gtk.ListStore(str, str, str, str, str, str)
for n in range(30):
transactions_liststore.append(["A", "2016-10-10", "Ulrich Farmer", "99,99 EUR", "A short Text", "A longer Text with much much more more content"])
treeview = Gtk.TreeView(Gtk.TreeModelSort(transactions_liststore))
scrolled_window.add(treeview)
for n, name in enumerate(["Type", "Date", "Name", "Value", "Info1", "Info2"]):
cell = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(name, cell, text=n)
if True:
column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
column.set_fixed_width(50)
column.set_min_width(50)
column.set_expand(True)
column.set_resizable(True)
column.set_reorderable(True)
treeview.append_column(column)
window.show_all()
Gtk.main()
edit:
found on https://lazka.github.io/pgi-docs/Gtk-3.0/classes/TreeViewColumn.html#Gtk.TreeViewColumn.set_resizable
If resizable is True and sizing mode of the column is
Gtk.TreeViewColumnSizing.AUTOSIZE, then the sizing mode is changed to
Gtk.TreeViewColumnSizing.GROW_ONLY.

Try this code :
if True:
column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
#column.set_fixed_width(50)
Edit:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf, Gdk
import os, sys
class GUI:
def __init__(self):
window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
window.set_size_request(400, 200)
mainbox = Gtk.VBox()
window.add(mainbox)
window.connect('destroy', self.on_window_destroy)
scrolled_window = Gtk.ScrolledWindow()
mainbox.pack_start(scrolled_window, True, True, 0)
transactions_liststore = Gtk.ListStore(str, str, str, str, str, str)
for n in range(30):
transactions_liststore.append(["A", "2016-10-10", "Ulrich Farmer", "99,99 EUR", "A longer Text with much much more more content", "A short Text"])
treeview = Gtk.TreeView(Gtk.TreeModelSort(transactions_liststore))
scrolled_window.add(treeview)
for n, name in enumerate(["Type", "Date", "Name", "Value", "Info1", "Info2"]):
cell = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(name, cell, text=n)
column.set_min_width(50)
column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
column.set_resizable(True)
column.set_reorderable(True)
treeview.append_column(column)
window.show_all()
def on_window_destroy(self, window):
Gtk.main_quit()
def main():
app = GUI()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())
You still cannot resize the last column but it works to resize the other columns. Hope this helps.

Related

How do I implement a drag and drop system in a Gtk TreeView?

I am teaching myself Python Gtk+3 using the readthedocs tutorial. I'm currently working on drag and drop and want to create a TreeView where every line is dragable. To do this, my code reads in a list of telecommands and puts them in a TreeView. This TreeView works and I can drag the single lines around. When I drop them into the designated drop area however, nothing happens.
My current goal is for the program to just print the text "Received data", whenever I drop something. Later on, I want the program to print out the single commands, that have been dropped.
My code looks as follows(I followed this example):
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
from csv import reader
# get data from file and format it
with open ("TC_list.csv", "r") as read_command_list:
csv_reader = reader(read_command_list)
list_of_commands = list(csv_reader)
list_header = list_of_commands.pop(0)
for command in list_of_commands:
command[0] = int(command[0])
command[1] = int(command[1])
DRAG_ACTION = Gdk.DragAction.COPY
class DragDropWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Drag and Drop Demo")
self.grid = Gtk.Grid()
self.grid.set_column_homogeneous(True)
self.grid.set_row_homogeneous(True)
self.add(self.grid)
self.grid.set_size_request(1200, 1000)
self.listview = DragSourceListView()
self.drop_area = DropArea()
self.grid.attach(self.listview, 0, 0, 1, 1)
self.grid.attach_next_to(self.drop_area, self.listview, \
Gtk.PositionType.BOTTOM, 1, 1)
class DragSourceListView(Gtk.Grid):
def __init__(self):
Gtk.Grid.__init__(self)
# Creating ListStore model
self.telecommand_liststore = Gtk.ListStore(int, int, str, str)
for telecommand_ref in list_of_commands:
self.telecommand_liststore.append(list(telecommand_ref))
self.current_filter_telecommand = None
# Creating the filter, feeding it with the liststore model
self.telecommand_filter = self.telecommand_liststore.filter_new()
# setting the filter function
self.telecommand_filter.set_visible_func(self.telecommand_filter_func)
# creating the treeview, making it use the filter a model, adding columns
self.treeview = Gtk.TreeView.new_with_model(Gtk.TreeModelSort(self.telecommand_filter))
for i, column_title in enumerate(list_header):
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(column_title, renderer, text=i)
column.set_sort_column_id(i)
self.treeview.append_column(column)
# set up drag-source
self.treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [], DRAG_ACTION)
self.treeview.connect("drag-data-get", self.on_drag_data_get)
# setting up layout, treeview in scrollwindow
self.scrollable_treelist = Gtk.ScrolledWindow()
self.scrollable_treelist.set_vexpand(True)
self.scrollable_treelist.set_hexpand(True)
self.attach(self.scrollable_treelist, 0, 1, 8, 10)
self.scrollable_treelist.add(self.treeview)
def telecommand_filter_func(self, model, iter, data):
if (
self.current_filter_telecommand is None
or self.current_filter_telecommand == "None"
):
return True
else:
return model[iter][0] == self.current_filter_telecommand
def on_drag_data_get(self, widget, drag_context, dat, info, time):
selected_tc = self.get_selected_items()[0]
selected_iter = self.get_model().get_iter(selected_tc)
class DropArea(Gtk.Label):
def __init__(self):
Gtk.Label.__init__(self)
self.set_label("Drop Area")
self.drag_dest_set(Gtk.DestDefaults.ALL, [], DRAG_ACTION)
self.connect("drag-data-received", self.on_drag_data_received)
def on_drag_data_received(self, widget, drag_context, x, y, data, info, time):
print("Received data")
win = DragDropWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
What am I overlooking here? Why doesn't the drop-area do anything?
Try to set gtk_tree_view_set_reorderable to True.

How to assign “hidden data” to Gtk.TreeView row in order to catch them with Gtk.TreeView.connect("row-activated")?

In Python, I have a class person witch contain firstName and lastName and also country attributes (actually their is much more other data, but I simplify it for the example).
So, I generate a table witch should only show firstName and lastName (the user shouldn’t see the country). But when the user click on a specific row, I want to get the the full person object.
This is my code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# MWE for hidden data in Gtk.TreeView
import sys
import os
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import Gio
from gi.repository import Pango
class person():
def __init__(self, firstName, lastName, country):
self.firstName=firstName
self.lastName=lastName
self.country=country
personsList=[
person("Ada", "Lovelace", "UK"),
person("Alan", "Turing", "UK"),
person("Denis", "Richie", "USA")
]
def onRowChange(widget, row, col):
# This function is executed when a user click on a row
print(widget)
print(row)
print(col)
pass
class GridWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="TreeView MWE")
self.connect("destroy", Gtk.main_quit)
# Setting up the self.grid in which the elements are to be positionned
self.grid = Gtk.Grid()
self.grid.set_column_homogeneous(True)
self.grid.set_row_homogeneous(True)
self.add(self.grid)
# Preparing the list store
listStore=Gtk.ListStore(str, str)
for aPerson in personsList:
listStore.append([aPerson.firstName, aPerson.lastName])
# Seting up the TreeView and given the ListStore to the Treeview
treeView=Gtk.TreeView(model=listStore)
renderer_text = Gtk.CellRendererText()
# Preparing the headers
column_text = Gtk.TreeViewColumn("First Name", renderer_text, text=0)
treeView.append_column(column_text)
column_text = Gtk.TreeViewColumn("Last Name", renderer_text, text=1)
treeView.append_column(column_text)
# Setting the event connection
treeView.connect("row-activated", onRowChange)
# Attaching the treeView to the Gride
self.grid.add(treeView)
screen = Gdk.Screen.get_default()
styleContext = Gtk.StyleContext()
win = GridWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
And here is the rendering:
As you can see, the onRowChange() function can only get the TreeView and the TreeViewColumn objects when the user click on it, according to the row_activated signal’s documentation.
I know I can get the row number and search in the list witch object has this row number but it’s too much hazardous and a little bit hacky.
So, is their a way to include in the Gtk.ListStore a user’s hidden data and catch back this data with row-activated signal?
You can just add data to your liststore without showing it in the treeview.
The following code snippet shows the necessary changes:
...
def onRowChange(widget, row, col):
# This function is executed when a user click on a row
model = widget.get_model()
iter_ = model.get_iter(row)
person = model.get_value(iter_, 2)
print(person.country)
class GridWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="TreeView MWE")
self.connect("destroy", Gtk.main_quit)
# Setting up the self.grid in which the elements are to be positionned
self.grid = Gtk.Grid()
self.grid.set_column_homogeneous(True)
self.grid.set_row_homogeneous(True)
self.add(self.grid)
# Preparing the list store
listStore=Gtk.ListStore(str, str, object)
for aPerson in personsList:
listStore.append([aPerson.firstName, aPerson.lastName, aPerson])
...
Please try the example below. Some of the original code is commented out and below it is replacement code highlighted with #***.
On clicking on a row the console should display a list containing the three fields (firstname, surname and country).
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# MWE for hidden data in Gtk.TreeView
import sys
import os
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import Gio
from gi.repository import Pango
class person():
def __init__(self, firstName, lastName, country):
self.firstName=firstName
self.lastName=lastName
self.country=country
personsList=[
person("Ada", "Lovelace", "UK"),
person("Alan", "Turing", "UK"),
person("Denis", "Richie", "USA")
]
#*** Instead use: def on_row_activated(self, widget, row, col_view):
#def onRowChange(widget, row, col):
# # This function is executed when a user click on a row
# print(widget)
# print(row)
# print(col)
# pass
class GridWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="TreeView MWE")
self.set_size_request(200,150)
self.connect("destroy", Gtk.main_quit)
# Setting up the self.grid in which the elements are to be positionned
self.grid = Gtk.Grid()
self.grid.set_column_homogeneous(True)
self.grid.set_row_homogeneous(True)
self.add(self.grid)
# Preparing the list store
#listStore=Gtk.ListStore(str, str)
#*** Increase to three strings
listStore=Gtk.ListStore(str, str, str)
for aPerson in personsList:
#listStore.append([aPerson.firstName, aPerson.lastName])
#*** Add the country
listStore.append([aPerson.firstName, aPerson.lastName, aPerson.country])
# Seting up the TreeView and given the ListStore to the Treeview
treeView=Gtk.TreeView(model=listStore)
renderer_text = Gtk.CellRendererText()
# Preparing the headers
column_text = Gtk.TreeViewColumn("First Name", renderer_text, text=0)
treeView.append_column(column_text)
column_text = Gtk.TreeViewColumn("Last Name", renderer_text, text=1)
treeView.append_column(column_text)
# Setting the event connection
#treeView.connect("row-activated", onRowChange)
#*** Change connection so double-clicking on row calls self.on_row_activated
treeView.connect("row-activated", self.on_row_activated)
# Attaching the treeView to the Grid
self.grid.add(treeView)
#*** Change to using this callback when a row is double-clicked.
def on_row_activated(self, widget, row, col_view):
""" Calllback for double-click on Treeview row"""
model = widget.get_model()
row_list = []
for i in range(model.get_n_columns()):
#print(model[row][i])
row_list.append(model[row][i])
print(row_list)
# Example of what the console displays upon double-clicking a row...
# ['Alan', 'Turing', 'UK']
# ['Denis', 'Richie', 'USA']
screen = Gdk.Screen.get_default()
styleContext = Gtk.StyleContext()
win = GridWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

PyGi: How to use a GTKListBox with a GTKListStore?

I am very new to GTK and Gnome app development, so apologies for my naiveté. (My development language is Python). I would like to use a ListBox to display some data, and the individual row views will be quite complicated (i.e. composed of multiple different widgets). As a result I would prefer not to use a TreeView, because that will require a bunch of custom drawing/event handling. I noticed that ListBox has a bind_model method, but it appears I can't use it to bind a ListStore model, even thought ListStore implements the ListModel interface. Does anybody know how to accomplish this?
A simple exampe:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gio, GObject
import sys
class Item(GObject.GObject):
text = GObject.property(type = str)
def __init__(self):
GObject.GObject.__init__(self)
class GUI:
def __init__(self):
item1 = Item()
item1.text = "Hello"
item2 = Item()
item2.text = "World"
liststore = Gio.ListStore()
liststore.append(item1)
liststore.append(item2)
listbox=Gtk.ListBox()
listbox.bind_model(liststore, self.create_widget_func)
window = Gtk.Window()
window.add(listbox)
window.connect("destroy", self.on_window_destroy)
window.show_all()
def create_widget_func(self,item):
label=Gtk.Label(item.text)
return label
def on_window_destroy(self, window):
Gtk.main_quit()
def main():
app = GUI()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())
This is condensed code from my open source accounting program.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf, Gdk
import os, sys
class GUI :
def __init__(self):
listbox = Gtk.ListBox()
employee_name_label = Gtk.Label("Henry", xalign=1)
combo = Gtk.ComboBoxText()
combo.set_property("can-focus", True)
for name in ["bar", "foo", "python"]:
combo.append('0', name)
list_box_row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
list_box_row.add(hbox)
switch = Gtk.Switch()
switch.props.valign = Gtk.Align.CENTER
project_time_label = Gtk.Label("0:00:00", xalign=1 )
project_time_label.set_property('width-chars', 8)
hbox.pack_start(employee_name_label, True, False, 5)
hbox.pack_end(project_time_label, False, False, 5)
hbox.pack_end(switch, False, False, 5)
hbox.pack_end(combo, False, False, 5)
listbox.add(list_box_row)
window = Gtk.Window()
window.add(listbox)
window.connect("destroy", self.on_window_destroy)
window.show_all()
def on_window_destroy(self, window):
Gtk.main_quit()
def main():
app = GUI()
Gtk.main()
if __name__ == "__main__":
sys.exit(main())
It may not answer your question exactly, but it does work and it shows a way to use ListBox. ListBox is a very good choice for complicated setups. In my case I was doing so much operations every second that it crashed Treeviews.

ComboBox with two columns

I'm trying to create a GtkComboBox with two columns. I picked up some examples and I'm trying to adapt but without success. Only the items that would be the second column are shown.
#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class ComboBox(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.set_title("ComboBox")
self.set_default_size(150, -1)
self.connect("destroy", Gtk.main_quit)
slist = Gtk.ListStore(str, str)
slist.append(['01', 'Ferro'])
slist.append(['07', 'Uranio'])
slist.append(['08', 'Cobalto'])
combobox = Gtk.ComboBox()
combobox.set_model(slist)
combobox.set_active(0)
combobox.set_wrap_width(2)
self.add(combobox)
cellrenderertext = Gtk.CellRendererText()
combobox.pack_start(cellrenderertext, True)
combobox.add_attribute(cellrenderertext, "text", 1)
window = ComboBox()
window.show_all()
Gtk.main()
I want create a GtkComboBox like this:
There must be a CellRendererText for each column to be displayed.
cell1 = Gtk.CellRendererText()
cell2 = Gtk.CellRendererText()
combobox.pack_start(cell1, True)
combobox.pack_start(cell2, True)
combobox.add_attribute(cell1, "text", 0)
combobox.add_attribute(cell2, "text", 1)

How can I create a GTK ComboBox with images in Python?

How can I create a ComboBox that displays a list of entries, each containing some text and an icon?
I'm using Python and GTK3 with GObject introspection.
Here's an example of how to do that, inspired by this answer for C.
from gi.repository import Gtk
from gi.repository import GdkPixbuf
store = Gtk.ListStore(str, GdkPixbuf.Pixbuf)
pb = GdkPixbuf.Pixbuf.new_from_file_at_size("picture.png", 32, 32)
store.append(["Test", pb])
combo = Gtk.ComboBox.new_with_model(store)
renderer = Gtk.CellRendererText()
combo.pack_start(renderer, True)
combo.add_attribute(renderer, "text", 0)
renderer = Gtk.CellRendererPixbuf()
combo.pack_start(renderer, False)
combo.add_attribute(renderer, "pixbuf", 1)
window = Gtk.Window()
window.add(combo)
window.show_all()
window.connect('delete-event', lambda w, e: Gtk.main_quit())
Gtk.main()
The same example in GTK2, inspired by your code:
import pygtk
pygtk.require('2.0')
import gtk
import gtk.gdk
import gobject
import gc
store = gtk.ListStore(str, gtk.gdk.Pixbuf)
pb = gtk.gdk.pixbuf_new_from_file("picture.png")
store.append(["Test", pb])
combo = gtk.ComboBox(store)
renderer = gtk.CellRendererText()
combo.pack_start(renderer, True)
combo.add_attribute(renderer, "text", 0)
renderer = gtk.CellRendererPixbuf()
combo.pack_start(renderer, False)
combo.add_attribute(renderer, "pixbuf", 1)
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.add(combo)
window.show_all()
window.connect('delete-event', lambda w, e: gtk.main_quit())
gtk.main()

Categories

Resources