The Canvas ControlScrolling Text and Images


The next example is one whose only reason for being is to provide an example. The example will show you how to draw and position both text and images as well as how to scroll a Canvas control using a Scrollbar control. There is also a Slider control that serves two purposes, depending on whether a graphic or text is being displayed. If graphics are being displayed, the Slider control will scale the image size, making it larger or smaller. If text is being displayed, it adjusts the vertical position of the text. In a sense, this is like scrolling, except that the text being displayed is moving within the Graphic object, whereas when using the ScrollBar, the entire image contained by the Graphic object is moving up and down. If this is a little unclear, a look at the comments in the code will show you exactly what is happening.

There are two buttons on Window1. The first is labeled Draw Text, and it takes the text from the EditField to the right of it and draws the String in the Canvas1 control. Below that button is an EditField, which is used to set the horizontal position of the text when it is drawn in Canvas1. Beneath the EditField is a Slider control called ImageMover that sets the vertical position of the text. Finally, the last EditField is used to set the width of the String. In other words, it determines when the text gets wrapped.

In Figure 10.1, the horizontal position of the text is 0, the vertical position is set to 10, and the width of the String is set to 100.

Figure 10.1. Drawing text.


The Slider ImageMover (labeled as Vertical in the Window) moves the text up or down within the Canvas.

In the Figure 10.2, the ImageMover Slider has been moved all the way to the right, meaning that the vertical position starts at 100. As a result, the text is drawn in the middle of the Picture instead of at the top of the Picture object.

Figure 10.2. Drawing text offset vertically by 100 pixels.


The Slider control has the following properties that you access to find out the position of the slider:

Slider.Value as Integer Slider.Minimum as Integer Slider.Maximum as Integer Slider.LineStep as Integer Slider.PageStep as Integer Slider.LiveScroll as Boolean


The Value property represents how far to the right (or down toward the bottom) the Slider has been moved. The direction is set by how you size the control. If it is wider than it is long, it moves along the horizontal axis; otherwise, it moves along the vertical axis. You can set the Minimum and Maximum values, which proscribes the available range of values for the Slider control. There are two ways to move the Slider: the first is to click and drag the Slider, and the second is to click a position in the Control. Dragging moves the value of Value up or down by increments set in the LineStep property. If you click a location in the Slider, the value of Value increments or decrements by the value set in PageStep. Normally, as you drag the Slider control one direction or another, nothing happens until you release it. However, if you have LiveScroll set to TRue, the Value property gets updated as you drag it.

In this example, the Minimum value is 0; the Maximum value is 100. The LineStep property equals 1, the PageStep property equals 20, and LiveScroll is set to TRue. One consequence of setting LiveScroll to true is that you will be able to see the text move up or down as you move the Slider. There is a trick to this, however, that will be explained shortly.

Next, I'll show you what happens when the Scrollbar control to the right of Canvas1 gets moved. The Canvas control has a method that handles scrolling the image that gets viewed in the control, but it does not work exactly like the Scrollbar control does, so there is some additional work to be done to get the scrolling to work properly.

The method used by the Canvas control follows:

[View full width]

Canvas.Scroll(DeltaX as Integer, DeltaY as Integer, [Left as Integer], [Top as Integer], [Width as Integer], [Height as Integer], [ScrollControls as Boolean])


The Scrollbar control works in a similar way to a Slider control. When the Scrollbar.ValueChanged event gets triggered, no argument is passed to it. All that it does is signal that the Scrollbar has been moved. To find the current value, you need to check the value of Scrollbar.Value.

The Canvas.Scroll method expects values for DeltaX and DeltaY, both of which represent the rate of change, or how far one direction or another the Canvas has been scrolled in a horizontal or vertical direction. All you have with the Scrollbar is the current value. This means that you have to keep track of the previous Scrollbar position and compare it with the current Scrollbar position when the ValueChanged event gets triggered. This will tell you how much the Scrollbar has been scrolled, as well as the direction in which it was scrolled.

In this particular example for Scrollbar, the PageStep value has been set to 20 and the LineStep value has been set to 1. Like the ImageMover Slider control, the LiveScroll property is set to true.

Figure 10.3 shows what happens when Scrollbar1 is scrolled down. Instead of just the text moving down, as happens when ImageMover is moved, the entire image moves up, and the only part that is displayed is that part that still resides within the frame of Canvas1.

Figure 10.3. Text scrolled using Scrollbar.


You should also see that the current Scrollbar position is displayed in a StaticText field, along with the last Scrollbar position. The New Scrollbar Position StaticText field indicates the degree of change incurred between firing of the ValueChanged event. In this case the value is 1.

