For Programmers: Free Programming Magazines  


Home > Archive > PerlTk > March 2005 > Tk::Scale : Three subtle issues









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Tk::Scale : Three subtle issues
Chris

2005-02-09, 8:58 pm

Hi Gang,

As you know, I've been working a lot with Scale widgets lately,
trying to create a mega-widget that combines several of them in a
certain complex way.

One big, recurring obstacle to getting my mega-widget to work the
way I want, is that the Scale widget itself often doesn't work the way
I want/expect, requiring me to complicate my code with various
workarounds. The Scale's departures from expectations are, of course
"between the cracks" of what's covered in the documentation, and I
don't seem to have access to the Scale source code, so... here I am.

First, I Scale behavior is slightly inconsistent across the three
different ways of "moving" its "slider:" user manipulation of the GUI,
application call to Scale::set(), application alteration of the value
of the Scale's associated scalar variable. In all three cases, the
Scale's visual appearance remains entirely consistent with the value in
the associated variable, so visually all is well. However, the Scale's
"value-changed callback" is called only in the first TWO of the three
cases -- it is NOT called in the THIRD case, which I feel it SHOULD be:
a value-change is a value-change, no matter HOW it arrives on the
screen.

Second, in the course of investigating the above, I am moved to
wonder just HOW the Scale widget FINDS OUT that its associated
variable's value has changed, and that it should redraw itself to
indicate the new value. The Scale doesn't seem to be "tying" the
variable's value (so as to hook the STORE() operation), which was my
first thought. Low-level behavior seems to suggest that some kind of
periodic "event" is being processed which "polls" the variable's value
to discover changes -- but when _I_ "tie" the associated variable I
don't see any periodic calls to the FETCH() method to retrieve the
value, and I can't see how else the value could be gotten correctly.
I'm at a loss to conjecture what OTHER mechanisms exist. Does anybody
here know how this is implemented?

Second, I find that the Scale's reaction to being given a
"non-numeric" value is somewhat inconsistent: namely, it is different
at construction/initialization than later on. Viz: if the variable
already has a non-numeric value when the Scale is constructed and the
variable assigned (via -variable), the Scale quietly changes the
variable's value to an empty string. But if the variable's value
starts out (or ever becomes!) numeric, and THEN the program tries to
assign it a non-numeric value, the attempt results in Tk errors. (If
the program simply assigns a value to the variable, the error is "can't
assign non-numeric value to scale variable." If the program calls
Scale::set(), the error is "modification of a read-only value
attempted..." (which I don't quite understand).)

I'd be very interested in any light anybody could shed on these
matters. Thanks in advance!

Chris

zentara

2005-02-10, 3:58 pm

On 9 Feb 2005 13:17:31 -0800, "Chris" <cchiesa1@rochester.rr.com> wrote:

> As you know, I've been working a lot with Scale widgets lately,
>trying to create a mega-widget that combines several of them in a
>certain complex way.
>
> One big, recurring obstacle to getting my mega-widget to work the
>way I want, is that the Scale widget itself often doesn't work the way
>I want/expect, requiring me to complicate my code with various
>workarounds. The Scale's departures from expectations are, of course


It's been awhile, and I don't remember exactly what you are looking for.
Also, I found it hard to follow your "issues", but it is probably clear
in your mind.

Would you simply re-state what you would like this "widget" to do?
If I can understand it, maybe I'll make one on a Canvas, as a learning
experience.

What should the widget look like, and what sort of data, should it
connect to?



--
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html
Chris

2005-02-28, 8:58 pm

zentara wrote:
> On 9 Feb 2005 13:17:31 -0800, "Chris" <cchiesa1@rochester.rr.com>

wrote:
>
>
> It's been awhile, and I don't remember exactly what you are looking

for.

I want a Scale widget that can put more than one "slider" into its
"trough," end-wise --

+----------/\------------/\----------+
| ( ) ( ) |
+----------\/------------\/----------+

-- and which lets you move the FIRST slider back and forth only until
it "bumps into" the SECOND slider, and vice versa. (Note that I do
NOT want to limit this thing to just TWO sliders -- it should support
insertion of "any number" of them, within reason.)

The goal is to provide a "natural" interface for adjusting a collection

of numeric values that must remain in a specific relative order, e.g.

val1 < val2 <= val3 < val4

To me, a "multi-slider Scale" seems to be the most natural interface
for this.

(As an alternative behavior -- possibly a configuration option --
a moving slider "bumping into" its neighbor might KEEP MOVING,
"pushing" its neighbor (and the next, and the next, and...) ahead
of it, changing values and firing callbacks for EACH slider ultimate-
ly moved at each increment...)

> Also, I found it hard to follow your "issues", but it is probably

clear
> in your mind.


Eh. It's not THAT clear in my mind, so don't feel bad! :-) I don't
recall the details just now, but believe me, it took a LOT of very
careful observation and note-taking, to be able to organize my
observations into what I reported here!

