use warnings;
use strict;
use Tk;
package Tk::MyScrollableEdit;
####
use Data::Dumper;
our @ISA = ('Tk::Frame');
Tk::Widget->Construct('MyScrollableEdit');
sub Populate{
my $self = shift;
my $args = $_[0];
my $data = delete($args->{-data}) || [];
my $rows = delete($args->{-rows}) || 10;
$self->SUPER::Populate($args);
my @labels = ();
my @entries = ();
for (0..$rows-1){
my $l = $self->Label(-textvariable => \$data->[$_]{label},
-anchor=> 'e'
);
my $w = $self->Entry(-textvariable => \$data->[$_]{value});
$l->grid($w,-sticky=>'e',
-pady=>3,
-padx=>2);
$w->gridConfigure(-sticky=>'ew');
push @labels, $l;
push @entries, $w;
}
$self->ConfigSpecs(-data => ['PASSIVE', undef, undef, $data],
-rows => ['PASSIVE', undef, undef, $rows],
-labels => ['PASSIVE',undef, undef, \@labels],
-entries=> ['PASSIVE',undef, undef, \@entries],
-offset => ['PASSIVE',undef, undef, 0],
);
}
sub yview{
my $self = shift;
#print Dumper \@_;
my $sb = shift;
my $data = $self->cget('-data');
my $rows = $self->cget('-rows');
my $entries = $self->cget('-entries');
my $labels = $self->cget('-labels');
my $offset = $self->cget('-offset');
my $visible = @$data / $rows;
my $max_offset = @$data - $rows;
my $units;
if ($_[0] eq 'scroll'){
$units = $_[1];
if ($_[2] ne 'units'){# page
$units = $units * ($rows-3);
}
}
elsif ($_[0] eq 'moveto'){
$units = @$data * $_[1] - $offset;
}
else{
$units = $_[0];
}
$offset = int($offset + $units);
if ($offset < 0){$offset = 0}
elsif ($offset > $max_offset){$offset = $max_offset}
for (0..$rows-1){
my $row = $offset + $_;
$entries->[$_]->configure(-textvariable => \$data->[$row]{value});
$labels->[$_]->configure(-textvariable => \$data->[$row]{label});
}
$self->configure(-offset => $offset);
my $first = $offset / @$data ;
my $last = ($offset + $rows) / @$data ;
$sb->set($first, $last);
}
####
package main;
my $mw = tkinit;
my @data;
for (1..10000){
push @data, {label=> "entry $_", value => "value $_"};
}
my $f = $mw->Frame()->pack(-expand => 1,-fill => 'both');
my $e_f = $f->MyScrollableEdit(
-data => \@data
)->pack(
-fill => 'both',
-side => 'left',
-expand => 1,
);
my $sb;
$sb = $f->Scrollbar( -jump => 0 );
$sb->configure(-command => [$e_f, 'yview', $sb]);
$sb->pack(-side => 'left',
-fill => 'y');
MainLoop;