No responses ;( OK I’ve stripped out the dynamic generation of the GridRow class, to make the example simpler. Whenever I call a setter ( eg set_Some_String ), I instead see the getter ( eg Some_String ) called. I’ve followed the example at How to force a "refresh" of widget values in a ColumnView? - #4 by ebassi by @ebassi … any ideas?
#!/usr/bin/python3
import gi
gi.require_version( "Gtk" , "4.0" )
from gi.repository import Gtk, Gio, Gdk, Pango, GObject, GLib
import json , uuid , importlib.util , sys
class GridRow_B20B2F( GObject.Object ):
__gtype_name__ = 'GridRow_B20B2F'
def __init__( self , track , record ):
super().__init__()
self._track = track
# Unpack record into class attributes
self._ID = record[ 0 ]
self._icon = record[ 1 ]
self._Some_String = record[ 2 ]
self._Another_thingy = record[ 3 ]
@GObject.Property(type=str)
def ID( self ):
return self._ID
@ID.setter
def set_ID( self , ID ):
if self._ID != ID:
self._ID = ID
self.notify( "ID" )
@GObject.Property(type=str)
def icon( self ):
return self._icon
@icon.setter
def set_icon( self , icon ):
if self._icon != icon:
self._icon = icon
self.notify( "icon" )
@GObject.Property(type=str)
def Some_String( self ):
return self._Some_String
@Some_String.setter
def set_Some_String( self , Some_String ):
if self._Some_String != Some_String:
self._Some_String = Some_String
self.notify( "Some_String" )
@GObject.Property(type=str)
def Another_thingy( self ):
return self._Another_thingy
@Another_thingy.setter
def set_Another_thingy( self , Another_thingy ):
if self._Another_thingy != Another_thingy:
self._Another_thingy = Another_thingy
self.notify( "Another_thingy" )
class GridWidget( Gtk.Widget ):
def __init__( self , column_name="oops" , **kwargs ):
super().__init__( **kwargs )
self.model_position = -1
self.column_name = column_name
class GridEntry( Gtk.Entry , GridWidget ):
def __init__( self , **kwargs ):
super().__init__( **kwargs )
class GridLabel( Gtk.Label , GridWidget ):
def __init__( self , **kwargs ):
super().__init__( **kwargs )
class GridImage( Gtk.Image , GridWidget ):
def __init__( self , **kwargs ):
super().__init__( **kwargs )
class Datasheet( Gtk.ScrolledWindow ):
def __init__( self , column_definitions , data ):
super().__init__()
self.set_policy( Gtk.PolicyType.NEVER , Gtk.PolicyType.AUTOMATIC )
self.setup_columns( column_definitions )
self.setup_model( column_definitions , data )
def setup_columns( self , column_definitions ):
cv = Gtk.ColumnView( hexpand=True , single_click_activate=False )
counter = 0
for d in column_definitions:
cvc = Gtk.ColumnViewColumn( title = d['name'] )
f = Gtk.SignalListItemFactory()
f.connect( "setup" , self.setup , d['type'] , 1 , -1 , d['name'] )
f.connect( "bind" , self.bind , d['type'] , d['name'] )
cvc.set_factory( f )
cv.append_column( cvc )
counter = counter + 1
self._column_definitions = column_definitions
self.cv = cv
def setup( self , factory , item , type , xalign , chars , name ):
if type == "label":
label = GridLabel( xalign=xalign , width_chars=chars , ellipsize=Pango.EllipsizeMode.END , valign=Gtk.Align.FILL , vexpand=True , column_name=name )
item.set_child( label )
elif type == "entry":
entry = GridEntry( xalign=xalign , width_chars=chars , valign=Gtk.Align.FILL , vexpand=True , column_name=name )
item.set_child( entry )
entry.connect( "activate" , self.on_entry_activate )
entry.connect( "state-flags-changed" , self.on_entry_move_focus )
elif type == "image":
image = GridImage( column_name=name )
item.set_child( image )
else:
raise Exception( "Unknown type: {0}".format( type ) )
def on_entry_move_focus( self , entry , flags ):
# print( "entry move focus and i have {0}".format( flags ) )
# print( flags.FOCUS_WITHIN )
self.on_entry_activate( entry )
def on_entry_activate( self , entry ):
parent = entry.get_parent()
single_selection = self.cv.get_model()
position = entry.model_position
# print( "ss: {0}".format( single_selection[ position ] ) )
grid_row = single_selection[ position ]
column_name = entry.column_name
old_value = getattr( grid_row , column_name )
new_value = entry.get_text()
if old_value != new_value:
# setter = getattr( grid_row , "set_" + column_name )
# grid_row.set_Some_String( new_value )
# grid_row.notify( "Some_String" )
# ???
getattr( grid_row , "set_" + column_name)( new_value )
getattr( grid_row , "set_icon" , "view-refresh" )
def bind( self , factory , item , type , column_name ):
widget = item.get_child()
grid_row = item.get_item()
if type == "label":
grid_row.bind_property( column_name , widget , "label" , GObject.BindingFlags.SYNC_CREATE )
elif type == "entry":
grid_row.bind_property( column_name , widget , "text" , GObject.BindingFlags.SYNC_CREATE )
elif type == "image":
grid_row.bind_property( column_name , widget , "icon-name" , GObject.BindingFlags.SYNC_CREATE )
else:
raise Exception( "Unknown type {0}".format( type ) )
widget.model_position = item.get_position()
def setup_model( self , column_definitions , data ):
glist = Gio.ListStore.new( item_type=GridRow_B20B2F )
track = 0
for row in data:
glist.append( GridRow_B20B2F( track , row ) )
track = track + 1
model=Gtk.SingleSelection( model = glist )
self.cv.set_model( model )
self.set_child( self.cv )
def column_name_to_number( self , column_name ):
counter = 0
for d in self._column_definitions:
if d['name'] == column_name:
return counter
counter = counter + 1
return False
def on_activate(app):
column_definitions = [
{
"name": "ID"
, "type": "label"
}
, {
"name": "icon"
, "type": "image"
}
, {
"name": "Some_String"
, "type": "entry"
}
, {
"name": "Another_thingy"
, "type": "entry"
}
]
data = []
for i in range( 0 , 1000 ):
# data.append( [ i , "ok" , "blah", "more" ] )
data.append( [ i , "ok" , uuid.uuid4().hex[:6].upper(), uuid.uuid4().hex[:6].upper() ] )
datasheet = Datasheet( column_definitions , data )
win=Gtk.ApplicationWindow( application=app )
win.set_child( datasheet )
win.present()
app=Gtk.Application( application_id="org.test.datasheet" )
app.connect( "activate" , on_activate )
app.run( None )