Scrollbars - Part 4 - The Scroll Event

You might want to see parts 1, 2, and 3 before reading this article.

So far we have a window that shows a part of an image, and have added scrollbars to the window, but the scrollbars don't yet work. In this article we'll look at the event we need to handle to make the scrollbars do something useful.

5 use Win32::GUI 1.05 qw( 6 CW_USEDEFAULT WS_CLIPCHILDREN 7 WM_HSCROLL WM_VSCROLL 8 SB_CTL SB_HORZ SB_VERT 9 SB_TOP SB_BOTTOM SB_LINEUP SB_LINEDOWN SB_PAGEUP SB_PAGEDOWN 10 SB_LEFT SB_RIGHT SB_LINELEFT SB_LINERIGHT SB_PAGELEFT SB_PAGERIGHT 11 SB_THUMBTRACK SB_THUMBPOSITION SB_ENDSCROLL 12 );

13

14 my @vert_cmds = qw(SB_LINEUP SB_LINEDOWN SB_PAGEUP SB_PAGEDOWN 15 SB_THUMBPOSITION SB_THUMBTRACK 16 SB_TOP SB_BOTTOM 17 SB_ENDSCROLL);

18 my @horz_cmds = qw(SB_LINELEFT SB_LINERIGHT SB_PAGELEFT SB_PAGERIGHT 19 SB_THUMBPOSITION SB_THUMBTRACK 20 SB_LEFT SB_RIGHT 21 SB_ENDSCROLL);

Don't worry too much about all these constants. We'll eventually see that we don't need many of them; I'll explain the important ones below, and the 2 arrays are to simplify the conversion of numeric numbers to strings for display of the messages.

23 my $mw = Win32::GUI::Window->new(

24 -title => "Scrollbar 04: View Scroll Messages",

25 -left => CW_USEDEFAULT,

26 -size => [ 400, 300 ],

27 -addstyle => WS_CLIPCHILDREN,

28 -vscroll => 1,

29 -hscroll => 1,

30 -onScroll => \&process_scroll,

31 );

The event we need to handle is the 'Scroll' event - it is triggered whenever a user does something with one of our scrollbars. I'm using a NEM-style handler here (-onScroll), but you can (almost as) easily use an OEM-style handler (sub NAME_Scroll(...)).

42 sub process_scroll {

43 my ( $self, $bar, $op, $pos ) = @_;

The handler is called with 4 arguments:

    1. $self is the window object that contains the scrollbar.
    2. $bar indicates which scrollbar is being used - possible values are SB_VERT for the vertical scrollbar or SB_HORZ for the horizontal scrollbar.
    3. $op is information about what operation is being performed - more on this in a minute.
    4. $pos is the (new) position of the scrollbar - note that it is zero unless $op is SB_THUMBTRACK or SB_THUMBPOSITION.

The possible values for $op for vertical scrollbars are:

    • SB_LINEUP when the arrow at the top is pressed. Indicates that we should move one 'line' towards the top of the contents of the window.
    • SB_LINEDOWN when the arrow at the bottom is pressed. Indicates that we should move one 'line' towards the bottom of the contents of the window.
    • SB_PAGEUP when the sunken area between the thumb and the top arrow is pressed. Indicates that we should move one 'page' towards the top of the contents of the window.
    • SB_PAGEDOWN when the sunken area between the thumb and the bottom arrow is pressed. Indicates that we should move one 'page' towards the bottom of the contents of the window.

For horizontal scrollbars there are a similar set of messages:

    • SB_LINELEFT when the arrow at the left is pressed. Indicates that we should move one 'line' towards the left of the contents of the window.
    • SB_LINERIGHT when the arrow at the right is pressed. Indicates that we should move one 'line' towards the right of the contents of the window.
    • SB_PAGELEFT when the sunken area between the thumb and the left arrow is pressed. Indicates that we should move one 'page' towards the left of the contents of the window.
    • SB_PAGERIGHT when the sunken area between the thumb and the right arrow is pressed. Indicates that we should move one 'page' towards the right of the contents of the window.

Both horizontal and vertical scrollbars can generate events for the following operations:

    • SB_THUMBTRACK when the thumb is being dragged. $pos indicates the current position of the dragged thumb.
    • SB_THUMBPOSITION when the thumb is released after being dragged. $pos indicates the position of the dragged thumb when the mouse is released.
    • SB_ENDSCROLL whenever a scroll operation finishes.

Note that we'll see that we are under control of the definition of the size of a 'line' and a 'page' in future articles in this series.

45 my ( $bar_text, $op_text );

46

47 if ( $bar == SB_VERT ) {

48 $bar_text = "VERTICAL";

49 $op_text = $vert_cmds[$op];

50 }

51 elsif ( $bar == SB_HORZ ) {

52 $bar_text = "HORIZONTAL";

53 $op_text = $horz_cmds[$op];

54 }

55 else {

56 $bar_text = "UNKNOWN";

57 $op_text = "UNKNOWN";

58 }

59

60 printf "%-10s : %-16s : %d\n", $bar_text, $op_text, $pos;

61

62 return 1;

63 }