Let's just say that I find some serious limitations in trying to
make a set of separate, ordinary Scale widgets support a sem-
blance of the behavior I desire in the above-described "multi-
slider" Scale widget. Mostly, I find the standard Scale's choice-
and-selection of available callbacks, and its decisions about
when to invoke them, a bit... awkward. (Details available upon
request and as I can work back into remembering them.) Un-
fortunately, most of the details seem to be in the Scale's C
implementation, where (for all practical purposes) I can't get
at them to make changes.

> Would you simply re-state what you would like this "widget" to do?


Done, above.

> If I can understand it, maybe I'll make one on a Canvas, as a

learning
> experience.


For what it's worth, that was the first thing I tried myself. I got
very tangled up trying to keep track of the "mapping" between
a slider's "physical" position in the trough, and the correspond-
ing numeric value of its associated scalar variable. It's not too
bad in the one-slider case, but gets sticky when one, or both,
of the "limits" on a slider's movement are simply the "current
positions" of OTHER sliders. (I also had some trouble account-
ing for non-zero thickness of sliders when "bumping into"
their limits. Your mileage may vary -- hopefully "for the bet-
ter."

> What should the widget look like, and what sort of data, should it
> connect to?


It should look, and operate, as much as possible like the stan-
dard Scale widget, with the exception of supporting addition-
al sliders. Aside from cases where I hope to IMPROVE UPON
the standard widget's behavior, the "single slider" case should
REDUCE TO the behavior of the standard widget.

I'm not sure quite what you're asking, with your question
about what it should "connect to;" I can't imagine it con-
necting to anything BUT a set of scalar values. As for whether
these should be individual scalars, elements of an array, or
some other far-out representation -- well, I'll leave that up
to YOU. Do whatever is easiest for you, produce the code,
I'll try it, and feed you back any issues I run into. :-) For a
first draft, though, I'm prepared not to be too picky! ;-)

Oh, one more thing -- the widget MUST provide a "reason-
able" set of behaviors -- ideally, a more self-consistent set
than those of the standard Scale widget -- in the case where
a slider's associated variable HAS (at Scale construction/ini-
tialization time) or TAKES ON (during program operation), an
UNDEF value.

Keep me/us informed of your progress. I'm all ears! Oh,
and -- THANKS!

Chris

zentara

2005-03-01, 3:58 pm

On 28 Feb 2005 12:17:55 -0800, "Chris" <cchiesa1@rochester.rr.com>
wrote:

>Keep me/us informed of your progress. I'm all ears! Oh,
>and -- THANKS!


Well your specifications are a "pretty tall order" :-)
But it is a good problem to work on, since it encompasses
alot of ideas. I would think the first step is to try and set
it up as a standalone program, keeping it "hash-oriented",
so it can be easily tranformed into an "object" later on.

