WinForm多窗体标签--HYAppFrame

本章节主要讲解在WinForm中如何实现多标签页,可通过菜单打开或激活子窗体,并显示标签选项卡效果,单击标签可实现窗体切换,通过关闭按钮可关闭子窗体。效果图如下:

技术分享

 

HYAppFrame项目地址:https://sourceforge.net/projects/hyappframe/

1 实现原理

  • 使用TabControl控件充当标签栏
  • 使用TreeView控件充当菜单导航
  • 窗体Form1设置成窗体容器
  • 创建一个全局数组用于存储已打开窗体列表,再创建一个全局数组用于存储已打开的选项卡窗体名称与选项卡名称一致,用于对应
  • 在每个标签TabPage右上角绘制一个关闭图标,当鼠标单击图标所在区域时,关闭窗体和移出标签

2 实现方法

2.1 定义两个全局数组

// 已打开表单集合
private static ArrayList frmList;
public static ArrayList FrmLsit
{
    get{ return frmList; }
    set{ frmList = value; }
}
// 已打开Tab选项卡
private static ArrayList tabList;
 
public static ArrayList TabList
{
    get{ return tabList; }
    set{ tabList = value; }
}

2.2 打开或激活窗体

打开给定窗体,并将窗体加入到全局数组FrmList

private void showForm(Form frm)
{
   frm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
   frm.MdiParent = this;
   frm.Dock = DockStyle.Fill;
   frm.Show();
   MyFuncLib.FrmLsit.Add(frm);
   MyFuncLib.ActivedFrm = frm;
}

激活给定窗体,并将窗体置于最前。

private void activeForm(Form frm)
{
   frm.Activate();
   frm.Focus();
   frm.BringToFront();
   MyFuncLib.ActivedFrm = frm;
}

打开或激活目标窗体,当给定一个窗体时,首先检查这个窗体是否打开,如果打开则激活它,并设置对应的标签选项卡为选中状态,如果未打开,则打开窗体,并在标签栏中加入窗体标签。窗体和标签选项卡名称要完全一致,否则将无法对应。

private voidOpenOrActiveForm(string name, string text)
{
    // 判断传入的是否是窗体
    if (!isForm)
        return;
    Boolean isOpen = false;
    #region 判断目标窗体是否打开,如果已打开则激活
    foreach (Form frm in MyFuncLib.FrmLsit)
    {
        if (frm.Name.Equals(name))
        {
            isOpen = true;
            foreach (TabPage tabItem inMyFuncLib.TabList)
            {
                if (tabItem.Name.Equals(name))
                    this.tabForms.SelectedTab =tabItem;
            }
            // 激活窗体
            activeForm(frm);
            break;
        }
    }
    #endregion
    #region 如果未曾打开,则打开打开窗体
    if (!isOpen)
    {
        Form frm = null;
        Assembly assembly =Assembly.GetExecutingAssembly();
        frm =assembly.CreateInstance(namespaceString + "." + name) as Form;
        if (frm == null)
        {
            MyFuncLib.msg("未找到指定的程序窗体", "w");
            return;
        }
        frm.Name = name ;
        showForm(frm);// 显示表单
 
        TabPage tabPage = new TabPage();
        tabPage.Name = name;
        tabPage.Text = text;
        this.tabForms.TabPages.Add(tabPage);
        this.tabForms.SelectedTab = tabPage;
        MyFuncLib.TabList.Add(tabPage);
    }
    #endregion
}

2.3 选项卡单击效果

单击标签选项卡时,找到对应的窗体并激活。

private voidtabForms_SelectedIndexChanged(object sender, EventArgs e)
{
    TabPage tab =((TabControl)sender).SelectedTab;
    if (tab == null)
        return;
    foreach (Form frm in MyFuncLib.FrmLsit)
    {
        if (frm.Name.Equals(tab.Name))
        {
            activeForm(frm);
            break;
        }
    }
}

2.4 绘制关闭图标

在TabForms控件DrawItem事件中加入绘制选项卡关闭图标

private void TabForms_DrawItem(object sender,DrawItemEventArgs e)
{
   DrawCloseImage(close16grey, e);
}
 
private void DrawCloseImage(Bitmap image,DrawItemEventArgs e)
{
    try
    {
       // 取得tabPage选项卡矩形区域
       Rectangle rect = this.tabForms.GetTabRect(e.Index);
       #region 设置tabPage选中时的背景颜色
       Color recColor = e.State == DrawItemState.Selected ?Color.FromArgb(214,231,247) : Color.White;
       using (Brush b = new SolidBrush(recColor))
       {
           e.Graphics.FillRectangle(b, rect);
       }
       #endregion
       // 绘制TabPage
       e.Graphics.DrawString(this.tabForms.TabPages[e.Index].Text, this.Font,SystemBrushes.ControlText, rect.X + 2, rect.Y + 2);
 
       #region 按照关闭图标大小画一个矩形区域
       using (Pen p = new Pen(Color.White))
       {
           rect.Offset(rect.Width - (CLOSEIMAGESIZE + 3), 2);
           rect.Width = CLOSEIMAGESIZE;
           rect.Height = CLOSEIMAGESIZE;
           e.Graphics.DrawRectangle(p, rect);
       }
       #endregion
 
       #region 使用图标填充这个区域
       using (Pen objpen = new Pen(Color.Black))
       {
           Bitmap bt = new Bitmap(image);
           Point p5 = new Point(rect.X, 4);
           e.Graphics.DrawImage(bt, p5);
       }
       #endregion
       // 释放资源
       e.Graphics.Dispose();
    }
   catch (Exception)
    { }
}

2.5 关闭按钮功能

在TabForms控件MouseDown事件中加入关闭窗体、移出选项卡的代码,难点在于如何获得鼠标单击坐标,其光标是否在“关闭图标”范围内,如果在则继续执行代码。值得说明的是,这里无法通过tabPage_Click事件达到目的。

private void TabForms_MouseDown(object sender,MouseEventArgs e)
{
    if(e.Button == MouseButtons.Left)
    {
       int x = e.X, y = e.Y;
       //计算关闭区域 
       Rectangle rect = this.tabForms.GetTabRect(this.tabForms.SelectedIndex);
 
       rect.Offset(rect.Width - (CLOSEIMAGESIZE + 3), 2);
       rect.Width = CLOSEIMAGESIZE;
       rect.Height = CLOSEIMAGESIZE;
 
       //如果鼠标在区域内就关闭选项卡 
       bool isClose = x > rect.X && x < rect.Right && y> rect.Y && y < rect.Bottom;
       if (isClose == true)
       {
           #region 移除Form和tab选项卡
           TabPage tab = this.tabForms.SelectedTab;
           // 选择左侧tab选项卡
           if (this.tabForms.SelectedIndex > 1)
               this.tabForms.SelectedIndex = this.tabForms.SelectedIndex - 1;
           this.tabForms.TabPages.Remove(tab);
           foreach (Form frm in MyFuncLib.FrmLsit)
           {
               if (frm.Name.Equals(tab.Name))
               {
                   MyFuncLib.FrmLsit.Remove(frm);
                    frm.Close();
                    break;
               }
           }
           #endregion
           #region 显示当前Form
           foreach (Form frm in MyFuncLib.FrmLsit)
           {
               if (frm.Name.Equals(this.tabForms.SelectedTab.Name))
               {
                    activeForm(frm);
                    break;
               }
           }
           #endregion
       }
    }
}

3 思考题

本章节中如何窗体名称调用窗体实体类?

如何在父窗体中的按钮执行子窗体中的方法?

如何在子窗体中打开另一个子窗体?

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。