【C#】注意用“划算”的方式使用图标

先解释一下何谓“划算”:假定一个Winform程序包含若干个窗体,每个窗体左上角都要显示图标(即要设置Form.Icon属性),该程序本身也要有个图标(用于在OS资源管理器中显示),所有这些图标都是一个样子——这是一种很常见的情形。如图:

即同一个图标要用在程序本身和程序中的各个窗体之上。那么所谓“划算”就是指,在程序文件(exe)中只存储1份图标数据,所有要用到该图标的地方都从这里取。而不是存储多份,各取各的,因为这样显然会增大程序体积,很不“划算”。

之所以有这个话题,是因为如果不注意操作技巧,就会造成同一个图标存储多份的情况,VS和编译器并没有智能到会帮我们自动清除冗余资源的地步。那么如何才能做到划算而不浪费,关键就是要弄清楚每种操作会造成什么样的结果。

一、先看程序图标的设置方法

这个地方有几种选取方式:

1、直接浏览到ico文件进行选取。VS会自动把ico文件拷贝到项目根目录

2、把ico文件存放到项目根目录或任意子目录(该目录必须“包括在项目中”),然后就可以在这里下拉选取。如上图的Resources\test.ico和test.ico就是这种情况

无论用何种方式选取,项目编译成PE文件后,这个图标都是存放在PE文件的资源节中,可以用eXeScope之类的工具看出。有关PE的信息请参看:

http://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx

http://blog.csdn.net/evileagle/article/details/11693499

换句话说,程序图标的选取没什么可注意的,因为结果都一样。

二、窗体图标的设置方法

1、在VS的属性面板中直接浏览ico文件。如图:

这可能是最直观简单的方法了。但是不幸,这恰恰是最容易造成浪费的方法,因为这样选取的图标,会嵌在相应窗体的资源里(Form.resx),有几个窗体这样设置图标,图标数据就会存几份。

2、把图标添加进项目资源(Resources.resx)中。然后在所有窗体代码中都这样设置:

this.Icon = xx.Properties.Resources.test;//xx是项目默认命名空间;test是资源名

这种方式的结果是,图标会以程序集资源的形式存储1份在程序集中,所有窗体共用这个资源。相比第1种方式,这种方式不会造成图标存储多份。但也只是解决了多个窗体共用一个图标的问题,还有程序本身的图标是个问题。

上面说过,程序图标只有一个地方可以设置,设置的结果是把图标存放到PE资源中,这里存在【程序集资源】和【PE资源】两个概念,就是虽然在程序集资源只有1份图标数据,但只要一设置程序图标,项目编译时就会把图标再存一份到PE资源中,所以在整个PE文件中还是存在2份图标数据。那么要想让程序和窗体共用一个资源,就有两种思路,一是让程序图标使用程序集资源,二是让窗体使用PE资源。

对于前一种,我怎么可能去找虐呢,即使自宫也未必成功的事,pass~

3、获取程序图标,给窗体使用。一开始想到的自然是Icon.ExtractAssociatedIcon(),但是这个方法只能取到32x32的图标,而窗体图标是16x16的,会造成缩放,对于我这种纠结视觉细节的人来说,是不可接受的。理想的情况是,取到完整的图标组(包含多种尺寸和色深的图标集合)赋值给窗体Icon,这样才能在窗体左上角和NT6任务栏拥有完美的表现。如图:

那怎样才能取到图标组呢。为此我啃了若干对于由.net起步的码农来说臣妾做不到的知识,包括SHGetFileInfo、LoadIcon、LoadImage、ExtractIcon、FindResource等API,甚至啃了下PE结构,OMG~越啃越觉得想死的心都有了。天幸在codeproject.com找到了高人的现成方案:

http://www.codeproject.com/Articles/32617/Extracting-Icons-from-EXE-DLL-and-Icon-Manipulatio

先感谢一下这位仁兄,好人一生平安。他这方案挺全,可以从各种源获取图标,本来想精简一下,只要获取PE图标组的方法,但发现整个方案中,大部分代码就是干这个的,精简意义不大,索性整个用上。回正题,在所有窗体中写上:

this.Icon = IconHelper.ExtractIcon(Application.ExecutablePath, 0);

即可。当然我对他的IconHelper稍微改造了一下,增加AppIcon属性:

static Icon appIcon;
/// <summary>
/// 主程序图标
/// </summary>
public static Icon AppIcon
{
    get
    {
        if (appIcon == null)
        {
            try { appIcon = ExtractIcon(Application.ExecutablePath, 0); }
            catch { return null; }
        }
        return appIcon;
    }
}

这样,到窗体中,写成: this.Icon = IconHelper.AppIcon;

即可。

至此,实现了程序和窗体共用一个图标,程序PE文件也只存储1份图标数据的目的。再次感谢高人!只是项目加入该方案后,最终生成的程序大概会增加接近20K的体积。所以是不是划算用上该方案,需从实际权衡。比如图标文件不大的程序,俩图标加起来还没有1图标+20K,那存两份就存两份,反正最终目的是程序体积,又不是追求彻底共用。

----------------------------------为什么非得给分隔线起个名字----------------------------------

另外,顺便说一下托盘区图标,如果给NotifyIcon.Icon设一个图标组,它是不会自动取16x16那一个的,取的是32x32,像这样:

非得直接丢给它一个16x16的才行,所以如果你已经拥有图标组,得这样设置托盘图标:

notifyIcon1.Icon = new System.Drawing.Icon(IconHelper.AppIcon,16,16);//意思就是从图标组中取出指定尺寸的单一图标。

这样就能得到完美的托盘图标了:

----------------------------------另一条分隔线----------------------------------

最后,附一张关于项目中各种资源的简易说明图:

最最后~我啥时候变这么啰嗦了,文中说的“划算”仅仅是在文件系统层面而言的,就是尽可能唯一存储PE文件中的图标数据,减小程序体积。然而在内存层面,上述方法是不是会造成复制多份图标数据,即文件是小了,但运行起来的内存占用可能并不少,这个我没求证,等蛋疼再追求一下内存层面的“划算”。

文毕。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

ASP.NET MVC 4中的单页面应用程序

ASP.NET MVC 4 beta中包含了一个实验项目,用作开发“单页面应用程序(single page applications)”。该项目也称为ASP.N...

2007
来自专栏前端小记

用字蛛动态遍历JS生成中文字体

字蛛 font-spider 通过分析本地 CSS 与 HTML 文件获取 WebFont 中没有使用的字符,并将这些字符数据从字体中删除以实现压缩,同时生成跨...

67627
来自专栏Python小屋

Python实现局域网内屏幕广播的技术要点分析

为更好地保证教学质量和提高学生的学习积极性,我使用Python开发了一套课堂教学管理系统,具有在线点名、在线答疑、随机提问、在线作业管理、在线自测、在线考试、数...

4387
来自专栏微信终端开发团队的专栏

微信iOS9适配总结

每年iOS升级,都会带来一些坑,这次iOS9也不例外。本文总结了微信在适配iOS9上遇到的问题和解决方案。 一、iOS9问题汇总 1. 编译问题(B...

2615
来自专栏破晓之歌

pycharm主题设置 原

File -> Settings -> IDE Settings -> Appearance -> Theme -> 选择主题

5203
来自专栏walterlv - 吕毅的博客

WPF 多线程 UI:设计一个异步加载 UI 的容器

2018-09-08 12:53

2901
来自专栏ionic3+

【Appetite】ionic3实录(六)首页实现

观察之,发布者和内容的文本信息可以用ionic现有的组件实现,而视频播放和图片画廊(如果是轮播图可以用slides组件,它是阉割并封装过的swiper,好像现在...

984
来自专栏java一日一条

高效Android开发者必须知道的4个工具

移动app开发是一个漫长而费力的过程。然而,现在的企业总是希望能够尽快发布app。幸运的是,我们有很多帮助移动开发人员加快工作步伐的工具。

1063
来自专栏逸鹏说道

Pycharm For Linux

之前说过JetBrains系列的破解方式:https://www.cnblogs.com/dunitian/p/8478252.html

1263
来自专栏java一日一条

高效Android开发者必须知道的4个工具

移动app开发是一个漫长而费力的过程。然而,现在的企业总是希望能够尽快发布app。幸运的是,我们有很多帮助移动开发人员加快工作步伐的工具。

1291

扫码关注云+社区

领取腾讯云代金券