This is what I came up with for my first experiment.
It was going fine until I needed to accurately check
for min and max values. When I tried to use bbox or coords
on the slider objects, I was getting a mismatch in values
by 1 or 2 pixels. This is a common problem with the Canvas,
so I think I will switch to Zinc, which gives more precision
in it's coordinate system. Zinc would also allow for an entirely
different design strategy, where each slider could be superimposed
on each other utilizing Zinc's contours, and "see-thru" abilities.

Anyways, here is the beginning of my idea. It dosn't have
"min max" stop points in the dragging, and it dosn't cause
cascading sliding as you move them back and forth. But I think
it is a good starting point.

I would think the cascading sliding can be done by checking
for all the tags of 'current', and if they exceed a set amount, you
know you need to "drag one or more sliders".

The tag which specifies which slider is being dragged, can be made into
an array, and you could push another slider onto the drag array, as
it is encountered.

I probably havn't advanced your cause much. :-)
#!/usr/bin/perl
use warnings;
use strict;
use Tk;

my $xinit; #global for dragging
my $move;

my $mw = MainWindow->new;
$mw->geometry("590x60");

my $width = 500;
my $height = 30;

my $min = 0;
my $max = 500;

my %sliders = (
1 => {
value => 20,
color => 'red',
min => 5,
max => 95,
},

2 => {
value => 40,
color => 'cyan',
min => 0,
max => 200,
},

3 => {
value => 60,
color => 'lightblue',
min => 50,
max => 300,
},

4 => {
value => 80,
color => 'green',
min => 0,
max => 400,
},
);

# do some error checking here to make sure values are within
# respective ranges

#create slider canvas
my $canvas = $mw->Canvas(-width => $width, -height =>$height,
-bg => 'black',
-borderwidth => 0,
-relief => 'sunken',
)->pack;

foreach my $slidernum(sort keys %sliders ){ #less than 10 :-)

$sliders{$slidernum}{'obj'} = $canvas->createLine(
$sliders{$slidernum}{'value'}, 0,
$sliders{$slidernum}{'value'}, $height,
-fill => $sliders{$slidernum}{'color'},
-width => 10,
-tags => [$slidernum, 'move'],
);

$sliders{$slidernum}{'obj1'} = $canvas->createLine(
$sliders{$slidernum}{'value'}, 0,
$sliders{$slidernum}{'value'}, $height,
-fill => 'black',
-width => 1,
-tags => [$slidernum, 'move'],
);

$sliders{$slidernum}{'group'} = $canvas->createGroup(
[$sliders{$slidernum}{'value'}, 0],
-members => [$sliders{$slidernum}{'obj'},
$sliders{$slidernum}{'obj1'}],
-tags => [$slidernum, 'move'],
);

}

$canvas->bind('move', '<1>', sub {&mobileStart();});
$canvas->bind('move', '<B1-Motion>', sub {&mobileMove();});
$canvas->bind('move', '<ButtonRelease>', sub {&mobileStop();});


my $bframe = $mw->Frame()->pack(-expand =>'x');

foreach my $slidernum(sort keys %sliders ){
$bframe->Label(-text => $slidernum,
-background => $sliders{$slidernum}{'color'}
)->pack(-side=>'left');
$bframe->Entry(-textvariable => \$sliders{$slidernum}{'value'},
-width => 5,
)->pack(-side=>'left');
$bframe->Label(-text => ' ')->pack(-side=>'left');

}

my $closebutton = $bframe->Button(-text => 'Exit',
-command => sub{ exit })->pack(-side=>'right');


MainLoop;
########################################
######################
sub mobileStart {
my $ev = $canvas->XEvent;
$xinit = 0 - $ev->x;
$canvas->raise('current');
# $canvas->bind('current', '<Leave>', sub { $move = 0 });
# print "START MOVE->$xinit\n";
}
########################################
#####################
sub mobileMove {
my $ev = $canvas->XEvent;
my ($slidernum,undef,undef) = $canvas->gettags('current');

$move = $ev->x + $xinit;

#####this is problem area, where a mismatch occurs in coords
my($xmin,undef,$xmax,undef) =
$canvas->bbox( $sliders{$slidernum}{'group'} );
my $xnow = ($xmin + $xmax)/2;
print "$xnow\n";
#
# if( $ev->x > $sliders{$slidernum}{'max'} )
# { $move = 0 }


$canvas->move($sliders{$slidernum}{'group'}, $move , 0 );

$xinit = 0 - $ev->x;

($sliders{$slidernum}{'value'},undef,und
ef,undef) =
$canvas->coords($sliders{$slidernum}{'obj1'});

}
########################################
#################

