前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Excel催化剂开源第9波-VSTO开发图片插入功能,图片带事件

Excel催化剂开源第9波-VSTO开发图片插入功能,图片带事件

作者头像
Excel催化剂
发布2021-08-19 15:03:31
1.4K0
发布2021-08-19 15:03:31
举报
文章被收录于专栏:Excel催化剂

图片插入功能,这个是Excel插件的一大刚需,但目前在VBA接口里开发,如果用Shapes.AddPicture方法插入的图片,没法对其添加事件,且图片插入后需等比例调整纵横比例特别麻烦,特别是对于插入的多个图片非统一的纵横尺寸比时。

例如一个很经典的需求是将插入的缩略图放大操作,没法点击、双击之类的事件响应对应的放大操作。

在VBA的方法中,还有一个方式,用窗体控件Image,可以实现图片插入后有事件关联。

窗体控件Image方法插入

但很遗憾的是,这个方法中插入的图片,当没有点选图片时,图片会有些模糊的情况。具体可对比下图左右部分。这个模糊的问题,还是老大难,难于达到完美。如果换成是VSTO的宿主项PictureBox,就完美解决了。

两种不同窗体控件方式插入图片

例如下图中的,用鼠标右键事件,调出上下文菜单。和Excel催化剂中的双击图片进行图片下载本地并调用Windows图片查看器实现图片的放大功能。

可以关联事件的插入图片方法

双击图片事件

保留有正确的原始图片纵横比例

笔者觉得这是个接近完美的解决方案(用窗体控件的方式插入图片,用户不能直接选择图片、移动图片,会有种奇怪的感觉)。

具体实现

使用VSTO的PictureBox容器,将其图片属性设置成对应的图片对象即可,此处传入的图片对象是Image对象,不必像VBA方法里的只能传入文件全路径,可以方便某些数据库等方式存储二进制图片格式时,直接调用。

代码语言:javascript
复制
 public static string AddPictureBoxToVstoWorkSheet(Excel.Range dstRange, Image img, string fileExt, bool hasBordersMargin, bool isLookupFromRangValue, int offsetRow, int offsetCol)
        {
            string picName = Guid.NewGuid().ToString();
            Excel.Worksheet actSht = dstRange.Worksheet;
            Worksheet vstoActSht = Globals.Factory.GetVstoObject(actSht);
            PictureBox pictureBox = new PictureBox();
            pictureBox.Image = img;
            pictureBox.SizeMode = PictureBoxSizeMode.Zoom;

            pictureBox.MouseDoubleClick += PictureBox_MouseDoubleClick;

            AddContextMenuToPictureBox(pictureBox);

            pictureBox.Name = picName;
            ControlSite controlSite;
            if (hasBordersMargin)
            {
                controlSite = vstoActSht.Controls.AddControl(
                       control: pictureBox,
                       top: dstRange.Top + 2,
                       left: dstRange.Left + 2,
                       height: dstRange.Height - 4,
                       width: dstRange.Width - 4,
                       name: picName);
            }
            else
            {
                controlSite = vstoActSht.Controls.AddControl(
                      control: pictureBox,
                      range: dstRange,
                      name: picName);
            }



            string srcFileName = string.Empty;
            Excel.Range srcFileNameRange = null;
            if (isLookupFromRangValue)
            {
                //取回图片文件名的单元格,可拿到文件名,我初始的单元格地址,为后面有可能插入过行、列来重新定位。
                srcFileNameRange = dstRange.Offset[-offsetRow, -offsetCol];
                srcFileName = srcFileNameRange == null ? "" : srcFileNameRange.Value2.ToString();
            }

            Common.vstoPicInfos.Add(
                            new Entity.VstoPicInfo()
                            {
                                PicName = picName,
                                IsLookupFromRangValue = isLookupFromRangValue,
                                PicOleName = controlSite.Name,
                                PicSht = actSht,
                                SrcFileNameRange = srcFileNameRange,
                                DstRange = dstRange,
                                SrcFileName = srcFileName,
                                ImageExt = fileExt,
                                PictureBoxImage = img
                            });
            return picName;
        }

其中核心代码有: 得到一个VSTO的WorkSheet对象和新建一个PictureBox对象。

代码语言:javascript
复制
  Excel.Worksheet actSht = dstRange.Worksheet;
            Worksheet vstoActSht = Globals.Factory.GetVstoObject(actSht);
            PictureBox pictureBox = new PictureBox();
            pictureBox.Image = img;
            pictureBox.SizeMode = PictureBoxSizeMode.Zoom;

通过方法vstoActSht.Controls.AddControl进行创建一个Picturebox到工作表中。具体各参数的意义和VBA的AddPicture方法类似,可自行查阅文档。

代码语言:javascript
复制
   controlSite = vstoActSht.Controls.AddControl(
                       control: pictureBox,
                       top: dstRange.Top + 2,
                       left: dstRange.Left + 2,
                       height: dstRange.Height - 4,
                       width: dstRange.Width - 4,
                       name: picName);

通过以上的方法,即可创建了一个PictureBox对象容器,并且图片是我们传入的图片。这当中可以绑定一些PictureBox事件和上下文菜单等,如:

代码语言:javascript
复制
pictureBox.MouseDoubleClick += PictureBox_MouseDoubleClick;

        private static void AddContextMenuToPictureBox(PictureBox pictureBox)
        {
            ContextMenuStrip contextMenuStrip = new ContextMenuStrip();
            string[] btnsText = { "复制另存为", "移动至其他区域", "删除图片" };
            foreach (var btnText in btnsText)
            {
                ToolStripButton toolStripButton = new ToolStripButton(btnText);
                toolStripButton.Tag = pictureBox;
                toolStripButton.Click += PictureBoxToolStripButton_Click;
                contextMenuStrip.Items.Add(toolStripButton);
            }

            pictureBox.ContextMenuStrip = contextMenuStrip;
        }

通过此方法插入的PictureBox,保存关闭后,Excel文件因无法在关闭状态下存储PictureBox对象,将会将其转换为OLE对象存储,设置过的事件将失效,Excel催化剂用了复杂的手段来恢复它,下篇其他技术时再进行介绍

结语

图片插入这样一个刚需功能,在Excel催化剂上已经将其做到极致化的体验,也是有别于传统方式所实现的,在用户体验上,相信有对比后,也会喜欢上Excel催化剂这样的突破性的方式。

此篇已经对核心的技术及代码完成开源公开化,有兴趣的朋友们,可以一试。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-01-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Excel催化剂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 具体实现
  • 结语
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档