Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Manning - Windows Forms Programming With CSharp.pdf
Скачиваний:
72
Добавлен:
24.05.2014
Размер:
14.98 Mб
Скачать

Set the version number of the MyPhotoAlbum library to 7.2.

IMPLEMENT A SCALETOFIT METHOD IN THE PHOTOGRAPH CLASS

 

Action

Result

 

 

 

1

In the Photograph.cs file, add the

public Rectangle ScaleToFit

 

ScaleToFit method.

(Rectangle targetArea)

 

 

{

 

 

 

2

Define a Rectangle to hold the

Rectangle result

 

calculated result.

= new Rectangle(targetArea.Location,

 

 

targetArea.Size);

 

 

 

3

Determine whether the photograph

// Determine best fit: width or height

 

will fit best horizontally or vertically.

if (result.Height * Image.Width

 

 

> result.Width * Image.Height)

 

 

{

 

 

 

4

If horizontally, determine the

// Final width should match target,

 

resulting height and center the

// determine and center height

 

rectangle in the available space.

result.Height = result.Width

 

* Image.Height / Image.Width;

 

 

 

 

result.Y += (targetArea.Height

 

 

- result.Height) / 2;

 

 

}

 

 

 

5

If vertically, determine the resulting

else

 

width and center the rectangle in

{

 

the available space.

// Final height should match target,

 

// determine and center width

 

 

 

 

result.Width = result.Height

 

 

* Image.Width / Image.Height;

 

 

result.X += (targetArea.Width

 

 

- result.Width) / 2;

 

 

}

 

 

 

6

Return the calculated result.

return result;

 

 

}

 

 

 

Since this algorithm is a bit off-topic from Windows Forms development, we will not discuss it in much detail. This gives us a mechanism for scaling our image to the proper display size, and accounts for both horizontal and vertical images. The method returns a Rectangle object containing both a location and a size for the new image. That is, this method does not just provide the final size for our displayed image; it also provides the location where it should appear within the target rectangle.

With this in hand, let’s turn back to our MyPhotos application. To implement our Scale to Fit menu, we need to add the menu item itself, the menu-handling logic, and the appropriate drawing code. We will begin with the menu option.

IMAGE DRAWING

207

 

 

 

ADD SCALETOFIT MENU ITEM

 

 

 

 

 

 

 

 

Action

Result

 

 

 

 

 

 

7

In the MainForm.cs [Design] window,

 

 

add a Scale To Fit menu to the top of

 

 

the View menu..

 

 

 

 

 

Settings

 

 

 

 

 

 

 

 

 

Property

Value

 

 

 

(Name)

menuScale

 

 

 

Text

&Scale to Fit

 

 

 

 

 

 

 

8

Add the menuImage_ChildClick

The handler is registered with the Click event

 

method as the Click event handler for

associated with the menu.

 

the menuScale menu item.

 

 

 

 

 

 

 

The code generated by these steps is similar to the menu code generated in chapter 3 and elsewhere. In particular, note that the Index property settings for these menus are adjusted in the InitializeComponent method to reflect the insertion of the new item at the first location.

menuScale.Index = 0;

menuStretch.Index = 1;

menuActual.Index = 2;

Since the DisplayMode enumeration must match our menu, we need to update the values appropriately.

UPDATE DISPLAYMODE ENUMERATION

 

Action

Result

 

 

 

9

Locate the DisplayMode definition in

private enum DisplayMode

 

the MainForm.cs source file.

{

 

 

 

10

Add a ScaleToFit value and adjust

ScaleToFit = 0,

 

the settings to match the Image

StretchToFit = 1,

 

submenu.

ActualSize = 2

 

}

 

 

 

 

 

11

Set the default value for the

private DisplayMode _selectedMode

 

_selectedMode field to the new

= DisplayMode.ScaleToFit;

 

setting.

 

 

 

 

We also need to check each place in the code where this enumerator is used. If you do a search, you will discover the _selectedMode field in menuImage_Popup, menuImage_ChildClick, and OnPaint. The popup event is not affected by this change, but the click handler requires a change to its switch block.

208

CHAPTER 7 DRAWING AND SCROLLING

UPDATE MENUIMAGE_CHILDCLICK EVENT HANDLER

 

Action

Result

 

 

 

