in reply to TableMatrix asynch update of cells

The reason why you see this symptom is that you are breaking OO encapsulation by modifying an object's internal storage directly without using the object's method calls for that purpose.

$variable->{"4,0"}="Test".$cnt++; Your object, $t is oblivious to the fact that one cell just changed. And you have to use brute force to make an update of the entire window happen.

$t->activate("4,0"); $t->curvalue( "Test".$cnt++ ); This works because $t is now fully aware that a cell within the %variable hash has changed and Tk will therefore update the screen automatically.

Raw performance is one reason to violate OO encapsulation. I did this in one application with often say 100,000 cells. When I say sorted by a column, I manipulated $variable directly and then called one of the methods that you correctly found will cause a full window "repaint". The internal data storage for a tablematrix object is amazingly enough, not an array or an array of hashes, but a 1D hash table. The combination of row and column are the keys. $variable->{"0,2"}="something"; #sets row 0, column 2 to "something"

Under certain circumstances, it is possible to "hide" some extra info inside the $variable which tablematrix will ignore (meaning more info than just values of the coordinates). Of course this is a massive OO encapsulation violation! I haven't needed to do that myself, but I have heard of this being done.

In your application, just call the appropriate methods on the $t object. Do not manipulate the storage of $t directly.

Update: Another comment, I see you have: -sparsearray => 0, in order to override the default of using a sparsearry. The effect of this could range from "nothing" to "a lot" in terms of the number of hash keys generated. In general, I would advise using the object's defaults and then enable stuff like this when needed and then put a comment in the code about why this was needed.

Replies are listed 'Best First'.
Re^2: TableMatrix asynch update of cells
by olgo (Sexton) on Apr 26, 2022 at 11:09 UTC
    Thanks for your kind responses.
    I agree that breaking OO encapsulation is a bad idea, but I don't really understand why it is described as an attribute alongside all other "public" attributes unless it is also to be regarded as a means for manipulating the table it is associated with.
    By using the "appropriate methods", I assume you mean the set method? This does work, but only as long as the TableMatrix is not disabled.
    (My supplied example does not set the TableMatrix to disabled, which is my bad, it shold have been for a clearer example.)

    (The reason for using a disabled TableMatrix is to avoid the user making changes to it, or , where applicable, replacing the cell with e.g. a Combobox widget for easier editing. The TableMatrix cells must never be changed, thus I use the -state => 'disabled')

    So, I rephrase my original question: What is the best way to update the cells of a disabled TableMatrix without breaking OO encapsulation?
    Regards

      You can try playing games with "validate" to leave the TableMatrix enabled but only allow change to the one desired cell.

      Something like this...

      #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11143267 use warnings; use Tk ':eventtypes'; use Tk::TableMatrix; use Data::Dumper qw( DumperX); my $top = MainWindow->new; my $changing = ''; my $arrayVar = {}; foreach my $row (-1..6){ foreach my $col (-2..5){ $arrayVar->{"$row,$col"} = "r$row, c$col"; } } ## Test out the use of a callback to define tags on rows and columns sub rowSub{ my $row = shift; return "OddRow" if( $row > 0 && $row % 2) } sub colSub{ my $col = shift; return "OddCol" if( $col > 0 && $col%2) ; } my $label = $top->Label(-text => "TableMatrix v1 Example"); my $t = $top->Scrolled('TableMatrix', -rows => 8, -cols => 8, -width => 6, -height => 6, -titlerows => 1, -titlecols => 2, -variable => $arrayVar, -roworigin => -1, -colorigin => -2, -rowtagcommand => \&rowSub, -coltagcommand => \&colSub, -colstretchmode => 'last', -rowstretchmode => 'last', -selectmode => 'extended', -sparsearray => 0, -validate => 1, # NOT +E -validatecommand => \&allowchange, # NOT +E ); my $button = $top->Button( -text => "Exit", -command => sub{ $top->des +troy}); # hideous Color definitions here: $t->tagConfigure('OddRow', -bg => 'orange', -fg => 'purple'); $t->tagConfigure('OddCol', -bg => 'brown', -fg => 'pink'); $t->colWidth( -2 => 7, -1 => 7, 1=> 5, 2 => 8, 4=> 14); $label->pack( -expand => 1, -fill => 'both'); $t->pack(-expand => 1, -fill => 'both'); $button->pack(-expand => 1, -fill => 'both'); sub allowchange { my ($row, $col) = @_; my $cell = "$row,$col"; return $cell eq $changing ? 1 : 0; } my $cnt; sub Timer { print "Now\n"; my $variable = $t->cget( -var); $changing = "4,0"; # NOTE $t->activate("4,0"); # NOTE $t->curvalue( "Test".$cnt++ ); # NOTE $changing = ""; # NOTE #$t->activate("4,0"); #$t->colWidth( -2 => 7, -1 => 7, 1=> 5, 2 => 8, 4=> 14); #$t->update(); $top->after(1000, \&Timer); return 1; } $top->after(1000, \&Timer); Tk::MainLoop;