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:
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
Listing 10.2. Window1.DrawTextPushButton.Action Handles Event
Listing 10.3. Window1.DrawString(s as String) as Picture
Listing 10.4. Window1.DrawPicture(p as Picture, Width as Integer, Height as Integer)
Listing 10.5. Window1.OpenJPGPushButton.Action Handles Event
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
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
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. |