C# 系统应用之ListView实现简单图片浏览器

简介:

        最近有同学问我如何使用ListView加载图片列表,前面在"C#系统应用"中TreeView+ListView+ContextMenuStrip控件实现树状图显示磁盘目录,并在ListView中显示文件的详细信息.这里准备简单介绍下给同学讲述的如何使用ListView+ImageList控件实现简单的图片浏览器知识.
       第一步 设计界面框架如下图所示,同时添加ImageList控件(不可见)

        注意:设置ListView控件的Anchor属性为Top,Bottom,Right;设置PictureBox的Anchor属性为上下左右.
       第二步 使用OpenFileDialog控件打开显示图片

//打开图片
private void button1_Click(object sender, EventArgs e)
{
    //设置打开文件控件
    OpenFileDialog openfile = new OpenFileDialog();
    openfile.Filter = "JPG(*.JPG;*.JPEG);gif文件(*.GIF);BMP文件(*.BMP);PNG文件(*.PNG)|*.jpg;*.jpeg;*.gif;*.bmp;*.png";
    openfile.FilterIndex = 1;  //当前选定索引
    openfile.RestoreDirectory = true;
    openfile.FileName = "";
    //对话框选择确定按钮
    if (openfile.ShowDialog() == DialogResult.OK)
    {
        //FromFile从指定的文件创建Image
        pictureBox1.Image = Image.FromFile(openfile.FileName);
        //图片被拉伸或收缩适合pictureBox大小
        pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;               
    }
}

        图片显示效果如下图所示,需要注意的是在使用FromFile显示图片,可能图片全屏显示时会出现只出现部分图片现象,我设置图片为可拉伸或收缩StretchImage模式.

       第三步 显示图片列表至ListView控件中
        主要通过控件FolderBrowserDialog控件打开文件夹,同时获取文件夹的路径;在通过GetFiles("*.jpg")函数获取jpg格式图片,并获取文件夹中文件增加至ImageList中,设置ListView的View属性格式为LargeIcon大图标格式显示.

//添加命名空间
using System.IO;                   //Directory目录
using System.Diagnostics;          //Stopwatch显示时间

//定义变量
private string folderDirPath;                            //图片文件夹地址
private string picDirPath = null;                        //图片路径
private List<string> imagePathList = new List<string>(); //获取列表图片路径
private int index;                                       //获取选中列表图片序号

//ListView和imageList显示图片列表
private void button2_Click(object sender, EventArgs e)
{
    try
    {
        //打开选择文件夹对话框
        FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
        DialogResult result = folderBrowserDialog.ShowDialog();
        if (result == DialogResult.OK)
        {
            //获取用户选择的文件夹路径
            this.folderDirPath = folderBrowserDialog.SelectedPath;
            //调用自定义函数显示图片列表至ListView控件
            ShowPicture();
        }
        else if (result == DialogResult.Cancel)
        {
            MessageBox.Show("取消显示图片列表");
        }
    }
    catch (Exception msg)
    {
        //报错提示 未将对象引用设置到对象的实例
        throw msg;
    }     
}