sub mobileStop{&mobileMove;}

__END__





--
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html
zentara

2005-03-01, 8:57 pm

On Tue, 01 Mar 2005 13:51:26 -0500, zentara <zentara@highstream.net>
wrote:
[color=darkred]
>On 28 Feb 2005 12:17:55 -0800, "Chris" <cchiesa1@rochester.rr.com>
>wrote:
>

Well I made an improvement, and am almost there. :-)

This script, will keep the individual sliders in their respective
ranges, and will track which sliders have to be watched for
"cascading".

I'm at a logic road block here, on how best to connect up the
sliders for a cascading slide, keeping their individual ranges
in mind. Maybe you can see how it could be done.

This is getting pretty close, in my estimation. There just has to be
a "clever" way to cascade the sliders when their values are passed
by $xnow. It eludes me at the moment, but sometimes you just need
to "sleep on it" for awhile. :-) I can feel it's there in some nested
loops.
Think about how an abacus ( the chinese sliding bead calculator ) would
work??

#!/usr/bin/perl
use warnings;
use strict;
use Tk;

my $xinit; #global for dragging
my $move;

my $mw = MainWindow->new;
$mw->geometry("590x60");

my $width = 500;
my $height = 30;

my $min = 0;
my $max = 500;

my %sliders = (
1 => {
value => 50,
color => 'red',
min => 5,
max => 105,
},

2 => {
value => 150,
color => 'cyan',
min => 20,
max => 200,
},

3 => {
value => 260,
color => 'lightblue',
min => 50,
max => 350,
},

4 => {
value => 350,
color => 'green',
min => 250,
max => 490,
},
);

# do some error checking here to make sure values are within
# respective ranges

#create slider canvas
my $canvas = $mw->Canvas(-width => $width, -height =>$height,
-bg => 'black',
-borderwidth => 0,
-relief => 'sunken',
)->pack;

#find array of sliders once, to be reused
my @sliders = sort {$a<=>$b} keys %sliders;

foreach my $slidernum(@sliders ){

$sliders{$slidernum}{'obj'} = $canvas->createLine(
$sliders{$slidernum}{'value'}, 0,
$sliders{$slidernum}{'value'}, $height,
-fill => $sliders{$slidernum}{'color'},
-width => 10,
-tags => [$slidernum, 'move'],
);

$sliders{$slidernum}{'obj1'} = $canvas->createLine(
$sliders{$slidernum}{'value'}, 0,
$sliders{$slidernum}{'value'}, $height,
-fill => 'black',
-width => 1,
-tags => [$slidernum, 'move'],
);

$sliders{$slidernum}{'group'} = $canvas->createGroup(
[$sliders{$slidernum}{'value'}, 0],
-members => [$sliders{$slidernum}{'obj'},
$sliders{$slidernum}{'obj1'}],
-tags => [$slidernum, 'move'],
);

}

$canvas->bind('move', '<1>', sub {&mobileStart();});
$canvas->bind('move', '<B1-Motion>', sub {&mobileMove();});
$canvas->bind('move', '<ButtonRelease>', sub {&mobileStop();});


my $bframe = $mw->Frame()->pack(-expand =>'x');

foreach my $slidernum(@sliders){
$bframe->Label(-text => $slidernum,
-background => $sliders{$slidernum}{'color'}
)->pack(-side=>'left');
$bframe->Entry(-textvariable => \$sliders{$slidernum}{'value'},
-width => 5,
)->pack(-side=>'left');
$bframe->Label(-text => ' ')->pack(-side=>'left');

}