In Figures 10.4, 10.5, and 10.6 you'll see the same thing, except that instead of drawing text into Canvas1, a JPEG image will be opened from the file system and then manipulated with the ImageMover Slider and Scrollbar1.

There is one notable difference, however, and that is that the ImageMover Slider does not redraw the image in another location. Instead, it changes the scale of the image, anywhere from 0% to 100%. Figure 10.4 shows the image scaled to 23% of the original size.

Figure 10.4. Image scaled to 23%.


In Figure 10.5, the ImageMover handle is slid all the way to the right, and the image is redrawn at 100% scale.

Figure 10.5. Image scaled to 100%.


Finally, when Scrollbar1 is used, the image gets scrolled just like the text does, which can be seen in Figure 10.6.

Figure 10.6. Image scrolled using the Scrollbar.


Now that you've seen the output of the sample application, it's time to review the code in more detail. There are a lot of things going on, especially with the ImageMover Slider control and Scrollbar1.

Before I cover those, I want to show Window1's properties, followed by the DrawTextPushbutton and OpenJPGPushButton.

Listing 10.1. Window1 Properties

// The fontsize used to display the text. Window1.fsize as Integer = 12 // The previous value for Scrollbar1.Value. // This is used to calculate how much the // Scrollbar has changed in value since the // most revent ValueChanged event. Window1.LastScroll as Integer // A reference to the Picture that is // being draw offscreen Window1.p as Picture // A reference to the PixmapShape object // that will display the Picture loaded from // the file system. I could have simply used // a Picture object, but I chose a PixmapShape // object because it allows you to scale the image. Window1.px as PixmapShape // When using Scrollbar1 to scroll the Canvas, // I need to keep track of the current // horizontal and vertical offset position // of Window1.px. The reason for this is that // the image will need to get redrawn as the // Canvas is scrolled and I need to redraw it // in the right place. See the Scrollbar1.ValueChanged // event for details on how these values are used. Window1.PicHorizon as Integer = 0 Window1.PicVertical as Integer = 0

Listing 10.2. Window1.DrawTextPushButton.Action Handles Event

// Displays the text in TextField in Canvas1 DrawPicture(DrawString(TextField.Text), 0,0)

Listing 10.3. Window1.DrawString(s as String) as Picture

// Renders the s String as a Picture object and // returns it. // // The picture should be the same height and width // as the Canvas in which it is displayed. // The color depth is 32 bits. p = NewPicture(Canvas1.Width, Canvas1.Height, 32) // The String is drawn in the positions displayed // in the HorizontalField EditField and the // position of the ImageMover Slider control. // The width of the String determines where the // text will wrap. The WidthField EditField holds // this value. p.Graphics.DrawString(s, Val(HorizontalField.Text), ImageMover.Value, Val(WidthField.Text)) // Return the p Picture object. Return p

Listing 10.4. Window1.DrawPicture(p as Picture, Width as Integer, Height as Integer)

// Draws the buffered picture Canvas1.Graphics.DrawPicture(p, PicHorizon, PicVertical)

Listing 10.5. Window1.OpenJPGPushButton.Action Handles Event

Dim f as FolderItem f = GetOpenFolderItem("image/jpg") If f <> Nil Then p = f.OpenAsPicture // Instantiate a PixmapShape for // the image. px = new PixmapShape(p) // Next, use the PixmapShape.Scale // method to scale the image according to the // value in the ImageMover Slider control. // The range of values for ImageMover.Value // is zero to 100. Divide that value by 100 // to get the value as a percent. In other words, // if the value is 99, then 99/100 equals .99, // which is equal to 99% px.Scale= ImageMover.Value / 100 // Draw the PixmapShape in Canvas1 Canvas1.Graphics.DrawObject(px) // Display the current position where the image // is being drawn. PicPos.Text = Str(PicHorizon) + "/" + Str(PicVertical) End If

The next event is the ImageMover.ValueChanged event, and this requires a little more explanation. First, here's the code that is executed when the event is triggered:

Listing 10.6. Sub ImageMover.ValueChanged() Handles Event

Dim aPic as Picture Dim s as StringShape // Display the current value for the Slider SliderPos.Text = Str(Me.Value) // If displaying a Picture If px <> Nil Then aPic = NewPicture(Canvas1.Width, Canvas1.Height, 32)         Self.px.Scale = Me.value / 100         aPic.Graphics.DrawObject(px)         Canvas1.Graphics.DrawPicture(apic, PicHorizon, PicVertical) Else // Display the text from TextField         DrawPicture(DrawString(TextField.Text), 0, Me.Value) End If 

