• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Just do it!
去想,去做,去努力,去奋斗,自己的未来是由自己改变的.
博客园    首页    新随笔    联系   管理    订阅  订阅
基于.NET CompactFramework的九宫格控件(附源码)
一个用c#写的九宫格控件(附图)
      在网上经常看见有人询问Windows Mobile下的九宫格控件的做法,我曾经也多次上网搜索,但找到的大部分都是c++版本的,于是萌发了自己写一个的念头,先上图片。

     

     选中后。

    
    
选中的效果其实是两张图片的交替结果,因为只针对了240×320这种样式,所以可能很多地方写死了,下面对部分源码的解析。

先定义一个继承自Control的类FlexStartMenu

   public class FlexStartMenu : System.Windows.Forms.Control

定义一个选项子类,因为这个控件中的图片中包含文字,因此我没有将子项的文字画到控件当中去,如果你们有需求的话可以修改OnPain事件,添加一个画文字的方法。

子项类
 public class FlexStartItem
    
{
        
/**//// <summary>
        
/// 显示文本
        
/// </summary>

        public string ItemText
        
{
            
get;
            
set;
        }

        
/**//// <summary>
        
/// 选项图片
        
/// </summary>

        public Image Icon
        
{
            
get;
            
set;
        }

        
/**//// <summary>
        
/// 选中时的图片
        
/// </summary>

        public Image PressIcon
        
{
            
get;
            
set;
        }

        
/**//// <summary>
        
/// 选项距离顶部的距离
        
/// </summary>

        public int Top
        
{
            
get;
            
set;
        }

        
/**//// <summary>
        
/// 选项距离左边栏的距离
        
/// </summary>

        public int Left
        
{
            
get;
            
set;
        }

        
/**//// <summary>
        
/// 选项编号
        
/// </summary>

        public int Index
        
{
            
get;
            
set;
        }

        
/**//// <summary>
        
/// 是否被选中
        
/// </summary>

        public bool Press
        
{
            
get;
            
set;
        }

    }

用泛型的方法,比数组的方式效率要高多了,原先我是采用数组的方式,但在两百条数据的加载效率差得非常明显,具体的时间我没有去测试过,但可以肯定的是装箱拆箱这一步能跳过去的就尽量跳过去。

FlexStartItemCollections
    public class FlexStartItemCollections : CollectionBase
    
{
        
public void Remove(FlexStartItem value)
        
{
            List.Remove(value);
        }

        
public bool Contains(FlexStartItem value)
        
{
            
return (List.Contains(value));
        }

        
public void Insert(int index, FlexStartItem value)
        
{
            List.Insert(index, value);
        }

        
public int IndexOf(FlexStartItem value)
        
{
            
return (List.IndexOf(value));
        }

        
public int Add(FlexStartItem value)
        
{
            
return (List.Add(value));
        }

        
public FlexStartItem this[int index]
        
{
            
get { return (FlexStartItem)List[index]; }
            
set { List[index] = value; }
        }

    }

核心部分来了:

核心部分
    public class FlexStartMenu : System.Windows.Forms.Control
    
{
        
public FlexStartMenu()
        
{
            
this.Items = new FlexStartItemCollections();
        }

        
public FlexStartItemCollections Items
        
{
            
get;
            
set;
        }

        
/**//// <summary>
        
/// 被选中的项
        
/// </summary>