my $closebutton = $bframe->Button(-text => 'Exit',
-command => sub{ exit })->pack(-side=>'right');


MainLoop;
########################################
######################
sub mobileStart {
my $ev = $canvas->XEvent;
$xinit = 0 - $ev->x;
$canvas->raise('current');
# $canvas->bind('current', '<Leave>', sub { $move = 0 });
# print "START MOVE->$xinit\n";
}
########################################
#####################
sub mobileMove {
my $ev = $canvas->XEvent;
my ($slidernum,undef,undef) = $canvas->gettags('current');

$move = $ev->x + $xinit;

# detect which direction you are moving and deduce which
# sliders need to be watched for a cascading move
my @watch = ();
if($move > 0) #moving to right
{ @watch = grep { $_ > $slidernum } @sliders;
}else{ @watch = grep { $_ < $slidernum } @sliders;
}
print "watch->@watch\n";


my($xnow,undef) =
$canvas->coords( $sliders{$slidernum}{'obj1'} );
print "$xnow\n";

#test for individual min max limits
if( $xnow > $sliders{$slidernum}{'max'} )
{ my $diff = $sliders{$slidernum}{'max'} - $xnow;
$move = $diff;
}

if( $xnow < $sliders{$slidernum}{'min'} )
{ my $diff = $sliders{$slidernum}{'min'} - $xnow;
$move = $diff;
}

#need tests here to detect collisions
# setup initial tag array for primary mover
my @sliders_2_move = $sliders{$slidernum}{'group'};

# first feeble attempt... it actually is more complicated
# where you need to monitor individual slider limits and
# be able to remove slider groups from the tag array if you
# change direction. I can "feel" it's there in a couple of
# nested loops. :-) Think abacus!! :-)

# foreach my $slidw(@watch){
# if( $xnow <= $sliders{$slidw}{'value'} )
# {
# push @sliders_2_move, $sliders{$slidw}{'group'};
# }
# }

print "movers->@sliders_2_move\n";

$canvas->move( "@sliders_2_move" ,$move, 0 );

$xinit = 0 - $ev->x;

($sliders{$slidernum}{'value'},undef,und
ef,undef) =
$canvas->coords($sliders{$slidernum}{'obj1'});

}
########################################
#################

sub mobileStop{&mobileMove;}

__END__

--
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html
zentara

2005-03-01, 8:58 pm

On Tue, 01 Mar 2005 15:33:13 -0500, zentara <zentara@highstream.net>
wrote:

>Well I made an improvement, and am almost there. :-)
>
>This script, will keep the individual sliders in their respective
>ranges, and will track which sliders have to be watched for
>"cascading".


Well, I came up with an idea to make the cascading
work( almost). I had to give up on having "individual min's and max's"
in order to get this to work. There is probably a way to work them in
together, but this as far as I'm going with this. ;-)

See if this spurs your imagination. :-)
#!/usr/bin/perl
use warnings;
use strict;
use Tk;

my $xinit; #global for dragging
my $move;

my $mw = MainWindow->new;
$mw->geometry("590x60");

my $width = 500;
my $height = 30;

my $min = 0;
my $max = 500;

my %sliders = (
1 => {
value => 45,
color => 'red',
min => 5,
max => 495,
},

2 => {
value => 150,
color => 'cyan',
min => 5,
max => 495,
},

3 => {
value => 260,
color => 'lightblue',
min => 5,
max => 495,
},

4 => {
value => 350,
color => 'green',
min => 5,
max => 495,
},
);

# do some error checking here to make sure values are within
# respective ranges

#create slider canvas
my $canvas = $mw->Canvas(-width => $width, -height =>$height,
-bg => 'black',
-borderwidth => 0,
-relief => 'sunken',
)->pack;

#find array of sliders once, to be reused
my @sliders = sort {$a<=>$b} keys %sliders;

