为ListView动态组合图标

ListView动态组合图标

浙江省丽水市汽车运输集团有限公司信息中心 苟安廷

注:本文代码请到ftp://202.107.251.26/上下载

 

我们先来看一组大家很熟悉的图标:

很显然,这是表示网络状态的一组图标,第一个表示正常状态,第二个表示禁用状态,后面的四个图标是在前面两个的基础上增加了断开、有防火墙或者既断开又有防火墙的几种附加状态,通常,我们用ListView控件来表示这类状态。

图中可以看出,共有两种基本状态:正常和禁用,两种附加状态,有防火墙和断开,所有的状态都是由基本状态和附加状态组合而成的。如何实现呢?你可以参照上图准备六个图标,并根据不同的状态选择显示不同的图标,但这是比较简单的情况,以宾馆客房为例,通常有空房、维修、入住、预留、脏房等m种基本状态,以及预订、有食品、叫醒等n种附加状态,那么你要准备多少个图标呢?(m+1)×n个?不对,因为许多附加状态是同时出现的,如上图中断开且有防火墙,这时,最理想的办法就是准备m个基本图标,n个附加图标,然后根据实际需要动态组合起来,但ListView本身并不支持动态图标的组合,本文就讨论如何实现这一设想,希望对有类似需求的朋友提供一些思路。

打开VS2005,新建一个C#windows项目,不妨取名为DyIconForListView吧,在窗口上放一个ListView控件(为简化叙述,我们都使用默认的控件名),设置其View属性为LargIcon,再放两个ImageList控件,imageList1的图象大小属性ImageSize=40×40,表示基本状态,因此图标要大一些,imageList2的图象大小属性ImageSize=12×12,表示基本附加状态,因此,图标小一些,并将listView1LargImageList设置为imagaList1SmallImageList不用设置,imageList2是组合用的。通过截取屏幕等方法准备两个40×40的位图,一个表示网络正常状态,一个表示禁用状态,并添加到imageList1中,再准备两个12×12的小位图,一个为表示断开的“×”图标,一个为表示有防火墙的“锁”图标,并添加到imageList2中。

为了显示各种状态,我们还必须增加一些其他控件。在窗口上放一个ListBox 控件,用来选择当前使用哪一种基本状态,放一个CheckListBox控件,用来选择当前使用哪几种附加状态,当然,还要放一个Button控件,用来将设置的状态显示出来,为了不太难看,将Button1Text属性改为“设置”吧,布置好后,界面如下:

切换到代码窗口中,增加引用:

using System.Collections;

增加两个枚举,用来表示基本状态和附加状态的名称,注意,对于附加状态,每一种状态用字节中的一个位表示,由于附加状态图标通常是放在基本图标的四个角落上的,也就是说通常不会超过四种,最多再加上四个边,共八种附加图标,但这样一来,基本图标就被挡得看不清楚了,实际上也用不到这么多附加状态。

        private enum BaseStateNames

        {

            正常 = 0, 禁用 = 1

        }

        private enum AttachStateNames

        {

            断开=1,             //二进制的00000001

            有防火墙=2          //二进制的00000010

            //如果有其他附加状态依此类推

            //第三种状态=4      //二进制的00000100

   }

编写Load事件,为ListView增加一个Item,用于显示设置的结果,并将基本状态和附加状态的名称显示在ListBoxCheckListBox控件中供选择:

        private void Form1_Load(object sender, EventArgs e)

        {

            ListViewItem item = new ListViewItem("本地连接");

            this.listView1.Items.Add(item);

 

            this.listBox1.Items.AddRange(Enum.GetNames(typeof(BaseStateNames)));

            this.checkedListBox1.Items.AddRange(Enum.GetNames(typeof(AttachStateNames)));

        }

编写一个函数,将一个基本位图(不是图标)和一个附加的位图组合而成一个新的位图,用于动态组合:

      /// <summary>

        /// 将两个位图组合,得到一个新的位图

        /// </summary>

        /// <param name="p_BaseBmp">基本位图</param>

        /// <param name="p_AttachBmp">附加位图</param>

        /// <param name="p_Align">附加位图放在基本位图的位置</param>

        /// <returns>生成的新位图</returns>

        private Bitmap AttachBmp(Bitmap p_BaseBmp, Bitmap p_AttachBmp, System.Drawing.ContentAlignment p_Align)

        {

//附加位图的起始坐标,默认放在左上角,因此为0,0

            int nX = 0, nY = 0;

            if (p_Align == ContentAlignment.BottomLeft)

                nY = p_BaseBmp.Height - p_AttachBmp.Height;

            else if (p_Align == ContentAlignment.BottomRight)

            {

                nX = p_BaseBmp.Width - p_AttachBmp.Width;

                nY = p_BaseBmp.Height - p_AttachBmp.Height;

            }

            else if (p_Align == ContentAlignment.TopRight)

            {

                nX = p_BaseBmp.Width - p_AttachBmp.Width;

            }

            //你还可以将附加位图放在其他位置,如四个边上,处理方法类似上面的代码

 

//将附加位图的逐点取出来,写到基本位图上

            for (int i = 0; i < p_AttachBmp.Height; i++)

            {

                for (int j = 0; j < p_AttachBmp.Width; j++)

                {

                    Color cr = p_AttachBmp.GetPixel(j, i);

                    //忽略白色背景,当然,你也可以指定为其他颜色,或者不忽略

                    if (cr.ToArgb() != Color.White.ToArgb())

                        p_BaseBmp.SetPixel(nX + j, nY + i, p_AttachBmp.GetPixel(j, i));

                }

            }

            return p_BaseBmp;

        }

 

新建一个嵌套的类,表示组合后图标的信息:

        internal class AttachIcon

        {

            /// <summary>

            /// 基本图标索引

            /// </summary>

            public int BaseImagIndex = 0;

            /// <summary>

            /// 组合状态

            /// </summary>

            public int Tag = 0;

            /// <summary>

            /// 组合后图标在ImageList1中的的索引

            /// </summary>

            public int NewImagIndex = 0;

        }

编写一个数组,用于存放原基本图标和组合后产生的图标信息:

ArrayList m_ArrAttachIcon = new ArrayList();

 

再编写一个函数,根据基本状态的和附加状态的组合产生新的图标,并返回新图标的索引,注意,是附加状态的组合,如果没有附加状态,则组合状态为0,第一种附加状态为二进制的0000 0001,第二种状态为二进制的0000 0010,因此,如果是第一、第二两种附加状态组合,则为0000 0011

/// <summary>

        /// 根据基本状态和附加状态,返回ImageIndex,如果是基本状态,直接返回,

        /// 否则,将基本状态图标+附加的图标,生成一个新的图标,添加的ImageList中去,

        /// 并返回新的索引

        /// </summary>

        /// <param name="p_BaseImageIndex">基本状态索引</param>

        /// <param name="p_Stat">附加状态的组合</param>

        /// <returns>最终图标的索引</returns>

        private int GetImageIndex(int p_BaseImageIndex, int p_Stat)

        {

            if (p_Stat == 0)

                return p_BaseImageIndex;

            //查看是已经生成了组合图标,如果有,直接返回索引

            foreach (AttachIcon att in m_ArrAttachIcon)

            {

                if ((att.BaseImagIndex == p_BaseImageIndex) && (att.Tag == p_Stat))

                    return att.NewImagIndex;

            }

            //重新组合一个出来,首先得到基本图标

            Bitmap bmpBase = (Bitmap)this.imageList1.Images[p_BaseImageIndex].Clone();

            //再根据附加图状态组合新的图标

            if ((p_Stat & ((int)AttachStateNames.断开)) > 0)

            {

                bmpBase = AttachBmp(bmpBase, (Bitmap)this.imageList2.Images[0].Clone(), System.Drawing.ContentAlignment.TopLeft);

            }

            if ((p_Stat & ((int)AttachStateNames.有防火墙)) > 0)

            {

                bmpBase = AttachBmp(bmpBase, (Bitmap)this.imageList2.Images[1].Clone(), System.Drawing.ContentAlignment.TopRight);

            }

 

            //将新组合而成的图标加入的ImageList1和数组中去

            int nIndex = this.imageList1.Images.Count;

            this.imageList1.Images.Add(bmpBase);

 

            AttachIcon newatt = new AttachIcon();

            newatt.BaseImagIndex = p_BaseImageIndex;

            newatt.Tag = p_Stat;

            newatt.NewImagIndex = nIndex;

            this.m_ArrAttachIcon.Add(newatt);

 

            return nIndex;

        }

到此,准备工作完成了,下面我们通过Button1Click事件实现:

private void button1_Click(object sender, EventArgs e)

        {

            //得到基本图标索引

            int nBaseIndex = this.listBox1.SelectedIndex;

            if (nBaseIndex < 0)

            {

                MessageBox.Show("请选择基本状态!");

                return;

            }

 

            //得到附加状态的组合

            int nAttachTags = 0;

            foreach (string strAttachName in this.checkedListBox1.CheckedItems)

            {

                if (strAttachName == AttachStateNames.断开.ToString())

                    nAttachTags |= (int)AttachStateNames.断开;

                else if(strAttachName == AttachStateNames.有防火墙.ToString())

                    nAttachTags |= (int)AttachStateNames.有防火墙;

            }

 

            int nImageIndex = GetImageIndex(nBaseIndex, nAttachTags);

            if (nImageIndex > -1)

                this.listView1.Items[0].ImageIndex = nImageIndex;

},

运行效果如下:

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值