在C#中轻松制作仿OutLook的界面
 

2010-01-07 作者:東大傳說 来源:東大傳說不blog

 

不知道从什么时候开始,许多软件都开始模仿OutLook界面,最典型的莫过于大家经常使用的QQ了,在网上搜索了好久,都没有找到几个满意的控件,干脆,自己写了一个,非常简单实用,特拿出来共享。

新建一个项目,不妨取名为MyOutLookFace吧,在上面放一个Panel控件用作容器,取名为:panFunMain,设置Dock属性为Left(或Righ),设置BorderStyle属性为Fixed3D,添加一个ImageList控件,设置其ImageSize为“32,32”,并添加几个图标给它。

在panFunMain中添加n个按钮(本例中n=3,用于显示有几组)和n个ListView控件(显示某组中具体内容),都用其默认的名字,注意ListView控件个数必须和按钮控件个数相同,都为n,设置各ListView控件的Lage imageList属性为刚才添加的ImageList控件,选中第一个ListView控件,在属性窗口中,选择items,并点右边的小按钮“,将弹出一个对话框,在这里添加几个成员,并指定Text属性和ImageIndex属性,同样,为第二、三个ListView指定Items成员。

为了实现自动隐藏,再添加一个计时器.

上面的插操作都是比较基本的,如不特殊说明,都使用其默认值,这里不再赘述。

本文最后还会提到播放声音的方法,为合理利用资源,必须修改文件输出路径,选择菜单“项目”→“属性”,会弹出如下一个对话框,在“配置(C)”后面的组合框中选择“所有配置”,然后设置“配置属性”的“生成”项,在右边的输出路径中填上“output\”,这样,无论是编译成release文件还是debug文件,输出的可执行文件都会放到当前项目中的output文件夹下(该文件会自动创建)。

至此,界面布置基本完成,切换到代码窗口,添加几个变量:

    /// <summary>

    /// 记录当前功能面板中用到的按钮

    /// </summary>

    private ArrayList ArrFunButton=new ArrayList();

     /// <summary>

    /// 记录当前功能面板中用到的listview

    /// </summary>

    private ArrayList ArrFunListView=new ArrayList();

    /// <summary>

    /// 功能面板的宽度

    /// </summary>

    private int m_nPanFunWidth=100;

    //功能面板隐藏后的宽度

    private int m_nPanFunHideWidth=2;

当我们单击一个按钮后,必须显示该按钮对应的ListView,并调整该按钮的位置,故手工写一个函数:

    //功能按钮点击后的特效

    private void btnFun_Click(object sender, System.EventArgs e)

    {

      Button btnNow=sender as Button;

         if(btnNow==null)

              return;

 

         //单击的按钮在数组中的索引

         int nIndex=this.ArrFunButton.IndexOf(btnNow);

         //将该按钮前面的置顶

         for(int i=1;i<=nIndex;i++)

         {

              Button btn=ArrFunButton[i] as Button;

              btn.Top=((Button)ArrFunButton[i-1]).Bottom;

              btn.Anchor=System.Windows.Forms.AnchorStyles.Left |System.Windows.Forms.AnchorStyles.Top;

         }

         //将下面的按钮下移

         for(int i=ArrFunButton.Count-1;i>nIndex;i--)

         {

              Button btn=ArrFunButton[i] as Button;

              if(i==ArrFunButton.Count-1)//最后一个

                  btn.Top=this.panFunMain.Height-btn.Height-4;

              else

                  btn.Top=((Button)ArrFunButton[i+1]).Top-btn.Height;

              btn.Anchor=System.Windows.Forms.AnchorStyles.Left |System.Windows.Forms.AnchorStyles.Bottom;

 

         }

 

         //显示对应的listview

         for(int i=0;i<ArrFunButton.Count;i++)

         {

              ListView lsv=ArrFunListView[i] as ListView;

              //当前按钮对应的ListView

              if(i==nIndex)

               {

                  lsv.Left=0;

                  lsv.Width=btnNow.Width;

                  lsv.Top=btnNow.Bottom;

 

                  if(nIndex==ArrFunListView.Count-1)//最后一个

                       lsv.Height=this.panFunMain.Height-btnNow.Bottom-4;

                  else

                       lsv.Height=(ArrFunButton[i+1] as Button).Top-btnNow.Bottom;

                  //将当前ListView显示出来

                  if(!lsv.Visible)

                       lsv.Visible=true;

             }

              else //隐藏其他listview

              {

                  if(lsv.Visible)

                       lsv.Visible=false;

              }

         }

 

    }