foreach my $slidernum(@sliders ){

$sliders{$slidernum}{'obj'} = $canvas->createLine(
$sliders{$slidernum}{'value'}, 0,
$sliders{$slidernum}{'value'}, $height,
-fill => $sliders{$slidernum}{'color'},
-width => 10,
-tags => [$slidernum, 'move'],
);

$sliders{$slidernum}{'obj1'} = $canvas->createLine(
$sliders{$slidernum}{'value'}, 0,
$sliders{$slidernum}{'value'}, $height,
-fill => 'black',
-width => 1,
-tags => [$slidernum, 'move'],
);

$sliders{$slidernum}{'group'} = $canvas->createGroup(
[$sliders{$slidernum}{'value'}, 0],
-members => [$sliders{$slidernum}{'obj'},
$sliders{$slidernum}{'obj1'}],
-tags => [$slidernum, 'move'],
);

}

$canvas->bind('move', '<1>', sub {&mobileStart();});
$canvas->bind('move', '<B1-Motion>', sub {&mobileMove();});
$canvas->bind('move', '<ButtonRelease>', sub {&mobileStop();});


my $bframe = $mw->Frame()->pack(-expand =>'x');

foreach my $slidernum(@sliders){
$bframe->Label(-text => $slidernum,
-background => $sliders{$slidernum}{'color'}
)->pack(-side=>'left');
$bframe->Entry(-textvariable => \$sliders{$slidernum}{'value'},
-width => 5,
)->pack(-side=>'left');
$bframe->Label(-text => ' ')->pack(-side=>'left');

}

my $closebutton = $bframe->Button(-text => 'Exit',
-command => sub{ exit })->pack(-side=>'right');


MainLoop;
########################################
######################
sub mobileStart {
my $ev = $canvas->XEvent;
$xinit = 0 - $ev->x;
$canvas->raise('current');
# $canvas->bind('current', '<Leave>', sub { $move = 0 });
# print "START MOVE->$xinit\n";
}
########################################
#####################
sub mobileMove {
my $ev = $canvas->XEvent;
my ($slidernum,undef,undef) = $canvas->gettags('current');

$move = $ev->x + $xinit;

# detect which direction you are moving and deduce which
# sliders need to be watched for a cascading move
my @watch = ();
if($move > 0) #moving to right
{ @watch = grep { $_ > $slidernum } @sliders;
}else{ @watch = grep { $_ < $slidernum } @sliders;
}
print "watch->@watch\n";

my($xnow,undef) =
$canvas->coords( $sliders{$slidernum}{'obj1'} );
print "$xnow\n";

#test for individual min max limits
if( $xnow > $sliders{$slidernum}{'max'} )
{ my $diff = $sliders{$slidernum}{'max'} - $xnow;
$move = $diff;
}

if( $xnow < $sliders{$slidernum}{'min'} )
{ my $diff = $sliders{$slidernum}{'min'} - $xnow;
$move = $diff;
}

#need tests here to detect collisions
# setup initial tag array for primary mover
my @sliders_2_move = $sliders{$slidernum}{'group'};

if($move < 0){
foreach my $slidw(@watch){
if( $xnow <= $sliders{$slidw}{'value'} )
{
push @sliders_2_move, $sliders{$slidw}{'group'};
}
}
}

if($move > 0){
foreach my $slidw(@watch){
if( $xnow >= $sliders{$slidw}{'value'} )
{
push @sliders_2_move, $sliders{$slidw}{'group'};
}
}
}

print "movers->@sliders_2_move\n";

foreach(@sliders_2_move){
$canvas->move( $_ ,$move, 0 );
}

$xinit = 0 - $ev->x;

foreach my $slinum (@sliders_2_move){
my ($slidernum,undef,undef) = $canvas->gettags($slinum);

($sliders{$slidernum}{'value'},undef,und
ef,undef ) =
$canvas->coords( $sliders{$slidernum}{'obj1'} );
}
}
########################################
#################

