65.9K
CodeProject 正在变化。 阅读更多。
Home

TouchPictureBox,用手指滑动图片!

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (10投票s)

2008 年 10 月 15 日

CDDL

5分钟阅读

viewsIcon

51904

downloadIcon

747

在小屏幕上查看图片时,放弃传统的滚动条。

Demo Project, main form Demo Project, TouchPictureBox form

引言

这个想法是在开发一个智能设备应用程序时产生的,该应用程序需要显示比屏幕更大的图片。我发现滚动条并不容易使用,即使在如今“触摸”体验如此流行的时代!所以我决定构建一个新的控件,让用户可以用手指浏览图片。之后,我添加了缩放功能,以便用户可以轻松地看到整个图片,然后对其进行浏览。

Using the Code

源代码项目将构建一个包含该控件的 DLL 文件。然后,您就可以将其添加到 Visual Studio 工具箱中,然后像普通的 PictureBox 一样使用它。如果您打开 zip 文件中的解决方案,进行构建并启动项目,您将获得一个示例应用程序,可以将其上传到您的 Pocket PC 设备上进行实时测试!使用底部的“实时演示”菜单,通过嵌入的图片(这是 Windows Vista 的标准壁纸)来测试该控件,或者您可以浏览设备上的其他图片,然后点击“显示”按钮来使用您自己的图片测试该控件!

控件属性

  • CropLocation:显示图片部分的左上角坐标 Point。此属性允许您获取实际位置,或者在设计时设置一个默认起始位置,或者在代码中设置以强制滚动。该点将在滚动时更新。为了更好地理解,请看下图。

    CropLocation

  • Picture:显示的图片 Bitmap。就像传统的 Image 属性一样使用它,可以在设计时或运行时使用!
  • StopEdges:一个 boolean 值,用于确定滚动是否会在到达图片边缘时停止。这些图片说明了该行为。

    StopEdges = true StopEdges = false

  • Zoom:一个 Int32 值,表示当前的缩放值,以百分比表示。“100”表示 100%,或者您更喜欢,“实际大小”!
  • ZoomMin:一个 Int32 值,表示允许的最小缩放值。
  • ZoomMax:一个 Int32 值,表示允许的最大缩放值。
  • ZoomStep:一个 Int32 值,表示缩放步长。当您在运行时调用 ZoomIn()ZoomOut() 方法时,Zoom 值将以 ZoomStep 为步长进行更新。例如,值为 25 将获得 25、50、75、100、125、150 等缩放值。

让我们深入代码

现在,我们将看一下最重要的代码部分:实现实际功能的三个事件。它们是 OnMouseDownOnMouseMoveOnPaint。事实上,我们想要捕获用户触摸屏幕的时刻并保留坐标。然后,当用户在保持触笔或手指按下的同时移动时,我们希望滚动图片。

我们有一个初步的解决方案:记住第一次触摸的坐标,然后始终使用这个记忆和当前的 MouseMove 坐标来计算新的图片坐标。但这有点复杂。所以我使用的解决方案将在 MouseMove 时计算新的图片坐标,然后将新的鼠标(触笔或手指)坐标保留为“第一次”坐标。

protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
	// Left button clicked, save click position
	_iFirstTapX = e.X;
	_iFirstTapY = e.Y;
    }
}

protected override void OnMouseMove(MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
	// Displace the CropLocation by the move size
	_pCropLocation.X -= (e.X - _iFirstTapX);
	_pCropLocation.Y -= (e.Y - _iFirstTapY);

	// Replace picture to avoid going further than the edges
	Replace();

	// Picture has moved, save the new click position for next move
	_iFirstTapX = e.X;
	_iFirstTapY = e.Y;
	this.Invalidate();
    }
}

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
    Graphics gxOff;	         // Offscreen graphics
            
    if (_bOffscreen == null) // Bitmap for doublebuffering
	_bOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);

    gxOff = Graphics.FromImage(_bOffscreen);
    gxOff.Clear(this.BackColor);
  
    if (_bPicture != null)
    {
	Rectangle rDst = new Rectangle
			(0, 0, ClientSize.Width, ClientSize.Height);
	Rectangle rSrc = new Rectangle(_pCropLocation.X, _pCropLocation.Y, 
			ClientSize.Width, ClientSize.Height);
	gxOff.DrawImage(_bZoomedPicture, rDst, rSrc, GraphicsUnit.Pixel);
    }

    // Draw from the memory bitmap
    e.Graphics.DrawImage(_bOffscreen, 0, 0);

    base.OnPaint(e);
}

