|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Introduction
BackgroundApplications for image displaying need to show different sizes of pictures in a limited form area. The size of pictures to be shown is large usually, for example, the size of a digital camera photo with 300 Meg pixels will be about 2000*1500 pixels. Users would want to see the whole image, or a properly zoomed out image. When I was developing a free album manager application (QAlbum.NET), a scrollable picture box control was needed, and I developed Using the controlUsing // set an image to show
this.scalablePictureBox.Picture = image;
// set pictureBox control of scalablePictureBox
// as active control of the form
// for ScalablePictureBox to receive mouse events
this.ActiveControl = this.scalablePictureBox.PictureBox;
StructureThe
How it works
/// <summary>
/// Resize picture box on resize event
/// </summary>
private void OnResize(object sender, System.EventArgs e)
{
ScalePictureBoxToFit();
RefreshContextMenuStrip();
}
/// <summary>
/// Scale picture box to fit to current control size and image size
/// </summary>
private void ScalePictureBoxToFit()
{
if (this.Picture == null)
{
// set size of picture box the same as client size
...
}
else if (this.pictureBoxSizeMode == PictureBoxSizeMode.Zoom ||
(this.Picture.Width <= this.ClientSize.Width &&
this.Picture.Height <= this.ClientSize.Height))
{
// set size of picture box as not bigger
// than client size according to current image
...
}
else
{
// set size of picture box according
// to current scale percent selected
...
this.AutoScroll = true; // let the control scrollable
}
// set cursor for picture box
SetCursor4PictureBox();
this.pictureBox.Invalidate();
}
The zooming context menu should be recreated when an image is loaded, or when the client size changes. And the /// <summary>
/// Refresh context menu strip according to current image
/// </summary>
private void RefreshContextMenuStrip()
{
int minScalePercent = GetMinScalePercent();
if (minScalePercent == MAX_SCALE_PERCENT)
{
// no need popup context menu
this.ContextMenuStrip = null;
}
else
{
this.pictureBoxContextMenuStrip.SuspendLayout();
this.pictureBoxContextMenuStrip.Items.Clear();
// add show whole menu item
...
// add scale to fit width menu item
...
// add other scale menu items
for (int scale = minScalePercent / 10 * 10 + 10;
scale <= MAX_SCALE_PERCENT; scale += 10)
{
...
}
this.pictureBoxContextMenuStrip.ResumeLayout();
this.ContextMenuStrip = this.pictureBoxContextMenuStrip;
// set last selected menu item checked
CheckLastSelectedMenuItem();
}
SetCursor4PictureBox(); // update cursor
}
Zoom cursors of /// <summary>
/// Load colored cursor handle from a file
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
[DllImport("user32.dll",
EntryPoint = "LoadCursorFromFileW",
CharSet = CharSet.Unicode)]
static public extern IntPtr LoadCursorFromFile(string fileName);
/// <summary>
/// Create cursor from embedded cursor
/// </summary>
/// <param name="cursorResourceName">embedded cursor resource name</param>
/// <returns>cursor</returns>
public static Cursor CreateCursorFromFile(String cursorResourceName)
{
// read cursor resource binary data
Stream inputStream = GetEmbeddedResourceStream(cursorResourceName)
byte[] buffer = new byte[inputStream.Length];
inputStream.Read(buffer, 0, buffer.Length);
inputStream.Close();
// create temporary cursor file
String tmpFileName = System.IO.Path.GetRandomFileName();
FileInfo tempFileInfo = new FileInfo(tmpFileName);
FileStream outputStream = tempFileInfo.Create();
outputStream.Write(buffer, 0, buffer.Length);
outputStream.Close();
// create cursor
IntPtr cursorHandle = LoadCursorFromFile(tmpFileName);
Cursor cursor = new Cursor(cursorHandle);
tempFileInfo.Delete(); // delete temporary cursor file
return cursor;
}
/// <summary>
/// Draw a reversible rectangle
/// </summary>
/// <param name="rect">rectangle to be drawn</param>
private void DrawReversibleRect(Rectangle rect)
{
// Convert the location of rectangle to screen coordinates.
rect.Location = PointToScreen(rect.Location);
// Draw the reversible frame.
ControlPaint.DrawReversibleFrame(rect, Color.Red, FrameStyle.Dashed);
}
/// begin to drag picture tracker control
private void pictureTracker_MouseDown(object sender, MouseEventArgs e)
{
// Make a note that we are dragging picture tracker control
isDraggingPictureTracker = true;
// Store the last mouse poit for this rubber-band rectangle.
// draw initial dragging rectangle
draggingRectangle = this.pictureTracker.Bounds;
DrawReversibleRect(draggingRectangle);
}
/// dragging picture tracker control in mouse dragging mode
private void pictureTracker_MouseMove(object sender, MouseEventArgs e)
{
if (isDraggingPictureTracker)
{
// caculating next candidate dragging rectangle
// saving current mouse position to be used for next dragging
// dragging picture tracker only when the candidate dragging rectangle
// is within this ScalablePictureBox control
if (this.ClientRectangle.Contains(newPictureTrackerArea))
{
// removing previous rubber-band frame
DrawReversibleRect(draggingRectangle);
// updating dragging rectangle
draggingRectangle = newPictureTrackerArea;
// drawing new rubber-band frame
DrawReversibleRect(draggingRectangle);
}
}
}
/// end dragging picture tracker control
private void pictureTracker_MouseUp(object sender, MouseEventArgs e)
{
if (isDraggingPictureTracker)
{
isDraggingPictureTracker = false;
// erase dragging rectangle
DrawReversibleRect(draggingRectangle);
// move the picture tracker control to the new position
this.pictureTracker.Location = draggingRectangle.Location;
}
}
ImprovementsThe maximum zoom-in rate of the History
|
||||||||||||||||||||||