sub mobileStop{ &mobileMove; }

__END__




--
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html
Chris

2005-03-03, 8:57 pm

zentara wrote:
> On Tue, 01 Mar 2005, at various times throughout the day zentara

<zentara@highstream.net>
> wrote:
>
> [ several iterations of a multi-scale slider ]


<applause>! I am very impressed and grateful! Not only did you
get most of the logic working mostly as I had in mind -- and in ONE
DAY, apparently -- but you also did it in less than one-quarter the
number of lines of code it was taking ME to do a Canvas-based "mega-
widget" implementation -- which didn't work nearly HALF as well as
yours! :-) You surely do know your Canvas widget -- you used a lot
of commands and operations that I've never seen before, which I will
have to study and add to my own repertoire. Thank you, thank you,
thank you!

> I had to give up on having "individual min's and max's"
> in order to get this to work.


Actually, it's fine the way it is -- I never WANTED "individual min's
and max's" in the FIRST place -- assuming that YOUR idea of
"min's and max's" is the same as mine, i.e. "limits on HOW FAR a
slider can MOVE." In my grand vision of the "MultiScale widget,"
the only limits on a slider's motion are "whenever-and-wherever
it bumps up against something it CAN'T PUSH" -- be that an
adjacent slider (perhaps individual sliders are CONFIGURABLE as
to "pushability") or an end of the trough. Unless you mean some-
thing different when you say "min's and max's," I actually prefer
it the way it turned out -- I was actually a little distressed to see
individual limits, in your first draft!

> There is probably a way to work them in
> together, but this as far as I'm going with this. ;-)
>
> See if this spurs your imagination. :-)


Yes, it surely does! I already have a few tweaks-and-enhancements in
mind, for the particular application that is driving all this. In
decreasing
order of priority, these include:

- VERTICAL rather than HORIZONTAL layout: ideally, in keeping
with the proud traditions <cough cough> of the standard Scale
widget, this should be configurable via an '-orient' option, but
in the particular application at hand, I'll settle for a whole
separate hunk of code that lays out the Scale vertically rather
than horizontally. Dang, I could have saved myself some work
if only I'd thought to mention this in the FIRST place. ;-)

- handling of 'undef' values: a wide-open field full of opportuni-
ties to break the code in all kinds of completely devastating
ways. (Thank heaven I will always-and-forever be able to
retrieve your original code from Google!) I'm open to sugges-
tions as to a set of "appropriate" or "reasonable" -- I might
even settle for simply "self-consistent" -- behaviors for a slider
whose associated variable may at any time take on an 'undef'
value. For example, consider the implications of a policy that
"a slider should DISAPPEAR (from the display) when its value is
'undef.' Okay, so should the "disappeared" slider still continue
to limit its neighbors' motion somehow? If so, HOW? In what
meaningful way CAN an 'undef' slider behave, and influence
others within the MultiScale paradigm? If a slider DOESN'T
limit its neighbors' motion while it's disappeared, then what
about if its variable is later assigned a NON-'undef' value,
causing it to REAPPEAR? Surely it should once again become
a limit to its neighbors' freedom -- but what if, in the mean-
time, one of those neighbors has "slipped past" the reappearing
slider's position? Do I reorder the SLIDER relationships accord-
ing to the new ordering of VALUES, or do I forcibly set a new
value into the neighbor-who-slipped, to make it once again
respect the suddenly-reappearing constraint? It almost has
to be configurable-in-great-detail in order to support "WHAT-
EVER BEHAVIOR IS APPROPRIATE FOR ANY GIVEN APPLICATION."
Thoughts? Inquiring minds are being rapidly driven insane.

- Arrange for the sliders NOT TO OVERLAP. When I said they
should "bump up against" each other, I meant to define "bump-
ing up" as the first position where adjacent sliders' NEAREST
EDGES FIRST TOUCH -- NOT when their single, numeric "posi-
tion values" become equal, as seems currently to be the case.
Alas, this "simple detail" is precisely what drove me batty, and
flung me painfully AWAY from attempting a Canvas-based
implementation, the FIRST time around. Wish me luck; if I am
never heard from again, just send flowers care of the local
loony bin...

