您的当前位置:首页>全部文章>文章详情

【C#】C# Winform 相册功能,图片缩放,拖拽,预览图分页

CrazyPanda发表于:2024-02-02 22:48:51浏览:322次TAG:


一、前言

在一些项目中也会用到预览图片的功能,至于为什么有一个添加图片的按钮,是因为有些项目,比如视觉相关的项目,摄像头拍摄图片,然后显示在界面上,拍一次显示一张。另一个,就是分页功能,当预览图位置不够用时就会用到。

当前软件的功能

1.添加图片

如果8个预览图都满了,会自动分页,就可以点击上一页,或者下一页了。

2.点击预览图显示大图

点击预览图,之前的拖拽和放大会自动复位

3.大图可以拖拽,放大,缩小

如果图片比较小,有这个功能就看到图片的更多细节了。

4.图片倒序排列

最后拍摄的图片,始终显示在前面,方便用户更好的观察到最新的图片

1.png



二、实现功能

新建一个winform项目,界面如下:

1.png

界面中大图和预览图都是 PictureBox 控件 ,至于控件的名字,在下面的代码中可以看到,在文章的最后面,我会附上这个Demo源码,Visual Studio 版本为2019.

代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace 相册功能
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        //本地的相册列表
        private string AlbumPath = Application.StartupPath + "\\Album";
        //相册列表
        private List<PictureBox> PictureBoxList = new List<PictureBox>();
        //图片路径列表
        private List<string> FilesinfoList = new List<string>();
        //相册显示的图片列表
        private List<Bitmap> BitmapList = new List<Bitmap>();
        //pictureBox1的初始位置
        private Point PicStartPos;
        //pictureBox1的初始大小
        private Size PicSize;
 
        //测试用
        int index = -1;
        //当前页数
        private int NowPage = 1;
        //总页数
        private int TotalPage = 1;
        //鼠标滚轮缩放图片的增量值
        private int ZoomStep = 20;
        //鼠标是否在拖拽中
        private bool IsMove = false;
        //鼠标点击的位置
        private Point MouseDownPoint;
 
        private void Form1_Load(object sender, EventArgs e)
        {
            PicStartPos = pictureBox1.Location;
            PicSize = pictureBox1.Size;
            this.pictureBox1.MouseWheel += new MouseEventHandler(this.pictureBox1_MouseWheel);
 
            PictureBoxList.Add(PictureBox_ImgList1);
            PictureBoxList.Add(PictureBox_ImgList2);
            PictureBoxList.Add(PictureBox_ImgList3);
            PictureBoxList.Add(PictureBox_ImgList4);
            PictureBoxList.Add(PictureBox_ImgList5);
            PictureBoxList.Add(PictureBox_ImgList6);
            PictureBoxList.Add(PictureBox_ImgList7);
            PictureBoxList.Add(PictureBox_ImgList8);
 
            //添加图片的点击事件
            for (int i = 0; i < PictureBoxList.Count; i++)
            {
                PictureBoxList[i].Click += new System.EventHandler(PictureBoxClick);
            }
 
            DirectoryInfo directory = new DirectoryInfo(AlbumPath);
            FileSystemInfo[] filesArray = directory.GetFileSystemInfos();
            foreach (var item in filesArray)
            {
                if (item.Attributes != FileAttributes.Directory)
                {
                    FilesinfoList.Add(item.FullName);
                }
            }
        }
 
        /// <summary>
        /// 上一页
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Back_Click(object sender, EventArgs e)
        {
            if (NowPage <= 1) return;
 
            NowPage--;
            for (int i = 0; i < PictureBoxList.Count; i++)
            {
                PictureBoxList[i].Image = null;
            }
 
            List<Bitmap> list = GetPagesBitmap(NowPage);
            for (int i = 0; i < list.Count; i++)
            {
                PictureBoxList[i].Image = list[i];
            }
 
            pictureBox1.Image = list[0];
            //设置坐标
            pictureBox1.Location = PicStartPos;
            //设置控件宽高
            pictureBox1.Size = PicSize;
 
            Label_NumberOfPages.Text = string.Format("{0} / {1}", NowPage, TotalPage);
            BackNextButtonType();
        }
 
        /// <summary>
        /// 下一页
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Next_Click(object sender, EventArgs e)
        {
            if (NowPage >= TotalPage) return;
 
            NowPage++;
            for (int i = 0; i < PictureBoxList.Count; i++)
            {
                PictureBoxList[i].Image = null;
            }
 
            List<Bitmap> list = GetPagesBitmap(NowPage);
            for (int i = 0; i < list.Count; i++)
            {
                PictureBoxList[i].Image = list[i];
            }
 
            pictureBox1.Image = list[0];
            //设置坐标
            pictureBox1.Location = PicStartPos;
            //设置控件宽高
            pictureBox1.Size = PicSize;
 
            Label_NumberOfPages.Text = string.Format("{0} / {1}", NowPage, TotalPage);
            BackNextButtonType();
        }
 
        /// <summary>
        /// 添加图片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Add_Click(object sender, EventArgs e)
        {
            index++;
            AddPicture(new Bitmap(FilesinfoList[index]));
            if (index >= FilesinfoList.Count - 1)
                index = -1;
        }
 
        /// <summary>
        /// 添加图片
        /// </summary>
        /// <param name="bitmap"></param>
        private void AddPicture(Bitmap bitmap)
        {
            if (bitmap == null) return;
 
            //添加到图片列表
            BitmapList.Add(bitmap);
            //界面预留图中显示
            pictureBox1.Image = bitmap;
            //设置坐标
            pictureBox1.Location = PicStartPos;
            //设置控件宽高
            pictureBox1.Size = PicSize;
 
            //计算当前总页数
            int page = BitmapList.Count / PictureBoxList.Count;
            int remainder = BitmapList.Count % PictureBoxList.Count;
            TotalPage = remainder > 0 ? page + 1 : page;
            Label_NumberOfPages.Text = string.Format("{0} / {1}", NowPage, TotalPage);
 
            BackNextButtonType();
 
            //让图片按逆向顺序显示
            List<Bitmap> reverseSort = new List<Bitmap>();
            for (int i = BitmapList.Count - 1; i >= 0; i--)
            {
                reverseSort.Add(BitmapList[i]);
            }
            for (int i = 0; i < reverseSort.Count; i++)
            {
                if (i <= 7)
                    PictureBoxList[i].Image = reverseSort[i];
            }
        }
 
        /// <summary>
        /// 8张预览图片的点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PictureBoxClick(Object sender, System.EventArgs e)
        {
            PictureBox pictureBox = (PictureBox)sender;
            if (pictureBox != null && pictureBox.Image != null)
            {
                pictureBox1.Image = pictureBox.Image;
                //设置坐标
                pictureBox1.Location = PicStartPos;
            }
        }
 
        /// <summary>
        /// 获取索引对应的图片
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private List<Bitmap> GetPagesBitmap(int index)
        {
            if (BitmapList.Count <= 0) return null;
 
            //页数
            int page = BitmapList.Count / PictureBoxList.Count;
            //余数
            int remainder = BitmapList.Count % PictureBoxList.Count;
            //总页数
            int allPage = remainder > 0 ? page + 1 : page;
 
            if (index > allPage) return null;
 
            //索引起点
            int start = (index * PictureBoxList.Count) - PictureBoxList.Count;
            //索引结束点
            int end = (index * PictureBoxList.Count) - 1;
            if (end > BitmapList.Count) end = BitmapList.Count - 1;
 
            List<Bitmap> reverseSort = new List<Bitmap>();
            for (int i = BitmapList.Count - 1; i >= 0; i--)
            {
                reverseSort.Add(BitmapList[i]);
            }
 
            List<Bitmap> list = new List<Bitmap>();
            for (int i = start; i <= end; i++)
            {
                list.Add(reverseSort[i]);
            }
 
            if (list.Count > 0)
                return list;
            return null;
        }
 
        /// <summary>
        /// 上一页,下一页按钮状态
        /// </summary>
        private void BackNextButtonType()
        {
            Button_Next.Enabled = true;
            Button_Back.Enabled = true;
 
            //现在页 = 总页数
            if (NowPage == TotalPage)
                Button_Next.Enabled = false;
            //现在页 小于等于 1
            if (NowPage <= 1)
                Button_Back.Enabled = false;
        }
 
 
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (pictureBox1.Image == null) return;
 
            if (e.Button == MouseButtons.Left)
            {
                MouseDownPoint.X = Cursor.Position.X; //记录鼠标左键按下时位置
                MouseDownPoint.Y = Cursor.Position.Y;
                IsMove = true;
                pictureBox1.Focus(); //鼠标滚轮事件(缩放时)需要picturebox有焦点
            }
        }
 
        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                IsMove = false;
            }
        }
 
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (pictureBox1.Image == null) return;
            pictureBox1.Focus(); //鼠标在picturebox上时才有焦点,此时可以缩放
            if (IsMove)
            {
                int x, y;   //新的pictureBox1.Location(x,y)
                int moveX, moveY; //X方向,Y方向移动大小。
                moveX = Cursor.Position.X - MouseDownPoint.X;
                moveY = Cursor.Position.Y - MouseDownPoint.Y;
                x = pictureBox1.Location.X + moveX;
                y = pictureBox1.Location.Y + moveY;
                pictureBox1.Location = new Point(x, y);
                MouseDownPoint.X = Cursor.Position.X;
                MouseDownPoint.Y = Cursor.Position.Y;
            }
        }
 
        private void pictureBox1_MouseWheel(object sender, MouseEventArgs e)
        {
            if (pictureBox1.Image == null) return;
 
            PictureBox pbox = pictureBox1;
            int x = e.Location.X;
            int y = e.Location.Y;
            int ow = pbox.Width;
            int oh = pbox.Height;
            int VX, VY;  //因缩放产生的位移矢量
            if (e.Delta > 0) //放大
            {
                //第1步
                pbox.Width += ZoomStep;
                pbox.Height += ZoomStep;
                //第2步
                PropertyInfo pInfo = pbox.GetType().GetProperty("ImageRectangle", BindingFlags.Instance | BindingFlags.NonPublic);
                Rectangle rect = (Rectangle)pInfo.GetValue(pbox, null);
                //第3步
                pbox.Width = rect.Width;
                pbox.Height = rect.Height;
 
                //Console.WriteLine(string.Format("宽:{0},高:{1}",pbox.Width,pbox.Height));
            }
            if (e.Delta < 0) //缩小
            {
                //防止一直缩成负值
                if (pbox.Width < 300)
                    return;
 
                pbox.Width -= ZoomStep;
                pbox.Height -= ZoomStep;
                PropertyInfo pInfo = pbox.GetType().GetProperty("ImageRectangle", BindingFlags.Instance |
                 BindingFlags.NonPublic);
                Rectangle rect = (Rectangle)pInfo.GetValue(pbox, null);
                pbox.Width = rect.Width;
                pbox.Height = rect.Height;
            }
 
            //第4步,求因缩放产生的位移,进行补偿,实现锚点缩放的效果
            VX = (int)((double)x * (ow - pbox.Width) / ow);
            VY = (int)((double)y * (oh - pbox.Height) / oh);
            pbox.Location = new Point(pbox.Location.X + VX, pbox.Location.Y + VY);
        }
 
 
    }
}

