可点击拖动、缩放和复制 - PictureBox






4.11/5 (16投票s)
2006年3月7日
4分钟阅读

151061

8883
一个具有内置的点击拖动、缩放和复制功能的 PictureBox。
引言
该控件最初是为了模仿我们公司正在使用的一些查看和处理医疗理赔的现有软件而开发的。最初的计划是开发一个 PictureBox
,允许用户在图像上绘制一个框,然后放大该点。但很快就发现这并非易事。
变更
PictureBoxEx
仍使用 .NET 1.1 来使其与当前和未来的项目兼容,但已进行了完全重写。
该控件是一个全新的控件,它不再基于 PictureBox
,而是基于 ScrollableControl
。做出这一改变是创建既灵活又快速的控件所必需的。在绘制拖动窗口时,旧控件构建图像和刷新速度很慢,而新控件则非常流畅。
新版本还增加了向图像添加注释的功能。这些注释可以着色,可以调整大小以匹配图像的当前缩放比例,最重要的是它们是 XmlSerializable
的,因此可以保存到文件并在以后检索。
此新控件还增加了滚动功能。该控件现在可以通过按键和鼠标进行垂直和水平滚动。滚动鼠标滚轮会垂直滚动图像,但如果按住 Ctrl 键滚动鼠标滚轮,则可以水平滚动图像。可以使用箭头键以及 Home、End、PageUp、PageDown 键滚动图像。由于该控件无法接收和保持直接焦点,因此焦点可能会在同一窗体上的控件之间转移。因此,要使用键盘滚动,最好将此 PictureBoxEx
设置为窗体上的唯一控件。(如果有人知道如何改进此限制,我将非常乐意听到。)
此外,还可以通过按住 Shift 键滚动鼠标滚轮来更改控件的当前缩放比例。
特点
- 点击并拖动窗口进行缩放或复制
- 无父控件设计 (新)
- 注释 (包含自定义光标) (新)
- 诊断模式 (新)
- 使用鼠标滚轮缩放和滚动 (新)
- 使用按键滚动 (在窗体上是唯一控件时效果最佳) (新)
自定义属性
控件的大部分自定义属性都可以通过设计器进行访问。
AllowDrag
:指示是否允许用户进行拖动和复制或缩放。CurrentZoom
:控制PictureBox
的当前缩放比例。DefaultZoom
:控制PictureBox
的默认缩放比例。DiagnosticMode
:设置为 true 以显示诊断信息。DoubleClickRestore
:控制PictureBox
双击时将图像恢复到默认缩放比例的功能。DragOptions
:控制PictureBox
的拖动选项。(复制、缩放或提示)DragWindowColor
:控制PictureBox
的拖动窗口颜色。DragWindowMinimum
:控制PictureBox
的最小可调用拖动窗口大小。DragWindowPattern
:绘制拖动窗口时控件使用的虚线图案。DrawMode
:控制调整图像大小时应用的图像滤镜。(InterpolationMode
)MaximumZoom
:控制允许的最大缩放比例。MinimumZoom
:控制允许的最小缩放比例。
代码
以下代码由 GenerateResizedImage
用于从设置控件的 Image
属性时创建的备份生成调整大小后的图像。调整大小后的图像的创建过程与当前缩放比例无关,即使缩放比例为 1。之所以仍然生成,是因为控件无法处理具有索引像素格式的图像。因此,直接转换图像会更简单。
int resizedWidth = Convert.ToInt32(backup.Width * _currentZoom);
int resizedHeight = Convert.ToInt32(backup.Height * _currentZoom);
resized = new Bitmap(resizedWidth, resizedHeight);
// Drag the backup image onto the resized image
using (Graphics g = Graphics.FromImage(resized))
{
g.InterpolationMode = (_currentZoom < 1F) ?
_drawMode : InterpolationMode.Default;
Rectangle srceRect =
new Rectangle(0, 0, backup.Width, backup.Height);
Rectangle destRect =
new Rectangle(0, 0, resized.Width, resized.Height);
g.DrawImage(backup, destRect, srceRect, GraphicsUnit.Pixel);
// Add any annotations to the resized image
DrawAnnotations(g);
}
确定缩放发生的位置需要大量的数学计算。第一步是补偿当前的缩放比例和当前的滚动位置。然后,需要确定拖动窗口的哪个部分相对于控件的大小比例更大,并放大该部分以填充控件,同时使剩余部分居中。
// The zoom window will never be proportional to the container, so one
// side will get filled while the other gets centered. The larger % will
// determine which gets filled, and which gets centered
float xRatio = (float)Width / (float)dragWindowSave.Width;
float yRatio = (float)Height / (float)dragWindowSave.Height;
float largerRatio;
int xAdjust = 0;
int yAdjust = 0;
largerRatio = (xRatio < yRatio) ? xRatio : yRatio;
// The cumulative zoom cannot exceed the maximum zoom;
if ((largerRatio * _currentZoom) > _maximumZoom)
largerRatio = _maximumZoom / _currentZoom;
if (dragWindowSave.Width * largerRatio > Width)
largerRatio = (float)Width / (float)dragWindowSave.Width;
if (dragWindowSave.Height * largerRatio > Height)
largerRatio = (float)Height / (float)dragWindowSave.Height;
yAdjust = Convert.ToInt32(
((float)Height - (float)dragWindowSave.Height * largerRatio) / 2F);
xAdjust = Convert.ToInt32(
((float)Width - (float)dragWindowSave.Width * largerRatio) / 2F);
int xScrollPos = Math.Max(Convert.ToInt32(((float)-AutoScrollPosition.X +
(float)dragWindowSave.X) * largerRatio) - xAdjust, 0);
int yScrollPos = Math.Max(Convert.ToInt32(((float)-AutoScrollPosition.Y +
(float)dragWindowSave.Y) * largerRatio) - yAdjust, 0);
CurrentZoom *= largerRatio;
使用控件
该控件非常类似于 PictureBox
。实际上需要做的就是将控件添加到窗体并设置其 Image
属性。
- 添加对 Build DLL 的引用。
- 将控件添加到您的窗体。
- 设置所需的控件属性。
- 设置控件的
Image
属性。
学到的教训
此控件有一个事件,在图像更改后触发。如果此事件的订阅者花费大量时间或处理器资源,它**将**对该控件的性能产生负面影响。
没有 backup
图像,缩放过程(放大和缩小)会降低图像质量。
已知问题
- 一些设计器模式不稳定。
- 一些边框样式绘制不正确的相关问题。
历史
该控件由 Trusted Plans Service Corp. Tacoma WA 开发。
- 版本 1 - 发布日期 2006 年 3 月 6 日。
- 版本 2 - 发布日期 2006 年 12 月 12 日。