当我们双击ListView的图标时,应用程序会根据你双击的具体项做相应处理,如QQ中弹出“发送消息”的对话框,我们这里只是简单地提示一句你双击的是哪一项,为此,也是手工添加一个函数:

     //双击listview后根据当前项执行操作

    private void lsvFun_DoubleClick(object sender, System.EventArgs e)

    {

         //双击后执行一个功能

         ListView lsv=sender as ListView;

         if(lsv==null)

              return;

         if(lsv.SelectedItems.Count==0)

              return;

         ListViewItem item=lsv.SelectedItems[0];

         MessageBox.Show("你双击了:"+item.Text);

    }

本例中设置自动隐藏功能,隐藏后(宽度为nPanFunHideWidth),如果鼠标在本工具条(也就是本例中的panFunMain中的全部内容)上移动时,重新将工具条显示出来,因此,手工添加一个鼠标移动事件响应函数:

    private void FunListView_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)

    {

        if(this.panFunMain.Width==m_nPanFunHideWidth)

         {

            this.panFunMain.Width=m_nPanFunWidth;

           this.timer1.Enabled=true;

        }

  }

为了达到自动隐藏的目的,我们设置了一个记时器,不断检测当前鼠标位置,如果不在工具条中,自将工具宽带设置为nPanFunHideWidth,起到隐藏的作用,当然,不能设置为0,否则鼠标移不上去就再也显示不出来了。添加计时器的响应代码:

    private void timer1_Tick(object sender, System.EventArgs e)

    {

         //当前功能面板显示出来

         if(this.panFunMain.Width==m_nPanFunWidth)

         {

              //检查光标位置是否在面板内

              Point p1=this.panFunMain.PointToScreen(new Point(0,0));

              Point p2=this.panFunMain.PointToScreen(new Point(panFunMain.Right,panFunMain.Bottom));

              Point pCur=Cursor.Position;//当前鼠标光标位置

              if(pCur.X<p1.X || pCur.X>p2.X || pCur.Y<p1.Y || pCur.Y>p2.Y)

              {

                  //隐藏panfunmain

                  this.panFunMain.Width=m_nPanFunHideWidth;

                  this.timer1.Enabled=false;

              }

         }//if

 }