12

Locate the

protected void menuImage_ChildClick

 

menuImage_ChildClick method in

(object sender, System.EventArgs e)

 

the MainForm.cs source file.

{

 

. . .

 

 

 

 

 

13

Add the new display mode to the

switch (_selectedMode)

 

switch statement, and make it the

{

 

default.

default:

 

case DisplayMode.ScaleToFit:

 

 

 

 

// Scale image to fit display area

 

 

this.Invalidate();

 

 

break;

 

 

case DisplayMode.StretchToFit:

 

 

. . .

 

 

}

 

 

. . .

 

 

}

 

 

 

The final change required to properly scale our image is in the OnPaint method. Here we simply draw the image into the Rectangle determined by our Photograph.ScaleToFit method.

 

 

UPDATE ONPAINT METHOD

 

 

 

 

Action

Result

 

 

 

14

Locate the OnPaint

protected override void OnPaint(PaintEventArgs e)

 

method in the

{

 

MainForm.cs source file.

. . .

 

 

 

 

 

15

Add the new display mode

switch (_selectedMode)

 

to the switch statement,

{

 

and make it the default.

default:

 

case DisplayMode.ScaleToFit:

 

 

 

 

// Preserve aspect ratio of image

 

 

g.DrawImage(photo.Image,

 

 

photo.ScaleToFit(DisplayRectangle));

 

 

break;

 

 

case DisplayMode.StretchToFit:

 

 

. . .

 

 

}

 

 

. . .

 

 

}

 

 

 

There you have it. The Scale to Fit display mode is very similar to the Stretch to Fit display mode. Both fit the image into the display area, and both draw the image into a rectangle. The difference is the rectangle into which they draw. Compile your application to verify that the image scales properly. It may be a bit hard to determine if this is working properly since a window resize does not cause the image to be redrawn. Let’s address this problem next.

IMAGE DRAWING

209

7.2.5REPAINTING WHEN THE FORM IS RESIZED

Now that we are drawing directly on the form, we need to redraw our image whenever the form is resized. The PictureBox control used in prior chapters handled this issue automatically for us.

There is in fact a Resize event associated with controls. This event occurs when

a control, including a Form object, is resized. Handling this event would allow us to invalidate the window whenever the display mode is ScaleToFit or StretchToFit. Since our MainForm class is derived from Form, we could even go directly to the protected OnResize method that raises this event. This would force our OnPaint method to be called and the window would update appropriately. A fine idea, but there is another way.

.NET Table 7.4 ControlStyles enumeration

The ControlStyles enumeration specifies a set of values related to the interaction of a control with the Windows desktop. These styles define how low-level Windows messages are processed by the control when a user interacts with it in various ways. This enumeration is part of the System.Windows.Forms namespace.

The values in this enumeration can be combined using the bitwise “or” operator. The protected GetStyle and SetStyle methods in the Control class can be used to modify these settings for a control.

 

DoubleBuffer

Whether to perform drawing in a buffer and

 

 

output the result to the screen after it

 

 

completes. This prevents flicker caused by

 

 

redrawing the control.

 

FixedHeight

Whether the control has a fixed height.

 

FixedWidth

Whether the control has a fixed width.

 

ResizeRedraw

Whether the control is completely redrawn

 

 

when it is resized.

 

Selectable

Whether the control can get the focus.

Enumeration

StandardClick

Whether OnClick is called when the control is

Values

 

single-clicked. Note that the control may still call

 

 

 

 

OnClick directly.

 

StandardDoubleClick

Whether OnDoubleClick is called when the

 

 

control is double clicked. Note that the control

 

 

may still call OnDoubleClick directly.

 

UserMouse

Whether the control does its own mouse

 

 

processing. If so, then mouse messages are not

 

 

passed to the control.a

 

UserPaint

Whether the control paints itself. If so, then paint

 

 

messages are not passed to the control.

 

 

 

a. Actually, the messages here are not passed to the underlying NativeWindow object, but you can think of it as the control itself. For UserMouse, this affects the WM_MOUSEDOWN, WM_MOUSEMOVE, and WM_MOUSEUP messages. For UserPaint, this affects the WM_PAINT and WM_ERASEBKGND messages.

210

CHAPTER 7 DRAWING AND SCROLLING