_iFirstTapX_iFirstTapY 将保存第一次触摸的坐标。_pCropLocation 是一个 Point,定义了需要显示的图片部分的左上角坐标。我称之为整个图片的裁剪。

然后您会看到对 Replace() 方法的调用。如果位移超过图片边缘,它将进行检查,如果 StopEdges 属性设置为 true,它将把位移复原。

当控件需要重绘时,总会调用 this.Invalidate()。所以我们来到了 OnPaint 事件。正如您所见,它将使用双缓冲来防止闪烁。创建一个与控件大小相同的临时 bitmap,然后我们检查是否设置了图片。如果为 true,我们将获取原始图片中需要显示的矩形部分,并将其绘制到临时 bitmap 中。

但是等等!这个 _bZoomedPicture 是什么?嗯,为了在缩放模式下实现轻松滑动,该控件会在内存中创建缩放后的图片,这将是绘制的源图片。因此,当您更改 Picture 属性、Zoom 属性,或使用 ZoomIn()ZoomOut() 方法时,我们将调用 CreateZoomedPicture() 来计算该图片的新版本。代码如下:

private void CreateZoomedPicture()
{
    // Draw zoomed version of the picture. 
    // In fact this version will be used for control drawing.
    if (_bPicture != null)
    {
	// If zoom value is 100, just take original picture !
	if (_iZoom == 100)
	    _bZoomedPicture = _bPicture;
         else
         {
	    Graphics gx;
	    _bZoomedPicture = new Bitmap((int)((double)_bPicture.Width * _dZoom), 
				(int)((double)_bPicture.Height * _dZoom));

	    gx = Graphics.FromImage(_bZoomedPicture);
	    gx.Clear(this.BackColor);

	    Rectangle rDst = new Rectangle
			(0, 0, _bZoomedPicture.Width, _bZoomedPicture.Height);
	    Rectangle rSrc = new Rectangle
			(0, 0, _bPicture.Width, _bPicture.Height);
	    gx.DrawImage(_bPicture, rDst, rSrc, GraphicsUnit.Pixel);
         }
    }
}

在这里,我们只是利用了 .NET CompactFramework 的功能:将源 bitmap 绘制到更大或更小的矩形中。图片将被重采样,而无需担心如何做到这一点!

使用此类

您可以在演示项目中看到,您可以创建一个填充有该控件的 Windows 窗体,以及两个用于设备的两个软按钮的“放大”和“缩小”菜单,然后进行全屏导航。每个按钮的代码只会简单地调用 touchPictureBox1.ZoomIn()touchPictureBox1.ZoomOut()!但您也可以将其用作窗体中的小型控件,用于小范围导航。

随附的项目是一个 Visual Studio 2008 项目,但将其在 Visual Studio 2005 中运行应该也很容易,因为它使用了 .NET CF 2.0。您还将获得一个小图标,以便在工具箱中良好地表示,以及 DesignTimeAttributes.xmta 文件,以获得良好的属性行为和描述!

此类将在 Windows Mobile 5 和 Windows Mobile 6 上运行,但您应该很容易地将其用于桌面应用程序进行编译,这样用户就可以使用鼠标滑动,或者在 Tablet PC 上使用他们的触笔进行滑动!

历史

  • 2008 年 10 月 15 日:第一个版本
© . All rights reserved.