Today’s digital cameras take pictures with much higher resolution than many computer screens. My Canon PowerShot SD800 IS camera takes pictures at 3072 x 2204 resolution.
One of my laptops died recently, and I noticed that local laptop retailers have machines with 1280 X 1024 resolution. I much prefer a higher resolution display, so I ordered a customizable Dell Inspiron 1525 with 1680 x 1050.
(I’ve been ordering computers from Dell for over 20 years, back in the days when it was called PC’s Limited. Why does Dell distinguish between business/government/home laptops?)
I was playing around with some photos using a PictureBox control, and I wanted to add a feature that would allow click/zoom using the mouse wheel to designate a point to magnify.
It was pretty easy to create my own class MyPictureBox which inherits from PictureBox and handles the MouseWheel and zooming.
Below are C# and VB versions. If I get enough requests, maybe I’ll make a Fox version (although I like this Fox version of zooming: Enable crop and zooming in on your digital photograph display form)
Start Visual Studio 2008 (I think these should work in VS2005)
File->New->Project->VB/C#->Windows Application.
View->Code, then paste the VB/C# code below, hit F5
Move the mouse to designate a zoom anchor point, then mouse wheel to zoom in/out
If you switch back to the form designer, the ToolBox has the MyPictureBox control on it, which you can drag/drop onto a form.
If you already have your own form that uses a PictureBox or several, you can avoid manually changing all the instances by carefully editing the Form1.Designer.vb file to replace the type with MyPictureBox (make a backup first).
As an exercise, try extending this feature by adding the ability to change the anchor point while zoomed or pan the zoomed picture.
Some VB/C# coding issues:
· semicolons
· capitalization
· intermediate arithmetic rounding results
· event handling
See also:
Enable crop and zooming in on your digital photograph display form
Create your own media browser: Display your pictures, music, movies in a XAML tooltip
<VB Code>
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.Left = 0
Me.Top = 0
Me.Size = My.Computer.Screen.WorkingArea.Size
Dim oPict = New MyPictureBox
oPict.Size = Me.Size
oPict.SizeMode = PictureBoxSizeMode.StretchImage
oPict.Image = New Bitmap("d:\kids.jpg") ' path to some picture
Me.Controls.Add(oPict)
Me.ActiveControl = oPict
End Sub
End Class
Public Class MyPictureBox
Inherits PictureBox
Private zmLevel As Integer = 1
Private zmPt As Point
Overloads Property Image() As Image ' we want to hook when client's set the image to reset the zoom level to unzoomed
Get
Return MyBase.Image
End Get
Set(ByVal value As Image)
zmLevel = 1 ' reinit
MyBase.Image = value
End Set
End Property
Protected Overrides Sub OnPaint(ByVal pe As System.Windows.Forms.PaintEventArgs)
'MyBase.OnPaint(pe) ' don't call baseclass to paint
If Me.Image IsNot Nothing Then
Dim loc As Point
Dim sz As Size
If zmLevel <> 1 Then
sz = New Size(Me.Image.Width / zmLevel, Me.Image.Height / zmLevel)
' center on zmPt
loc = New Point(Me.Image.Width * (zmPt.X / Me.ClientRectangle.Width) - sz.Width / 2, _
Me.Image.Height * (zmPt.Y / Me.ClientRectangle.Height) - sz.Height / 2) '
Else
loc = New Point(0, 0) ' no zoom: we want the entire source picture
sz = Me.Image.Size
End If
Dim rectSrc = New Rectangle(loc, sz)
' now draw the rect of the source picture in the entire client rect of MyPictureBox
pe.Graphics.DrawImage(Me.Image, Me.ClientRectangle, rectSrc, GraphicsUnit.Pixel)
End If
End Sub
Sub PictureBox_MouseWheel(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Me.MouseWheel
If Me.zmLevel = 1 Then ' can only anchor when unzoomed
Me.zmPt = New Point(e.X, e.Y)
End If
If e.Delta > 0 Then
If zmLevel < 20 Then
zmLevel += 1
End If
Else
If e.Delta < 1 Then
If zmLevel > 1 Then
zmLevel -= 1
End If
End If
End If
Me.Invalidate() ' queue msg to repaint
End Sub
End Class
</VB Code>
<C# Code>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Left = 0;
this.Top = 0;
this.Size = Screen.PrimaryScreen.WorkingArea.Size;
var oPict = new MyPictureBox();
oPict.Size = this.Size;
oPict.SizeMode = PictureBoxSizeMode.StretchImage;
oPict.Image = new Bitmap("d:\\kids.jpg");
this.Controls.Add(oPict);
this.ActiveControl = oPict;
}
}
}
public class MyPictureBox : PictureBox
{
private int zmLevel = 1;
private Point zmPt;
public MyPictureBox()
{
this.MouseWheel += new MouseEventHandler(MyPictureBox_MouseWheel);
}
void MyPictureBox_MouseWheel(object sender, MouseEventArgs e)
{
if (this.zmLevel == 1)
{
this.zmPt = new Point(e.X, e.Y);
}
if (e.Delta > 0)
{
if (zmLevel < 20)
{
zmLevel += 1;
}
}
else
{
if (e.Delta < 1)
{
if (zmLevel > 1)
{
zmLevel -= 1;
}
}
}
this.Invalidate();
}
new public Image Image // overrides
{
get
{
return base.Image;
}
set
{
zmLevel = 1;
base.Image = value;
}
}
protected override void OnPaint(PaintEventArgs pe)
{
//base.OnPaint(pe);
if (this.Image != null)
{
Point loc;
Size sz;
if (zmLevel != 1)
{
sz = new Size(this.Image.Width / zmLevel, this.Image.Height / zmLevel);
// center on zmPt. Casts are needed so integer divide doesn't occur (intermediate double result)
loc = new Point((int)(this.Image.Width * (zmPt.X / (double)this.ClientRectangle.Width)) - sz.Width / 2,
(int)(this.Image.Height * (zmPt.Y / (double)this.ClientRectangle.Height)) - sz.Height / 2);
}
else
{
loc = new Point(0, 0);
sz = this.Image.Size;
}
Rectangle rectSrc = new Rectangle(loc, sz);
// now draw the rect of the source picture in the entire client rect of MyPictureBox
pe.Graphics.DrawImage(this.Image, this.ClientRectangle, rectSrc, GraphicsUnit.Pixel);
}
}
}
</C# Code>