        public FlexStartItem SelectedItem
        
{
            
get
            
{
                FlexStartItem m_item 
= null;
                
for (int i = 0; i < this.Items.Count; i++)
                
{
                    
if (Items[i].Press == true)
                    
{
                        m_item 
= Items[i];
                        
break;
                    }

                }

                
return m_item;
            }

        }

        
//定义一个Bitmap变量用双缓冲的方式防止闪烁
        protected Bitmap backBuffer;
        
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        
{
            
if (backBuffer != null)
            
{
                Graphics gOffScreen 
= Graphics.FromImage(backBuffer);
                gOffScreen.Clear(
this.BackColor);
                
for (int i = 0; i < this.Items.Count; i++)
                
{
                    DrawItem(
this.Items[i], i, gOffScreen);
                }

                e.Graphics.DrawImage(backBuffer, 
0, 0);
            }

            
else
                e.Graphics.Clear(
this.BackColor);
        }

        
protected override void OnResize(EventArgs e)
        
{
            
base.OnResize(e);
            
if (backBuffer != null)
                backBuffer.Dispose();
            backBuffer 
= new Bitmap(this.Width, this.Height, PixelFormat.Format32bppRgb);
        }

        
private void DrawItem(FlexStartItem m_item, int index, Graphics gOffScreen)
        
{
            m_item.Index 
= index + 1;
            TopAndLeft(m_item);
            Bitmap bmp 
= null;
            
//选中时的图片
            if (m_item.Press && m_item.PressIcon != null)
                bmp 
= new Bitmap(m_item.PressIcon);
            
else
                bmp 
= new Bitmap(m_item.Icon);
            ImageAttributes ia 
= new ImageAttributes();
            ia.SetColorKey(bmp.GetPixel(
0, 0), bmp.GetPixel(0, 0));
            Rectangle imgRect 
= new Rectangle(m_item.Left * 11 / 12 + this.Width / 12, m_item.Top * 11 / 12 + this.Height / 12, bmp.Width, bmp.Height);
            gOffScreen.DrawImage(bmp, imgRect, 
0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, ia);
            bmp.Dispose();
        }

        
private void DynamicIcon()
        
{
            Timer m_timer 
= new Timer();
            m_timer.Interval 
= 1000;
            m_timer.Tick 
+= new EventHandler(ChangeIcon);
        }

        
private void ChangeIcon(object sender, EventArgs e)
        
{

        }

        
/**//// <summary>
        
/// 捕获点击动作
        
/// </summary>
        
/// <param name="e"></param>

        protected override void OnMouseDown(MouseEventArgs e)
        
{
            
for (int i = 0; i < this.Items.Count; i++)
            
{
                Rectangle itemRec 
= new Rectangle(this.Items[i].Left, this.Items[i].Top, this.Width / 3, this.Height / 3);
                
if (itemRec.Contains(e.X, e.Y))
                
{
                    
this.Items[i].Press = true;
                    
for (int j = 0; j < this.Items.Count; j++)
                    
{
                        
if (j != i)
                        
{
                            
this.Items[j].Press = false;
                        }

                    }

                    
this.Invalidate();
                    
break;
                }

            }

            
base.OnMouseDown(e);
        }

        
/**//// <summary>
        
/// 计算九宫格的长宽高
        
/// </summary>
        
/// <param name="m_item"></param>

        private void TopAndLeft(FlexStartItem m_item)
        
{
            
if ((double)m_item.Index / 3 > 2)
                m_item.Top 
= this.Height * 2 / 3;
            
else if ((double)m_item.Index / 3 > 1)
                m_item.Top 
= this.Height / 3;
            
else
                m_item.Top 
= 0;
            
if (m_item.Index % 3 == 0 && m_item.Index != 1)
                m_item.Left 
= this.Width * 2 / 3;
            
else if (m_item.Index == 2 || m_item.Index == 5 || m_item.Index == 8)
                m_item.Left 
= this.Width / 3;
            
else
                m_item.Left 
= 0;
        }

        
protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
        
{
            
// base.OnPaintBackground(e);
            
//e.Graphics.DrawRectangle(new Pen(Color.Black), 0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1);
        }

        
/**//// <summary>
        
/// 改变按键移动时选项的选中情况
        
/// </summary>
        
/// <param name="e"></param>

        protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e)
        