前面都是准备工作,添加一个函数,将上面的代码同具体的按钮和Listview控件组合起来:

                     /// <summary>

      /// 初始化功能面板

      /// </summary>

      private void InitPanFun()

      {

           //设置功能面板的位置和宽带

           this.panFunMain.Width=m_nPanFunWidth;

           this.panFunMain.Dock=DockStyle.Left;

           //记录功能按钮

           ArrFunButton.Add(this.button1);

           ArrFunButton.Add(this.button2);

            ArrFunButton.Add(this.button3);

 

           //记录功能面板中的listview,注意要和上面的button对应

           ArrFunListView.Add(this.listView1);

           ArrFunListView.Add(this.listView2);

           ArrFunListView.Add(this.listView3);

 

           int nCount=ArrFunButton.Count;

           //布置各功能按钮的位置和ListView的属性

           for(int i=nCount-1;i>=0;i--)

           {

                Button btn=ArrFunButton[i] as Button;

                btn.Width=this.panFunMain.Width-4;

                btn.Left=0;

 

                //将按钮的单击事件和具体代码对应起来

                btn.Click += new System.EventHandler(btnFun_Click);

                if(i==0)

                {

                    btn.Top=0;

                    btn.Anchor=AnchorStyles.Left |AnchorStyles.Top;

                }

                else

                {

                    if(i==nCount-1)

                        btn.Top=this.panFunMain.Height-btn.Height-4;

                    else

                        btn.Top=(ArrFunButton[i+1] as Button).Top-btn.Height;

                       btn.Anchor=AnchorStyles.Left | AnchorStyles.Bottom;

                }

                //鼠标在按钮上移动时,同样判断当前工具条是否隐藏

                btn.MouseMove+=new MouseEventHandler(FunListView_MouseMove);

 

                //设置listview的anchor属性

                ListView lsv=ArrFunListView[i] as ListView;

                if(lsv!=null)

                {

                    lsv.Anchor=AnchorStyles.Left | AnchorStyles.Top |

                         AnchorStyles.Right |AnchorStyles.Bottom;

                    //隐藏功能listview

                    lsv.Visible=false;

                    //设置listview双击事件

                    lsv.DoubleClick+=new EventHandler(lsvFun_DoubleClick);

                    lsv.MouseMove+=new MouseEventHandler(FunListView_MouseMove);

 

                }//pan

           }//for int i

 

           //将第一个功能按钮点一下

           (ArrFunButton[0] as Button).PerformClick();

           //别忘了打开记时器

           this.timer1.Enabled=true;

      }

最后,添加Form1的Load事件响应函数,用来初始化工具条:

      private void Form1_Load(object sender, System.EventArgs e)

      {

           this.InitPanFun();

      }

现在运行一下,效果是不是很不错?单击按钮时,会显示不同的分组,当鼠标离开窗口左边时,工具自动隐藏,在左边移动时,工具自动出现,双击ListView某图标后,会弹出一个对话框,告诉你点了哪一项.

通过设置panFunMain的Dock属性,可以让本工具条在停泊在窗口的左边或右边,本例中代码的通用性较强(当然,如果能做成控件就更好了),很容易复制到新的软件中,上面的自动隐藏是模仿QQ做的,我们还可以做得更象QQ一点,当用户点了分组按钮后,播放一个声音,如果你安装了QQ,将其安装路径中sound文件夹下面的folder.wav声音文件复制到本项目的output文件夹中(也就是本项目EXE文件输出路径中),其中播放/停止声音的代码如下:

                [DllImport("winmm.dll")]

      public static extern long mciSendString(string lpstrCommand,string lpstrReturnString,long length,long hwndcallback);

      /// <summary>

      /// 播放音乐文件

      /// </summary>

      /// <param name="p_FileName">音乐文件名称</param>

      private void PlayMusic(string p_FileName)

      {

           try

           {

                mciSendString(@"close " +p_FileName ,"                                  "/*34个空格 */,0,0);

                mciSendString(@"open " + p_FileName,"                                  "/*34个空格 */,0,0);

                mciSendString(@"play " + p_FileName ,"                                  "/*34个空格 */,0,0);

           }

           catch

           {

           }

 

      }

        

      /// <summary>

      /// 停止当前音乐播放

      /// </summary>

     /// <param name="p_FileName">音乐文件名称</param>

      private void StopMusic(string p_FileName)

      {

           try

           {

                mciSendString(@"close " + p_FileName,"                                  ",0,0);

           }

           catch{}

由于使用了API函数,别忘了在前门添加一个应用:

using System.Runtime.InteropServices;

当然在,为了能播放声音,在private void btnFun_Click(object sender, System.EventArgs e)事件中加入下面两句:

     //播放声音,由于文件路径中可能有空格,因此,文件要用引号引起来

      string strFileName="\""+Application.StartupPath+"\\folder.wav"+"\"";

      this.PlayMusic(strFileName);

再运行一下,是不是更酷了?

火龙果软件/UML软件工程组织致力于提高您的软件工程实践能力,我们不断地吸取业界的宝贵经验,向您提供经过数百家企业验证的有效的工程技术实践经验,同时关注最新的理论进展,帮助您“领跑您所在行业的软件世界”。

资源网站: UML软件工程组织