The earlier Draw Shapes example worked very well because everything you needed to draw fit into initial window size, This section covers what you need to do if that is not the case.
this example, you expand the Draw Shapes sample to demonstrate scrolling, To make things a bit realistic, you start by creating an example, Big Shapes, in which you make the rectangle and a bit bigger, Also while you are at it, you will see how to use the Point, Size, and Rectangle tructs by using them to assist in defining the drawing areas, With these changes, the relevant part of the looks like this:
Note that you have also turned the Pen, Size, and Point objects into member fields, This is more efficient than creating a new Pen every time you need to draw anything, as you have been doing so far.
The result of running this example looks like Figure 33-6.
You can see a problem instantly. The shapes do not fit in your 300 x 300 pixel drawing area.
Normally, if a document is too large to display, an application will add scroll bars to let you scroll the window and look at a chosen part of it, This is another area in which if you were building Windows Forms using standard controls, you would simply allow the .NET runtime and the base classes to handle everything for you, If your form has various controls attached to it, then the Form instance will normally know where these controls are, and it will therefore know if its window becomes so small that scroll bars are necessary. The Form instance automatically adds the scroll bars for you, It is also able to draw correctly the portion of the screen you have scrolled to. In that case, there is nothing you need to do in your code, In this chapter, however, you are taking responsibility for drawing to the screen, Therefore, you need to help the Form instance out when it comes to scrolling.
Adding the scroll bars is actually very easy. The Form can still handle all that for you because the form does not know how big an area you will want to draw in, (The reason it didn’t do so in the earlier Big Shapes example is that windows does not know they are needed.) You need to determine whether the size of a rectangle the streches from the top-left comer of the document (or equivalently, the top-left corner of the client area before you have done any scrolling) is big enough to contain the entire document, this area is called the document area, As shown in Figure 33-7, the document area for this example is (250 x 350) pixels.
It is easy to tell the form how big the document is. You use the relevant property, Form, AutoScrollMinSize, Therefore, you can add this code to either the InitializeComponent () method or the Forml constructor:
Alternatively, the AutoScrollMinSize property can be set using the Visual Studio 2008 properties window, Note that to gain access to the Size class, you need to add the following using statement:
using System. Drawing;
Setting the minimum size at application startup and leaving it thereafter is fine in this particular example because you know that is how big the screen area will always be, Your document never changes size while this particular application is running. Keep in mind, however, that if your application does things like display contents of files or something else for which the area of the screen might change, you will need to set this property at other times (and in that case you will have to sort out the code manually the Visual Studio 2008 properties window can help you only with the initial value that a property has when the.form is constructed).
Setting AutoScrollMinSize is a start, but it is not yet quite enough. Figure 33-8 shows what the sample application looks like now – initially you get the screen that correctly
Notice that not only has the form correctly set the scroll bars, but also it has correctly sized them to indicate what proportion of the document is currently displayed. You can try resizing the window while the sample is running – you will find the scroll bars respond properly, and even disappear if you make the window big enough so that they are no longer needed.
However, look at what happens when you actually use one of the scroll bars to scroll down a bit (see Figure 33-9). Clearly, something has gone wrong!
What’s wrong is that you haven’t taken into account the position of the scroll bars in the code in your On Paint () override, You can see this very clearly if you force the window to repaint itself completely by minimizing and restoring it (see Figure 33-10).
The shapes have been painted, just as before, with the top-left comer of the rectangle nestled into the top-left comer of the client area – as if you hadn’t moved the scroll bars at all.
Before you see how to correct this problem, take a closer look at precisely what is happening in these screenshots.
Start with the Big Shapes sample, shown in Figure 33-8. In this example, the entire window has just been repainted, Reviewing your code, you learn that it instructs the graphics instance to draw a rectangle with top-left coordinates (0,0)- relative to the top-left comer of the client area of the window – which is what has been drawn. The problem is that the graphics instance by default interprets coordinates as relative to the client window and is unaware of the scroll bars. Your code, as yet, does not attempt to adjust the coordinates for the scroll bar positions. The same goes for the ellipse.
Now, you can tackle the screenshot in Figure 33-9. After you scroll down, you notice that the top half of the window looks fine because it was drawn when the application first started up, When you scroll windows, Windows does not ask the application to redraw what was already on the screen.
Windows is smart enough to determine which currently displayed bits can be smoothly moved around to match where the scroll bars now are located, This is a much more efficient process because it may be able to use some hardware. acceleration to do that, too The bit in this screenshot that is wrong is the bottom third of the window. This part of the window was not drawn when the application first appeared because before you started scrolling, it was outside the client area, This means that Windows asks your Big Shapes application to draw this area. It will raise a Paint event passing in just this area as the clipping rectangle. And that is exactly what your on Paint () override has done.
One way to look at the problem is that you are, at the moment, expressing your coordinates relative to the top-left comer of the start of the document – you need to convert them to express them relative to the top-left comer of the client area instead (see Figure 33-11).
To make the diagram clearer, the document is actually extended further downward and to the right, beyond the boundaries of the screen, but this does not change our reasoning. It also assumes a small horizontal scroll as well as a vertical one.
In Figure 33-11, the thin rectangles mark the borders of the screen area and of the entire document, The thick lines mark the rectangle and ellipse that you are trying to draw. P marks some arbitrary point that you are drawing and that is being used as an example. When calling the drawing methods, the graphics instance was supplied with the vector from point B to (say) point P, expressed as a Point instance, You actually need to give it the vector from point A to point P.
The problem is that you do not know what the vector from A to P is. You know what Bto P is; that is just the coordinates of P relative to the top-left comer of the document – the position where you want to 0 draw point P in the document. You also know that the vector from B to A is just the amount you have scrolled by. This is stored in a property of the Form class called AutoScrollPosition, However, you do
not know the vector from A to P.
To solve this problem, you subtract the one vector from the other. Say, for example, to get from B to P you move 150 pixels across and 200 pixels down, whereas to get from B to A you move 10 pixels across and 57 pixels down. That means to get from A to P you have to move 140 (150 minus 10) pixels across and 143 (200 minus 57) pixels down. To make it even simpler, the Graphics class actually implements a method that will do these calculations for you, It is called Translate Transform ( You
pass it the horizontal and vertical coordinates that say where the top left of the client area is relative to the top-left comer of the document (your AutoScrollPosition property, that is, the vector from B to A in the diagram), The Graphics device will now work out all its coordinates, taking into account wherethe client area is relative to the document.
If we translate this long explanation into code, all you typically need to do is add the following line to your drawing code:
dc.TranslateTransform (this.AutoScrollPosition.X. this.AutoScrollPosition.Y;
However, in this example, it is a little more complicated because you are also separately testing whether you need to do any drawing by looking at the clipping region. You need to adjust this test to take the scroll position into account, too, When you have done that, the full drawing code for the sample looks like this:
Now you have your scroll code working perfectly. You can at last obtain a correctly scrolled screenshot (see Figure 33-12).