Scrollbars - Part 7 - Processing the scroll message

In the previous articles in this series (parts 1, 2, 3, 4, 5 and 6) we investigated the scrollbar messages and set-up the scrollbars for our application. In this article we finally make the scrollbars do something for us.

In the Scroll handler we react to each scrollbar operation, and re-position the image:

51 sub process_scroll {

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

53

54 my $prev_pos = $self->ScrollPos($bar);

55 my $new_pos = $prev_pos;

56

57 if ( $op == SB_LINEUP ) { # or SB_LINELEFT 58 $new_pos -= 1;

59 }

60 elsif ( $op == SB_LINEDOWN ) { # or SB_LINERIGHT 61 $new_pos += 1;

62 }

63 elsif ( $op == SB_PAGEUP ) { # or SB_PAGELEFT 64 $new_pos -= $self->ScrollPage($bar);

65 }

66 elsif ( $op == SB_PAGEDOWN ) { # or SB_PAGERIGHT 67 $new_pos += $self->ScrollPage($bar);

68 }

69 elsif ( $op == SB_THUMBTRACK ) {

70 $new_pos = $pos;

71 }

72 elsif ( $op == SB_THUMBPOSITION ) {

73 $new_pos = $pos;

74 }

75

76 $self->ScrollPos( $bar, $new_pos );

77

78 if ( $bar == SB_VERT ) {

79 $self->BM->Top( -$new_pos );

80 }

81 else { # SB_HORZ 82 $self->BM->Left( -$new_pos );

83 }

84

85 return 1;

86 }

There are two subtleties:

The first is that because we have chosen a positive range for our reported positions, we have to negate them before using them to position the label control.

The second is that we also need to re-position the control in the Resize handler: because we change the page size in this handler we may make the current position invalid (remember from the last article in the series the page-size affects the maximum reportable position of the scrollbar). Fortunately the scrollbar implementation takes care of adjusting the current position for us, so we can just retrieve the new current position after we set the page size and use that to position the control.

40 sub process_resize {

41 my ($self) = @_;

42

43 $self->ScrollPage( SB_HORZ, $self->ScaleWidth() );

44 $self->ScrollPage( SB_VERT, $self->ScaleHeight() );

45

46 $self->BM->Move( -$self->ScrollPos(SB_HORZ), -$self->ScrollPos(SB_VERT) );

47

48 return 1;

49 }

Finally we end up with what we want - scrollbars that allow us to scroll around the image and see the parts that don't fit into the window.

Note that handling both the SB_THUMBTRACK and SB_THUMBPOSITION operations is not strictly necessary. Typically it is better to handle the SB_THUMBTRACK, as that allows us to move the contents while the user is dragging the thumb; however, if we had a window that took a long time to redraw, then we might chose to only process the SB_THUMBPOSITION operation so that we only need to redraw when the user releases the thumb. Try removing the branches in the above code to see the 2 behaviours.

As always, here is the full code:

#!perl -w

use strict;

use warnings;

use Win32::GUI 1.05 qw(CW_USEDEFAULT WS_CLIPCHILDRENWM_HSCROLL WM_VSCROLLSB_CTL SB_HORZ SB_VERTSB_LINEUP SB_LINEDOWN SB_PAGEUP SB_PAGEDOWNSB_THUMBTRACK SB_THUMBPOSITION);

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

-title => "Scrollbar 07: Process Scroll Messages",

-left => CW_USEDEFAULT,

-size => [ 400, 300 ],

-addstyle => WS_CLIPCHILDREN,

-vscroll => 1,

-hscroll => 1,

-onScroll => \&process_scroll,

-onResize => \&process_resize,

);

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

$mw->AddLabel( -bitmap => $bm, -name => 'BM' );

my ( $bmw, $bmh ) = $bm->Info();

$mw->ScrollRange( SB_HORZ, 0, $bmw );

$mw->ScrollRange( SB_VERT, 0, $bmh );

$mw->ScrollPage( SB_HORZ, $mw->ScaleWidth() );

$mw->ScrollPage( SB_VERT, $mw->ScaleHeight() );

$mw->Show();

Win32::GUI::Dialog();

$mw->Hide();

exit(0);

sub process_resize {

my ($self) = @_;

$self->ScrollPage( SB_HORZ, $self->ScaleWidth() );

$self->ScrollPage( SB_VERT, $self->ScaleHeight() );

$self->BM->Move( -$self->ScrollPos(SB_HORZ), -$self->ScrollPos(SB_VERT) );

return 1;

}

sub process_scroll {

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

my $prev_pos = $self->ScrollPos($bar);

my $new_pos = $prev_pos;

if ( $op == SB_LINEUP ) { # or SB_LINELEFT $new_pos -= 1;

}

elsif ( $op == SB_LINEDOWN ) { # or SB_LINERIGHT $new_pos += 1;

}

elsif ( $op == SB_PAGEUP ) { # or SB_PAGELEFT $new_pos -= $self->ScrollPage($bar);

}

elsif ( $op == SB_PAGEDOWN ) { # or SB_PAGERIGHT $new_pos += $self->ScrollPage($bar);

}

elsif ( $op == SB_THUMBTRACK ) {

$new_pos = $pos;

}

elsif ( $op == SB_THUMBPOSITION ) {

$new_pos = $pos;

}

$self->ScrollPos( $bar, $new_pos );

if ( $bar == SB_VERT ) {

$self->BM->Top( -$new_pos );

}

else { # SB_HORZ $self->BM->Left( -$new_pos );

}

return 1;

}

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