//显示图片列表至ListView控件
private void ShowPicture()
{
    //提供一种方法测试运行时间 开始计算
    //参考资料:http://www.cnblogs.com/newstart/archive/2012/09/21/2696884.html
    Stopwatch sw = new Stopwatch();
    sw.Start();

    //获取目录与子目录
    DirectoryInfo dir = new DirectoryInfo(folderDirPath);
    //获取当前目录JPG文件列表 GetFiles获取指定目录中文件的名称(包括其路径)
    FileInfo[] fileInfo = dir.GetFiles("*.jpg");
    //防止图片失真
    //参考资料:http://blog.csdn.net/cdefg198/article/details/7821891 (博客中引用)
    this.imageList1.ColorDepth = ColorDepth.Depth32Bit;
    for (int i = 0; i < fileInfo.Length; i++)
    {
        //获取文件完整目录
        picDirPath = fileInfo[i].FullName;
        //记录图片源路径 双击显示图片时使用
        imagePathList.Add(picDirPath);
        //图片加载到ImageList控件和imageList图片列表
        this.imageList1.Images.Add(Image.FromFile(picDirPath));
    }

    //显示文件列表
    this.listView1.Items.Clear();
    this.listView1.LargeImageList = this.imageList1;
    this.listView1.View = View.LargeIcon;        //大图标显示
    //imageList1.ImageSize = new Size(40, 40);   //不能设置ImageList的图像大小 属性处更改

    //开始绑定
    this.listView1.BeginUpdate();
    //增加图片至ListView控件中
    for (int i = 0; i < imageList1.Images.Count; i++)
    {
        ListViewItem lvi = new ListViewItem();
        lvi.ImageIndex = i;
        lvi.Text = "pic" + i;
        this.listView1.Items.Add(lvi);
    }
    this.listView1.EndUpdate();

    //显示打开图片列表所需时间
    sw.Stop();
    long secords = sw.ElapsedMilliseconds; //毫秒单位
    label1.Text += '\n' + (Convert.ToDouble(secords) / 1000).ToString();  //转换为秒
}  

        显示结果如下图所示:

        需要注意的是:
        1.使用ListView加载信息的几个步骤:获取文件夹路径 -> DirectoryInfo获取目录 -> GetFiles获取文件 -> Add图片至ImageList -> Add图片至ListView.
        2.在设置ListView中图片的大小时,使用imageList1.ImageSize = new Size(40, 40)赋值失败,我是通过修改ImageList1的ImageSize属性为(64,64)实现的.
        3.显示ListView中图片,通常会出现失真的情况,主要原因参考博客:
ListView显示图片失真.
        主要概括为ImageList里面图片颜色失真和图片大小失真,其中图片颜色失真原因是Design-Time在VS.NET中添加图片时没有使用用户指定的ColorDepth(如Depth32Bit),而用了ImageList.ColorDepth的默认值(Depth8Bit).因此需要先设置图片颜色深度,在再往ImageList中添加图片,而图片大小统一的都等于ImageList.ImageSize.
       第四步 通过listView1_DoubleClick函数双击打开图片
        在Form1.cs[设计]中ListView属性页为其添加DoubleClick双击事件,并通过Image.FromFile显示图片.

//增加双击ListView事件 显示图片至PictureBox
private void listView1_DoubleClick(object sender, EventArgs e)
{
    if (this.listView1.SelectedItems.Count == 0)
        return;
    //采用索引方式 imagePathList记录图片真实路径
    index = this.listView1.SelectedItems[0].Index;
    //显示图片
    this.pictureBox1.Image = Image.FromFile(imagePathList[index]);
    //图片被拉伸或收缩适合pictureBox大小
    pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
}

        双击列表中不同图片的显示效果如下图所示:


        其中需要注意的是,我在列表中显示图片重命名为"pic+数字",同时定义变量记录文件夹中图片真实路径与其一一对应.private List<string> imagePathList = new List<string>().这里使用index显示对应图片即可,同样显示上一张\下一张相同.
       第五步 显示上一张\下一张

//显示上一张图片
private void button3_Click(object sender, EventArgs e)
{
    if (pictureBox1.Image != null)
    {
        if (index > 0)
        {
            index--;
            //显示图片
            this.pictureBox1.Image = Image.FromFile(imagePathList[index]);
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;                  
        }
        else if (index == 0)
        {
            index = imagePathList.Count;
            index--;
            //显示图片
            this.pictureBox1.Image = Image.FromFile(imagePathList[index]);
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;                  
        }
    }
}
//显示下一张图片
private void button4_Click(object sender, EventArgs e)
{
    if (pictureBox1.Image != null)
    {
        if (index == imagePathList.Count - 1) //最后一张图片
        {
            index = 0;
            //显示图片
            this.pictureBox1.Image = Image.FromFile(imagePathList[index]);
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
                 
        }
        else
        {
            index++;
            //显示图片
            this.pictureBox1.Image = Image.FromFile(imagePathList[index]);
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;                  
        }
    }
}   

        文章写到此处基本内容完成,内容比较简单,但也构成了一个完整的图片浏览器.同时很多时候我们需要上传缩略图,可以调用下面函数(在线笔记):