{
            
if (SelectedItem != null)
            
{
                
int index = SelectedItem.Index - 1;
                
switch (e.KeyCode)
                
{
                    
case Keys.Down:
                        
if (SelectedItem.Index > 6)
                        
{
                            
this.SelectedItem.Press = false;
                            
this.Items[index - 6].Press = true;
                            
this.Invalidate();
                        }

                        
else
                        
{
                            
this.SelectedItem.Press = false;
                            
this.Items[index + 3].Press = true;
                            
this.Invalidate();
                        }

                        
break;
                    
case Keys.Up:
                        
if (SelectedItem.Index <= 3)
                        
{
                            
this.SelectedItem.Press = false;
                            
this.Items[index + 6].Press = true;
                            
this.Invalidate();
                        }

                        
else
                        
{
                            
this.SelectedItem.Press = false;
                            
this.Items[index - 3].Press = true;
                            
this.Invalidate();
                        }

                        
break;
                    
case Keys.Left:
                        
if (SelectedItem.Index ==1)
                        
{
                            
this.SelectedItem.Press = false;
                            
this.Items[8].Press = true;
                            
this.Invalidate();
                        }

                        
else
                        
{
                            
this.SelectedItem.Press = false;
                            
this.Items[index - 1].Press = true;
                            
this.Invalidate();
                        }

                        
break;
                    
case Keys.Right:
                        
if (SelectedItem.Index == 9)
                        
{
                            
this.SelectedItem.Press = false;
                            
this.Items[0].Press = true;
                            
this.Invalidate();
                        }

                        
else
                        
{
                            
this.SelectedItem.Press = false;
                            
this.Items[index + 1].Press = true;
                            
this.Invalidate();
                        }

                        
break;
                    
case Keys.Enter:
                        
this.OnClick(e);
                        
break;
                }

                
/**/////以上只针对九个图标的,下面针对两个活动图标
                //if (e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
                
//{
                
//    if (SelectedItem.Index == 1)
                
//    {
                
//        this.SelectedItem.Press = false;
                
//        this.Items[1].Press = true;

                
//    }
                
//    else
                
//    {
                
//        this.SelectedItem.Press = false;
                
//        this.Items[0].Press = true;
                
//    }
                
//    this.Invalidate();
                
//}
                
//else if (e.KeyCode == Keys.Enter)
                
//{
                
//    this.OnClick(e);
                
//}
            }

            
else
            
{
                
this.Items[0].Press = true;
                
this.Invalidate();
            }

            
base.OnKeyDown(e);
        }

    }

可能未接触过GDI编程或许看得有点晕(我当初就是这样),建议可以先运行代码,然后变化属性先熟悉控件,然后再修改一些数值来看控件的变化,这样的体会深很多。

前台部分:绑定的过程是很简单的,先定义一组显示的图片和选中后的图片,我是用Imagelist来加载图片的,其实也可以选择不嵌入到程序中的方式,用读取路径的方式。

            for (int i = 0; i <= 8; i++)
            
{
                FlexStartItem m_item 
= new FlexStartItem();
                m_item.Icon 
= imgDefautIcon.Images[i];
                m_item.PressIcon 
= imgPressedIcon.Images[i];
                FlexMenu.Items.Add(m_item);
            }

编后语:贴代码的方式赘述了一个九宫格控件的制作,其实这个控件可以衍生为一个数据列表控件,就像自定义一个双层文本的ListView一样(我就是这么做的),麻雀虽小,五脏俱全,小小的一个控件或许也能有变大的一天。

 

更新(2008.07.31):有很多朋友给我发MSN说在控件VS2005下编译会出错,Sorry,我没有声明清楚,这个控件我是在vs2008下编写的,用到了.NET CF 3.5的新特性属性设置器,所以很多属性的地方都编译不过去,所以我重新整理了下,针对.NET CF 2.0版本下的源码供大家下载。

 

附:控件源码下载(.NET CF 3.5)

           源码下载(.NET CF 2.0)

posted on 2008-07-15 10:44  JustDI  阅读(4474)  评论(56)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3