- Arrange for the sliders, and their associated values, NOT TO
"JITTER" when the user attempts to drag them beyond the limits
of the trough. I don't know how-or-why the standard Scale's
slider doesn't do this, or why yours DOES -- and I'm not com-
plaining, mind you! -- but I'm going to try to tweak it for the
sake of aesthetics.

Again, much thanks.

Chris

zentara

2005-03-04, 3:59 pm

On 3 Mar 2005 14:35:51 -0800, "Chris" <cchiesa1@rochester.rr.com> wrote:

>
>Yes, it surely does! I already have a few tweaks-and-enhancements in
>mind, for the particular application that is driving all this. In
>decreasing
>order of priority, these include:
>
> - VERTICAL rather than HORIZONTAL layout: ideally, in keeping
> with the proud traditions <cough cough> of the standard Scale
> widget, this should be configurable via an '-orient' option, but
> in the particular application at hand, I'll settle for a whole
> separate hunk of code that lays out the Scale vertically rather
> than horizontally. Dang, I could have saved myself some work
> if only I'd thought to mention this in the FIRST place. ;-)


Thats actually pretty easy, in the code I started with, I had 'y' motion
too, but set the 'y'field to zero. For instance;

###############
sub mobileStart {
my $ev = $canvas->XEvent;
$dx = 0 - $ev->x;
$canvas->raise('current');
print "START MOVE->$dx\n";
}

sub mobileMove {
my $ev = $canvas->XEvent;
$canvas->move('current', $ev->x + $dx, 0 );

$dx = 0 - $ev->x;
print 'Value->', -$dx ,"\n";
}
###############

was originally

###########################
sub mobileStart {
my $ev = $canvas->XEvent;
($dx, $dy) = (0 - $ev->x, 0 - $ev->y);
$canvas->raise('current');
print "START MOVE-> $dx $dy\n";
}

sub mobileMove {
my $ev = $canvas->XEvent;
$canvas->move('current', $ev->x + $dx, $ev->y +$dy);
($dx, $dy) = (0 - $ev->x, 0 - $ev->y);
print "MOVING-> $dx $dy\n";
}

###############################


So you could just change the routines to watch 'y'
in the vertical, and set the 'x' component to 0.



> - Arrange for the sliders NOT TO OVERLAP. When I said they
> should "bump up against" each other, I meant to define "bump-
> ing up" as the first position where adjacent sliders' NEAREST
> EDGES FIRST TOUCH --


Yeah, where I test for when the objects overlap, I'm using the
"centerline", or the the coords for the
$canvas->coords( $sliders{$slidernum}{'obj1'} );

You could use
my ($x,$y,$x1,$y1) = $canvas->bbox( $sliders{$slidernum}{group} )

to get the box around the whole slider group. But you will need some
logic to take either the $x of $x1 , depending on whether the
slider is moving left or right. It gets further complicated, because
you will test the "left-most" 'x' coord of the active-slider against
the "right-most" 'x' coord of a static slider( if moving to the left).
And Vice-Versa if moving to the right. So you can see why I stuck
with the simplicity of the "centerpoint". :-) But it can be done. Just
carefully map the coords out in hashes, and check and update them
all as you move a slider(s). The check for collisions.

Another option is to count the number of tags returned by
$canvas->find('withtag','current'). The count should double(triple)
when overlapping, so you can test for that to do things. But maybe the
first way, of keeping a hash-map of the bbox's of each slider is the
easiest.

Another problem, is that bbox, returns only to + or - 1 pixel accuracy.
That is where I was thinking about Zinc. Zinc reports coords to
5(or more) decimal places accuracy.


>Again, much thanks.
>
>Chris


Goodluck, I hope you can turn it into a useful module.


--
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com