//添加命名空间
using System.Drawing.Drawing2D;    //CompositingQuality.HighQuality
using System.Drawing.Imaging;      //EncoderParameter

/// <SUMMARY>
/// 图片无损缩放 自定义函数生成缩略图
/// </SUMMARY>
/// <PARAM name="sourceFile">图片源路径</PARAM>
/// <PARAM name="destFile">缩放后图片输出路径</PARAM>
/// <PARAM name="destHeight">缩放后图片高度</PARAM>
/// <PARAM name="destWidth">缩放后图片宽度</PARAM>
/// <RETURNS></RETURNS>
public static bool GetThumbnail(string sourceFile, string destFile, int destHeight, int destWidth)
{
    System.Drawing.Image imgSource = System.Drawing.Image.FromFile(sourceFile);
    System.Drawing.Imaging.ImageFormat thisFormat = imgSource.RawFormat;
    int sW = 0, sH = 0;

    // 按比例缩放
    int sWidth = imgSource.Width;
    int sHeight = imgSource.Height;

    if (sHeight > destHeight || sWidth > destWidth)
    {
        if ((sWidth * destHeight) > (sHeight * destWidth))
        {
            sW = destWidth;
            sH = (destWidth * sHeight) / sWidth;
        }
        else
        {
            sH = destHeight;
            sW = (sWidth * destHeight) / sHeight;
        }
    }
    else
    {
        sW = sWidth;
        sH = sHeight;
    }

    //新建一个bmp图片  
    Bitmap outBmp = new Bitmap(destWidth, destHeight);
    //新建一个画板
    Graphics g = Graphics.FromImage(outBmp);
    //清空画布并以透明背景色填充 Color.Black黑色填充
    g.Clear(System.Drawing.Color.Transparent);
    //设置画布的描绘质量
    g.CompositingQuality = CompositingQuality.HighQuality;
    //设置高质量,低速度呈现平滑程度
    g.SmoothingMode = SmoothingMode.HighQuality;
    //设置高质量插值法
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    //在指定位置并且按指定大小绘制原图片的指定部分
    g.DrawImage(imgSource, new Rectangle((destWidth - sW) / 2, (destHeight - sH) / 2, sW, sH), 0, 0, imgSource.Width, imgSource.Height, GraphicsUnit.Pixel);
    g.Dispose();

    //以下代码为保存图片时 设置压缩质量
    EncoderParameters encoderParams = new EncoderParameters();
    long[] quality = new long[1];
    quality[0] = 100;
    EncoderParameter encoderParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
    encoderParams.Param[0] = encoderParam;

    try
    {
        //获得包含有关内置图像编码解码器的信息的ImageCodecInfo对象
        ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders();
        ImageCodecInfo jpegICI = null;
        for (int x = 0; x < arrayICI.Length; x++)
        {
            if (arrayICI[x].FormatDescription.Equals("JPEG"))
            {
                jpegICI = arrayICI[x]; //设置JPEG编码
                break;
            }
        }
        //保存为JPG格式图片
        if (jpegICI != null)
        {
            outBmp.Save(destFile, jpegICI, encoderParams);
        }
        else
        {
            outBmp.Save(destFile, thisFormat);
        }

        return true;
    }
    catch(Exception e)
    {
        throw e;
    }
    finally
    {
        imgSource.Dispose();
        outBmp.Dispose();
    }
}

        总结:本文主要是根据给同学讲解ListView控件显示图片写的一篇文章,同时存在一个缺点图片可能被扯拉变形,而且代码中打开ListView图片时有个"打开时间",主要是通过Stopwatch记录批量打开图片所需时间,如果打开大量图片时我希望使用并行的方法实现,与其进行时间对比.同时如果对图片处理感兴趣的同学(C++通过Bitmap打开变换)自己可以去研究.我希望的显示效果想Google Picasa一样快速批量显示(研究ing).
        下载地址:http://download.csdn.net/detail/eastmount/8021077
        最后希望文章对大家有所帮助,如果有错误或不足之处,请海涵~
        (By:Eastmount 2014-10-10 中午13点 原创CSDN http://blog.csdn.net/eastmount/)

目录
相关文章
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
1772 14
|
前端开发
WebView2 控件(基于 Microsoft Edge (Chromium) 的嵌入式浏览器控件),保存资源(图片、脚本、CSS)
WebView2 控件(基于 Microsoft Edge (Chromium) 的嵌入式浏览器控件),保存资源(图片、脚本、CSS)
674 88
|
存储 监控 算法
基于 C# 时间轮算法的控制局域网上网时间与实践应用
在数字化办公与教育环境中,局域网作为内部网络通信的核心基础设施,其精细化管理水平直接影响网络资源的合理配置与使用效能。对局域网用户上网时间的有效管控,已成为企业、教育机构等组织的重要管理需求。这一需求不仅旨在提升员工工作效率、规范学生网络使用行为,更是优化网络带宽资源分配的关键举措。时间轮算法作为一种经典的定时任务管理机制,在局域网用户上网时间管控场景中展现出显著的技术优势。本文将系统阐述时间轮算法的核心原理,并基于 C# 编程语言提供具体实现方案,以期深入剖析该算法在局域网管理中的应用逻辑与实践价值。
385 5
|
Web App开发 编解码 vr&ar
使用Web浏览器访问UE应用的最佳实践
在3D/XR应用开发中,尤其是基于UE(虚幻引擎)开发的高精度场景,传统终端因硬件局限难以流畅运行高帧率、复杂效果的三维应用。实时云渲染技术,将渲染任务转移至云端服务器,降低终端硬件要求,确保用户获得流畅体验。具备弹性扩展、优化传输协议、跨平台支持和安全性等优势,适用于多种终端和场景,特别集成像素流送技术,帮助UE开发者实现低代码上云操作,简化部署流程,保留UE引擎的强大开发能力,确保画面精美且终端轻量化。
879 17
使用Web浏览器访问UE应用的最佳实践
|
存储 安全 物联网
C# 在物联网 (IoT) 应用中的应用
本文介绍了C#在物联网(IoT)应用中的应用,涵盖基础概念、优势、常见问题及其解决方法。重点讨论了网络通信、数据处理和安全问题,并提供了相应的代码示例,旨在帮助开发者更好地利用C#进行IoT开发。
820 3
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
331 3
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
470 2
|
Web App开发 定位技术 iOS开发
Playwright 是一个强大的工具,用于在各种浏览器上测试应用,并模拟真实设备如手机和平板。通过配置 `playwright.devices`,可以轻松模拟不同设备的用户代理、屏幕尺寸、视口等特性。此外,Playwright 还支持模拟地理位置、区域设置、时区、权限(如通知)和配色方案,使测试更加全面和真实。例如,可以在配置文件中设置全局的区域设置和时区,然后在特定测试中进行覆盖。同时,还可以动态更改地理位置和媒体类型,以适应不同的测试需求。
Playwright 是一个强大的工具,用于在各种浏览器上测试应用,并模拟真实设备如手机和平板。通过配置 `playwright.devices`,可以轻松模拟不同设备的用户代理、屏幕尺寸、视口等特性。此外,Playwright 还支持模拟地理位置、区域设置、时区、权限(如通知)和配色方案,使测试更加全面和真实。例如,可以在配置文件中设置全局的区域设置和时区,然后在特定测试中进行覆盖。同时,还可以动态更改地理位置和媒体类型,以适应不同的测试需求。
1602 1
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
471 0
|
消息中间件 网络协议 安全
C# 一分钟浅谈:WebSocket 协议应用
【10月更文挑战第6天】在过去的一年中,我参与了一个基于 WebSocket 的实时通信系统项目,该项目不仅提升了工作效率,还改善了用户体验。本文将分享在 C# 中应用 WebSocket 协议的经验和心得,包括基础概念、C# 实现示例、常见问题及解决方案等内容,希望能为广大开发者提供参考。
1501 0