As you can see in the code, the ImageMover slider tests to see if the Px property is not Nil. The Px property is set when an image has been opened up, so that means that when it is Nil, it will display the Text in the TextField EditField. At this point, the concern is displaying text. As you can see in the code, the DrawString method is called to generate a Picture object of the String, and that Picture object is passed to the DrawPicture method, where it is displayed in Canvas1. You may have wondered why I used two steps to display the text. I could have just as easily done all the drawing of the text directly in the Graphics object of Canvas1, but if I had, the text would flicker when it got redrawn as I dragged the Slider handle. To keep that from happening, I draw the Picture offscreen and then, after the image is rendered, I display the image in Canvas1.

This is a technique sometimes called double buffering. Basically, all that I am doing is this: It takes a certain amount of time to render the String as an Image. When I am dragging the Slider handler, the String has to be rerendered with each increment of the drag, and the delay in time results in the flicker you see on the screen. If instead of rendering the text directly in Canvas1's Graphic object, I render it in a separate Picture object and then draw that Picture in the Canvas1 Graphics object, the time spent rendering the new text takes place offscreen and only after it is done does the old image get swapped out for the old. Displaying a new graphic that has already been rendered can be done a lot faster, so the flicker disappears.

Next is the Scrollbar1.ValueChanged event and it, like the previous event, is worthy of some extended discussion.

Listing 10.7. Window1.Scrollbar1.ValueChanged Handles Event

Dim NewScroll as Integer Dim aPic as Picture ScrollBarPos.Text = "Scrollbar Position: " + Str(Me.Value) LastScrollBarPos.Text ="Last Scrollbar Position: " + Str(LastScroll) // Subtract the current value of Scrollbar.Value from // the value of LastScroll in order to get the rate and // direction of change (a negative number means it's // scrolling up, a positive number means it's scrolling // down NewScroll = LastScroll - Me.Value // Display the position NewScrollBarPos.Text = "New Scrollbar Position: " + Str(newScroll) // Scroll the Canvas by passing NewScroll as the // value for DeltaY. Since there is only a // vertical Scrollbar, DeltaX is zero. Canvas1.Scroll(0, NewScroll) // Calculate the new vertical position of the picture // so that it will be redrawn in the correct place. PicVertical = PicVertical + newScroll PicPos.Text = Str(PicHorizon) + "/" + Str(PicVertical) // Set LastScroll equal to the current position of the // Scrollbar. LastScroll = Me.Value If px <> Nil Then     // If px is not Nil, then an image is being viewed.     // The first step is to create a new Picture object     // that will serve as the buffer.     aPic = NewPicture(Canvas1.Width, Canvas1.Height, 32)         self.px.Scale = ImageMover.value / 100     // Draw the px object into aPic     aPic.Graphics.DrawObject(px)     // Next, draw the buffered Picture object aPic     // in Canvas1, using the values from PicHorizon     // and PicVertical.         Canvas1.Graphics.DrawPicture(aPic, PicHorizon, PicVertical) Else     // Create a buffer for displaying the text        aPic = NewPicture(Canvas1.Width, Canvas1.Height, 32)     // Draw the text         DrawPicture(DrawString(TextField.Text), 0, ImageMover.Value) End If 

Using the ScrollBar and the Canvas scrolling methods is a little more challenging than simply resizing images or repositioning text within a Picture object, like I did with the ImageMover slider control. The reason is that as you scroll, not all of the Picture will be drawn on the screen. If you scroll down, the Canvas will handle drawing only the part of the Picture that should be drawn. However, if you then scroll back up, you will find that the top half of the picture is gone. To do this, you need to resort to more double buffering, only this time you also have to keep track of the current position of the Picture so that you can redraw it in the right place. To do so, I use the PicHorizon and the PicVertical properties, both of which start off set to 0 because when the picture is first drawn, the Scrollbar has not been scrolled down at all. As the Scrollbar.Value value changes, the value for PicVertical needs to change as well. With each ValueChanged event, the picture needs to be redrawn in the new position.

To keep track of the position, you need to be able to know how far the Scrollbar has been scrolled. The Scrollbar.Value property only tells you the current valueit doesn't tell you how much the value has changed or in which direction it has changed. To do that, I use the LastScroll property to store the previous position and then use it to calculate which direction and by how much the Scrollbar has been changed. After I have this value, I can then call the Canvas.Scroll method, which expects a value that represents how much has been scrolled, rather than an absolute scroll position like that available in the Scrollbar.Value property.




REALbasic Cross-Platform Application Development
REALbasic Cross-Platform Application Development
ISBN: 0672328135
EAN: 2147483647
Year: 2004
Pages: 149

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net