代码中,鼠标缩放,拖拽功能,需要在控件里选择对应的方法,否则运行就没有效果

1.png

运行后,效果就如文章开头的 Gif 图片

源码:点击下载


结束

如果这个帖子对你有用,欢迎 关注 + 点赞 + 留言,谢谢

end

原文链接C# Winform 相册功能,图片缩放,拖拽,预览图分页_c#鼠标滚轮放大缩小图片-CSDN博客

猜你喜欢

【C#】C# Winform 多个程序之间的通信(非Scoket)
效果功能:打开窗体自动连接主程序,并自动添加到列表,可以向子程序群发消息可以向单个程序单独发送消息在退出程序后,添加的程序列表会自动移除一、概述参考:C# Winfrom程序之间通讯_c# sendmessege copydatastruct 返回多个值_熊思宇的博客-CSDN博客在之前我写过 winform 程序与程序之间的通信,但是这个版本有个问题,那就是只能由两个程序进行通信,同时打开多个程序的话,接收方收到的数据就会一模一样,这次发表这个教程,也就是要解决这个问题。归根结底,还是&amp;nbs
发表于:2024-02-03 浏览:304 TAG:
【C#】C# Winfrom 常用功能整合-2
目录Winfrom&nbsp;启动一个外部exe文件,并传入参数Winform ListBox用法HTTP下载文件(推荐)Winform HTTP下载并显示进度Winform&nbsp;HTTP下载文件Winform&nbsp;跨线程访问UI组件Winform 改变文字的颜色和大小Winfrom&nbsp;启动一个外部exe文件,并传入参数在我们常用的一些软件中,经常有些软件,双击之后根本打不开,这是因为启动时做了限制,我们需要传入一些参数才能打开,在工作中,这个需求也可以用在软件的自动更新上,
发表于:2024-02-02 浏览:339 TAG:
【C#】C#实现Excel合并单元格数据导入数据集
目录功能需求Excel与DataSet的映射关系范例运行环境Excel DCOM 配置设计实现组件库引入方法设计返回值&nbsp;参数设计打开数据源并计算Sheets拆分合并的单元格创建DataTable将单元格数据写入DataTable总结功能需求将Excel里的worksheet表格导入到DataSet里,是项目应用里常用的一种操作。一般情况下,worksheet是一个标准的二维数组,如下图:我们可以效仿 MS SQL SERVER 的一些基本导入选项,如首行是否包含数据,要导入哪个Shee
发表于:2024-01-29 浏览:356 TAG:
【C#】c#开发桌面应用程序用什么框架
style="text-wrap: wrap;">在C#开发桌面应用程序时,可以使用以下几种常见的框架:</p><ol class=" list-paddingleft-2" style="width: 1529.1px; text-wrap: wrap;"><li><p>Windows Forms:这是一种由.NET Framework提供的GUI框架,它提供了丰富的GUI控件和易于使用的编程模型。Windows Forms在C#开发领域中使用非常广泛,并且已经存在多年,获得了广泛的支持和优化。</p></li></ol
发表于:2024-01-27 浏览:452 TAG:
【C#】C# 开源框架(整理)
C# 开源框架(整理)Json.NEThttp://json.codeplex.com/Json.Net 是一个读写Json效率比较高的.Net框架.Json.Net 使得在.Net环境下使用Json更加简单。通过Linq To JSON可以快速的读写Json,通过JsonSerializer可以序列化你的.Net对象。让你轻松实现.Net中所有类型(对象,基本数据类型 等)和Json的转换。Math.NEThttp://www.mathdotnet.com/Math.NET的目标是为提供一款
发表于:2024-01-30 浏览:344 TAG:
【C#】从零开始用C#写一个桌面应用程序(二)一个表白程序
恶搞表白小程序如何添加按钮,如何添加属性和事件请移步前文。基础操作第一步:新建窗口&nbsp;&nbsp;在工具箱内找到label和button,拖到form上,设置它们的size属性,autosize属性,text属性。第二步:添加事件为了实现我们的效果,需要给三个按钮分别设计点击事件,鼠标移入事件,鼠标点下事件。分别为click,mouseenter,mousedown事件。第三步:实现移动逻辑this获取form对象,clientsize获取实时大小,使用随机数值,设置对应按钮位置。将对应
发表于:2024-01-30 浏览:304 TAG:
【C#】C# Winform程序之间通讯
实现原理通过Windows系统中 User32.dll 中的 FindWindow 方法来寻找系统正在运行的程序句柄,通过 SendMessage 方法来发送消息,winform 中的&nbsp;WndProc 方法来接收消息,下面是SendMessage,FindWindow 这两个参数的具体介绍:1.SendMessage该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。该函数是应用程序和应用程序之间进行消息传递的主要手段之一 函数原型:I
发表于:2024-01-30 浏览:392 TAG:
【C#】C# Winfrom 右键菜单
目录一、概述二、新建&nbsp;winform 项目三、给图片控件添加右键菜单四、给菜单添加点击事件五、测试结束一、概述ContextMenuStrip 是 Windows 窗体应用程序中的一个控件,它提供了一个弹出菜单,用于在用户右键单击控件或其他界面元素时显示上下文相关的选项。它通常用于在图形用户界面中提供快捷操作和功能。ContextMenuStrip 控件可以通过在 Visual Studio 的设计器中拖放方式添加到窗体上,或者通过编程方式创建和配置。它可以与其他控件(如按钮、文本框等
发表于:2024-02-02 浏览:361 TAG:
【C#】C# Winform GDI+ 绘图
目录一、概述二、绘图1.画直线2.画矩形3.画圆、圆弧4.画扇形5.画多边形6.绘制字符串7.填充图形结束一、概述Graphics类是GDI+技术的一个基本类。GDI+(Graphics Device Interface)是.NET框架的重要组成部分,提供对二维图形图像和文字排版处理的支持。GDI+相关的类分布在下列命名空间中: System.Drawing:提供了最基本的绘图功能(比如画直线、矩形、椭圆等); System.Drawing.Drawing2D: 提供了高级的二维和矢量绘图功能(
发表于:2024-02-18 浏览:387 TAG:
【C#】C# Winform 定时清理日志
一、前言在 Winform 开发中经常有这样的需求,在用户执行一些操作不正确时,需要将错误信息反馈给用户,比如:登录密码不正确,无法连接到服务器等,一般常见的用法有两个:1.弹框使用&nbsp;MessageBox.Show(&quot;密码错误&quot;); 这样的方式,弹框后,用户必须点击确定后才能执行下一步操作,给用户的体验并不是特别好。2.在界面中显示错误信息,定时清除如果是输入框,直接用&nbsp;ErrorProvider 控件就行了。如果只是做一些简单的提示信息,那么就要定时清除
发表于:2024-01-31 浏览:307 TAG: