导航

[智能设备]SmartPhone开发常用类(三) 自定义菜单(ListView)

Posted on 2005-12-28 21:59  xujh  阅读(1197)  评论(0编辑  收藏  举报

转自微软的例子

using System;
using System.Windows.Forms;
using System.Collections;
using System.Drawing;
using System.Data;
using System.Reflection;

using System.Drawing.Imaging;

namespace SmartUI {
     enum MailIcon {
          unopened,
          opened
     }

     /// <summary>
     /// Class used to store display score info
     /// </summary>
     class MailItem {
          public MailIcon icon;
          public string sender;
          public string subject;

          public MailItem(MailIcon Icon, string Sender, string Subject)
         {
               this.icon = Icon;
               this.sender = Sender;
               this.subject = Subject;
          }
     }

     /// <summary>
     /// Provide a 2 line listview
     /// </summary>
     class MyListView : OwnerDrawnList {
      constint Column1Left  = 5;//条目位图X位置
      const int Column2Left  = 25;//条目文字X位置

      public MyListView() {
           // We need a total of 5 rows, so the height is 180/5=36
           Graphics g = this.CreateGraphics();
           Font font = new Font(this.Font.Name, 10, FontStyle.Bold);
           // Calc line height to be height of letter A plus 10%
           int fontHeight = (int)(g.MeasureString("A", font).Height*1.1);//计算当前字体的高度*1.1作为字体高度
           this.ItemHeight = fontHeight*2; //每一条目为两行汉字,因此为字体高度*2
           g.Dispose();
      }

      //键盘处理流程。上/下键已由基类处理,这里只处理回车键
      protected override void OnKeyDown(KeyEventArgs e) {
           switch(e.KeyCode) {
                case Keys.Return:
                     MessageBox.Show("You selected item " + this.SelectedIndex.ToString(),
                          "Item selected", 
                          MessageBoxButtons.OK,
                          MessageBoxIcon.Asterisk,
                          MessageBoxDefaultButton.Button1);
                 break;
           }

           base.OnKeyDown(e);
      }


      /// <summary>
      /// 自定义绘图事件。绘制ListView的条目
      /// </summary>
      /// <param name="e"></param>
     protected override void OnPaint(PaintEventArgs e) {
   
           // Declare vars
           Font font;
           Color fontColor;
           string bmpName;
   
           // 从控件位图中产生控件绘图区,注:控件位图为控件不含滚动条的可显示区域图像,即条目显示部分
           Graphics gOffScreen = Graphics.FromImage(this.OffScreen);

           //以控件背景色填充绘图区
           gOffScreen.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);

       
           int itemTop = 0;//当前条目的Y坐标

           // 绘制可显示的条目,从滚动条当前位置绘制DrawCount个条目
           for(int n = this.VScrollBar.Value; n < this.VScrollBar.Value + DrawCount; n++) 
            {

    
                //如果该条目为当前选中条目,则要高亮显示
                if(n == this.SelectedIndex) 
                {
                    //用高亮色填出该条目区域
                     gOffScreen.FillRectangle(new SolidBrush(SystemColors.Highlight),
                          0,
                          itemTop,
                          //如果滚动条可显,则要减去滚动条的宽度
                          this.ClientSize.Width - (this.VScrollBar.Visible ? this.VScrollBar.Width : 0),
                          this.ItemHeight);
                         //字体颜色为高亮色的对比色
                         fontColor = CalcTextColor(SystemColors.Highlight);
                }
                else
                     fontColor = this.ForeColor; //否则,字体颜色为控件前景色

            // 用灰色绘制分割线
            gOffScreen.DrawLine(new Pen(Color.DarkGray), 
                 1, 
                 itemTop+this.ItemHeight, 
                 this.ClientSize.Width - (this.VScrollBar.Visible ? this.VScrollBar.Width : 2),
                 itemTop+this.ItemHeight);

            // 取得当前条目
            MailItem lvi = (MailItem)this.Items[n];

            // 设置字体和条目位图
            if (lvi.icon == MailIcon.unopened) { //如果为未开状态,则设置为粗体字
                 font = new Font(this.Font.Name, 10, FontStyle.Bold);
                 bmpName = "SmartUI.unread.bmp";//位图的名称
            }
            else {
                 font = new Font(this.Font.Name, 10, FontStyle.Regular);
                 bmpName = "SmartUI.read.bmp";
            }

            // Load image
                Bitmap bmp = new Bitmap(Assembly.GetExecutingAssembly().GetManifestResourceStream(bmpName));    
    
    
            //设置图片的透明颜色,在本实例中为红色
                ImageAttributes ia = new ImageAttributes();
                ia.SetColorKey(Color.Red, Color.Red);

            //设置位图绘图区域
            Rectangle imgRect = new Rectangle(Column1Left, itemTop+3, bmp.Width, bmp.Height);

            // 绘制条目位图
            gOffScreen.DrawImage(bmp, imgRect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, ia);
            // 绘制条目文字
            gOffScreen.DrawString(lvi.sender, font, new SolidBrush(fontColor), Column2Left, itemTop);
            // 绘制条目文字
            gOffScreen.DrawString(lvi.subject, font, new SolidBrush(fontColor), Column2Left, itemTop + (ItemHeight/2));

            // 清理
            font.Dispose();
            bmp.Dispose();

            // 设置下一个条目的Y位置=当前条目的Y位置+条目高度
            itemTop += this.ItemHeight;
       }

       // 将整个绘图位图绘制到控件上
       e.Graphics.DrawImage(this.OffScreen, 0, 0);

       gOffScreen.Dispose();
      }

      // Draws the external border around the control.    
      protected override void OnPaintBackground(PaintEventArgs e) {
       //   e.Graphics.DrawRectangle(new Pen(Color.Black), 0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1);
      }
     }

    // 基类 OwnerDrawnList
     class OwnerDrawnList : Control {
          int scrollWidth;
          int itemHeight         = -1;
          int selectedIndex      = -1;

          Bitmap offScreen; //控件位图为控件不含滚动条的可显示区域图像,即条目显示部分
          VScrollBar vs; //竖向滚动条
          ArrayList items;//条目数组         
         public OwnerDrawnList() {
               this.vs = new VScrollBar(); //产生滚动条
               scrollWidth = this.vs.Width; //设定滚动条宽度=控件默认宽度
               this.vs.Parent      = this; //滚动条的父窗口为控件
               this.vs.Visible     = false; //不可见
               this.vs.SmallChange = 1; //最小变化量为1
               this.vs.ValueChanged += new EventHandler(this.ScrollValueChanged);//设置滚动变化事件

               // Items to draw
               this.items = new ArrayList();//产生Item数组
          }
          /// <summary>
          /// 条目数组
          /// </summary>
          public ArrayList Items {
               get { return this.items;}
          }
        /// <summary>
        /// 控件位图
        /// </summary>

          protected Bitmap OffScreen {
               get {return this.offScreen;}
          }
          /// <summary>
          /// 控件滚动条
          /// </summary>

          protected VScrollBar VScrollBar {
               get {return this.vs;}
          }
          /// <summary>
          /// 选中条目索引改变事件
          /// </summary>
          public event EventHandler SelectedIndexChanged;

          // Raise the SelectedIndexChanged event
          protected virtual void OnSelectedIndexChanged(EventArgs e) {
               if(this.SelectedIndexChanged != null) //如果设置了选中Item变化的事件,则执行
                this.SelectedIndexChanged(this, e);
          }

          // 获取或设置当前选中项目索引
          public int SelectedIndex {
               get {return this.selectedIndex;} //返回索引              
              set {
                        this.selectedIndex = value; //设置新索引值,并调用索引改变事件
                        if (this.SelectedIndexChanged != null)
                         this.SelectedIndexChanged(this, EventArgs.Empty);
                   }
          }

          protected void ScrollValueChanged(object o, EventArgs e) {
               this.Refresh();
          }

          protected virtual int ItemHeight {
               get {return this.itemHeight;}
               set {this.itemHeight = value;}
          }

          // If the requested index is before the first visible index then set the
          // first item to be the requested index. If it is after the last visible
          // index, then set the last visible index to be the requested index.
          public void EnsureVisible(int index) {//计算滚动条的当前位置
               if(index < this.vs.Value) {//如果新位置<原有滚动条位置
                    this.vs.Value = index;
                    this.Refresh();
               }
               else if(index >= this.vs.Value + this.DrawCount) {
                    this.vs.Value = index - this.DrawCount + 1;
                    this.Refresh();
               }
          }

          // 键盘事件,处理上下键 
         protected override void OnKeyDown(KeyEventArgs e) {
               switch(e.KeyCode) {
                    case Keys.Down: //Down键时,如果当前选中索引<滚动条的最大值,则当前选中索引+1,并显
                         if(this.SelectedIndex < this.vs.Maximum) {
                              EnsureVisible(++this.SelectedIndex);
                              this.Refresh();
                         }
                         break;
                    case Keys.Up://Up键时,如果当前选中索引>滚动条的最小值,则当前选中索引-1,并显示
                         if(this.SelectedIndex > this.vs.Minimum) {
                              EnsureVisible(--this.SelectedIndex);
                              this.Refresh();
                         }
                         break;
               }

               base.OnKeyDown(e); //调用基类的键盘事件
          }

          //计算实际需要绘制条目数量
          protected int DrawCount {
               get {
                    if(this.vs.Value + this.vs.LargeChange > this.vs.Maximum)//如果从当前位置到最尾+可显示最大栏目数量>总栏目数量
                         return this.vs.Maximum - this.vs.Value + 1; //返回实际栏目数量
                    else
                     return this.vs.LargeChange; //否则,返回可显示最大栏目数量
               }
          }
        //控件尺寸调整事件
         protected override void OnResize(EventArgs e) {
               int viewableItemCount = this.ClientSize.Height / this.ItemHeight; //可显示栏目数量=控件高度/条目高度                   
                this.vs.Bounds = new Rectangle(this.ClientSize.Width - scrollWidth,//重新调整滚动条大小
                    0,
                    scrollWidth,
                    this.ClientSize.Height);

                //重新计算控件位图的大小
               //判断是否需要滚动条

           if(this.items.Count > viewableItemCount) { //如果条目数大于可显示条目数,则显示滚动条,并把滚动条最大变化量设置为可显示条目数
                    this.vs.Visible = true;
                    this.vs.LargeChange = viewableItemCount;
                    //产生一个控件可显示区位图
                    //宽度=控件宽度-滚动条宽度
                    //高度=控件高度
                    this.offScreen = new Bitmap(this.ClientSize.Width - scrollWidth, this.ClientSize.Height);
            }
           else { //如果不需要滚动条
                    this.vs.Visible = false;
                    this.vs.LargeChange = this.items.Count;
                    //产生一个控件可显示区位图
                    this.offScreen = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
           }

           this.vs.Maximum = this.items.Count - 1; //计算滚动条的最大值=条目个数-1
      }

     //决定什么颜色作为高亮选中条目的字体颜色
      protected Color CalcTextColor(Color backgroundColor) {
           if(backgroundColor.Equals(Color.Empty)) 
                return Color.Black;  //如果背景颜色为空,则返回黑色

           int sum = backgroundColor.R + backgroundColor.G + backgroundColor.B;

           if(sum > 256) //如果红绿蓝颜色大于256,则返回黑色
                return Color.Black;
           else
                return Color.White; //否则返回白色
      }

     }
}
----------------------------------------------------------------------------------------------------------------------------------------------

调用方法
public CustomListView()
  {
   //
   // Required for Windows Form Designer support
   //
   InitializeComponent();

   //
   // TODO: Add any constructor code after InitializeComponent call
   //
   
   olv = new MyListView();
   olv.Parent = this;
   // Set the bounds of the listview.
   olv.Bounds = new Rectangle(0,0, this.ClientSize.Width, this.ClientSize.Height);

   // Add data items to listview
   for (int i=0; i<10; i++) {
    olv.Items.Add(new MailItem(MailIcon.unopened, "James Pratt", "re: Custom ListView"));
    olv.Items.Add(new MailItem(MailIcon.opened, "Chung Webster", "Custom ListView"));
   }

   olv.SelectedIndex = 0;
   olv.EnsureVisible(olv.SelectedIndex);
   
  }