DataGridView中的图像缩略图预览
展示了如何在 DataGridView 中显示图像,并进行图像大小调整和分页的实现。
引言
这是一个展示如何在 DataGridView
中显示缩略图,并进行图像大小调整和分页的实现。我创建它的主要原因是为了允许用户快速高效地预览数千张图像,同时仍然具有 DataGridView
的核心功能,例如,选择单元格等。
我见过的其他解决方案使用所有者面板或其他控件,这些控件运行良好,但不允许用户选择图像。此外,由于控件是所有者绘制的,因此它们没有像 SelectIndexChanged
等内置事件,这在我的情况下使它们无法使用。我见过的其他解决方案仅显示带有上一个和下一个预览的主图像,就像胶片预览一样。同样,我无法使用它们,因为我需要显示数千张图像并且能够快速浏览它们。
所以,如果它可以节省一些人的时间,或者给他们灵感,那就太好了。
演示/示例
该实现将尝试动态创建正确的列数以适应 DataGridView
宽度。当 DataGridView
调整大小以适应正确的宽度时,图像会重新加载。
使用滑块控件选择图像缩略图大小。当值更改时,图像会重新加载,并以新的选定图像大小显示当前图像集。
每页显示的图像数量可以通过下拉列表修改。如果值更改,则图像将从头开始重新显示;这纯粹是为了使实现更容易!
代码
列宽是使用以下代码计算的,这使我们能够动态创建所需的列数以适应 DataGridView
的实际宽度
int numColumnsForWidth = (dataViewImages.Width - 10) / (_imageSize + 20);
另一个要求是显示每页所需图像数量的最少行数,原因是我想让它看起来尽可能专业。要计算行数,我们需要计算要显示的图像数量,然后使用适合 DataViewGrid
所需的列数。接下来,我们使用模数运算符来检查计算的余数;如果得到结果,那么我们添加另一行来显示溢出
numRows = numImagesRequired / numColumnsForWidth;
// Do we have a an overfill for a row
if (numImagesRequired % numColumnsForWidth > 0)
{
numRows += 1;
}
该代码使用先前计算的值动态创建列和行。值 **20** 只是一个用于在图像周围创建边框的值,以便用户可以看到选择了哪些图像
// Dynamically create the columns
{
dataViewImages.Columns.Add(dataGridViewColumn);
dataViewImages.Columns[index].Width = _imageSize + 20;
}
// Create the rows
for (int index = 0; index < numColumnsForWidth; index++)
{
DataGridViewImageColumn dataGridViewColumn =
new DataGridViewImageColumn();
dataViewImages.Rows.Add();
dataViewImages.Rows[index].Height = _imageSize + 20;
}
图像是从先前加载的 List<string>
变量动态加载的,该变量包含图像路径。实际图像是从文件系统加载的。该代码将文件名分配给工具提示,以便可以轻松识别图像
// Load the image from the file and add to the DataGridView
Image image = Helper.ResizeImage(_files[index],
_imageSize,
_imageSize,
false);
dataViewImages.Rows[rowIndex].Cells[columnIndex].Value = image;
dataViewImages.Rows[rowIndex].Cells[columnIndex].ToolTipText =
Path.GetFileName(_files[index]);
上面的代码引用了一个 Helper.ResizeImage
函数,这是一个简单的例程,顾名思义,它将在内存中调整图像大小
public static Image ResizeImage(string file,
int width,
int height,
bool onlyResizeIfWider)
{
using (Image image = Image.FromFile(file))
{
// Prevent using images internal thumbnail
image.RotateFlip(RotateFlipType.Rotate180FlipNone);
image.RotateFlip(RotateFlipType.Rotate180FlipNone);
if (onlyResizeIfWider == true)
{
if (image.Width <= width)
{
width = image.Width;
}
}
int newHeight = image.Height * width / image.Width;
if (newHeight > height)
{
// Resize with height instead
width = image.Width * height / image.Height;
newHeight = height;
}
Image NewImage = image.GetThumbnailImage(width,
newHeight,
null,
IntPtr.Zero);
return NewImage;
}
}
因为某些行将具有没有图像的单元格,原因是显示的图像数量不等于行数 * 列数,我们需要将单元格设置为 null 值,否则会显示一个通用的未找到图像图标,这很难看
// Blank the unused cells
if (numGeneratedCells > numImagesRequired)
{
for (int index = 0; index <
numGeneratedCells - numImagesRequired; index++)
{
DataGridViewCellStyle dataGridViewCellStyle =
new DataGridViewCellStyle();
dataGridViewCellStyle.NullValue = null;
dataGridViewCellStyle.Tag = "BLANK";
dataViewImages.Rows[rowIndex].Cells[columnIndex +
index].Style = dataGridViewCellStyle;
}
}
其余代码处理检查列表边界条件,以处理诸如用户显示的图像少于每页图像数量设置的情况。此外,另一个关键检查是确保当我们到达列表末尾时,我们可以显示所有图像。
历史
- v1.0.0 - 初始版本。