The rest of the code decodes the $bar and $op fields, before displaying the information. Here's the full code for this article - run it and play with the scrollbars to see the generated messages. Next time we'll see how to set the range of positions the scrollbar can report, rather than the default 0 through 100 that you'll see if you drag the thumb from one end of the scrollbar to the other.

#!perl -w

use strict;

use warnings;

use Win32::GUI 1.05 qw(CW_USEDEFAULT WS_CLIPCHILDRENWM_HSCROLL WM_VSCROLLSB_CTL SB_HORZ SB_VERTSB_TOP SB_BOTTOM SB_LINEUP SB_LINEDOWN SB_PAGEUP SB_PAGEDOWNSB_LEFT SB_RIGHT SB_LINELEFT SB_LINERIGHT SB_PAGELEFT SB_PAGERIGHTSB_THUMBTRACK SB_THUMBPOSITION SB_ENDSCROLL);

my @vert_cmds = qw(SB_LINEUP SB_LINEDOWN SB_PAGEUP SB_PAGEDOWNSB_THUMBPOSITION SB_THUMBTRACKSB_TOP SB_BOTTOMSB_ENDSCROLL);

my @horz_cmds = qw(SB_LINELEFT SB_LINERIGHT SB_PAGELEFT SB_PAGERIGHTSB_THUMBPOSITION SB_THUMBTRACKSB_LEFT SB_RIGHTSB_ENDSCROLL);

my $mw = Win32::GUI::Window->new(

-title => "Scrollbar 04: View Scroll Messages",

-left => CW_USEDEFAULT,

-size => [ 400, 300 ],

-addstyle => WS_CLIPCHILDREN,

-vscroll => 1,

-hscroll => 1,

-onScroll => \&process_scroll,

);

my $bm = Win32::GUI::Bitmap->new("kids.bmp");

$mw->AddLabel( -bitmap => $bm );

$mw->Show();

Win32::GUI::Dialog();

$mw->Hide();

exit(0);

sub process_scroll {

my ( $self, $bar, $op, $pos ) = @_;

my ( $bar_text, $op_text );

if ( $bar == SB_VERT ) {

$bar_text = "VERTICAL";

$op_text = $vert_cmds[$op];

}

elsif ( $bar == SB_HORZ ) {

$bar_text = "HORIZONTAL";

$op_text = $horz_cmds[$op];

}

else {

$bar_text = "UNKNOWN";

$op_text = "UNKNOWN";

}

printf "%-10s : %-16s : %d\n", $bar_text, $op_text, $pos;

return 1;

}

Source code can be downloaded from the series index page. Back to Part 3. Move on to Part 5.