zoukankan      html  css  js  c++  java
  • 在winform下实现左右布局多窗口界面的方法(一)

    在web页面上我们可以通过frameset,iframe嵌套框架很容易实现各种导航+内容的布局界面,而在winform、WPF中实现其实也很容易,通过本文给大家介绍在winform下实现左右布局多窗口界面的方法,本文介绍的非常详细,对winform布局相关知识感兴趣的朋友一起学习吧
    在web页面上我们可以通过frameset,iframe嵌套框架很容易实现各种导航+内容的布局界面,而在winform、WPF中实现其实也很容易,我这里就分享一个:在winform下实现左右布局多窗口界面。

    我这里说的多窗口是指一个父窗口包含多个子窗口,在winform中实现这种效果很简单,即将某个窗口的IsMdiContainer设为true,然后将其它子窗口的MdiParent设为其父窗口对象即可,这样就完成了一个多窗口界面,效果如下:

    点击NEW新打开一个窗口,其效果如下:

    请看我上图红色标注的地方,Windows菜单项下面显示的是当前所有已打开的子窗口,点击某个菜单,即可快速切换到其它窗口,若关闭某个子窗口,与之相对应的菜单项也会自动被移除,实现这个功能也很简单,只需要将菜单的MdiWindowListItem属性设为需要显示活动窗口列表的菜单项即可,例如:上图中我想让Windows菜单显示所有打开的窗口列表,而Windows菜单的(name)属性是windowsToolStripMenuItem,所以只需要如下代码,就可以让Windows菜单显示打开的窗口列表。

    this.menuStrip1.MdiWindowListItem = this.windowsToolStripMenuItem;    //让windowsToolStripMenuItem菜单对象显示窗口列表

    上述示例完整的实现代码如下:

    public partial class FormMdi : Form
    {
    private int formCount = 0;
    public FormMdi()
    {
    InitializeComponent();
    this.menuStrip1.MdiWindowListItem = this.windowsToolStripMenuItem;
    }
    private void newToolStripMenuItem_Click(object sender, EventArgs e)
    {
    ShowChildForm<FormChild>();
    }
    private void ShowChildForm<TForm>() where TForm : Form, new()
    {
    TForm childForm = new TForm();
    childForm.Name = "frm" + Guid.NewGuid().ToString("N");
    childForm.Text = string.Format("Child Form -{0}", ++formCount);
    childForm.MdiParent = this;
    childForm.WindowState = FormWindowState.Maximized;
    childForm.Show();
    }
    }

    相信实现上面这部份功能一般用过winform的人都会操作,我这里就当是复习顺便给新手一个参考,同时也为下面要实现的左右布局功能做一个铺垫吧。

    要实现左右布局,并且能够支持可动态调整左右占比的功能,非SplitContainer控件莫属了,如果不了解该控件用法请自行在网上查找相关资料,我这里就不作说明,如果要显示WINDOWS已打开的子窗口情况,同样也需要用到MenuStrip控件,

    最终设计的主窗口(FormMain)效果如下:

    我这里因为只是演示,所以菜单控件上我只添加了两个菜单项,分别为:WINDOWS,用于显示WINDOWS已打开的子窗口列表,NEW,用于打开一个子窗口;SplitContainer控件全部采用默认的,没有放置任何控件在其中,如果用在正式系统中,一般左边Panel1中会放置一个树形菜单,右边Panel2中保持空即可,因为这个是用来作为子窗口的容器。

    控件层次结构如下图示:

    界面设计好了,下面就实现最重要的两个功能。

    第一个功能:在右边Panel2中显示子窗口,实现代码如下:

    public FormMain()
    {
    this.IsMdiContainer = true;
    }
    private void ShowChildForm<TForm>() where TForm : Form, new()
    {
    TForm childForm = new TForm();
    childForm.Name = "frm" + Guid.NewGuid().ToString("N");
    childForm.Text = string.Format("Child Form -{0}", ++formCount);
    childForm.MdiParent = this;
    childForm.Parent = splitContainer1.Panel2;
    childForm.WindowState = FormWindowState.Maximized;
    childForm.Show();
    }

    简要说明:

    1.在窗口构造函数中动态的将IsMdiContainer设为true,当然也可以设计视图中设置;

    2.编写一个显示写子窗口的方法,方法中需注意的地方:childForm.MdiParent = this;childForm.Parent = splitContainer1.Panel2,意思是:将当前窗口作为子窗口的父窗口,同时将Panel2指定为子窗口的父对象,这样就能实现子窗口在Panel2中打开了。

    第二个功能:在WINDOWS菜单项下显示已打开的子窗口列表,这里实现就没有像文章一开始介绍的那样简单,使用那个方法是无效的,需要我们来自行实现,稍微有点复杂,但如果明白其实现原理,也就简单明白了。

    实现思路:当childForm加载到Panel2时,会触发Panel2.ControlAdded事件,当childForm被关闭时,会触发Panel2.ControlRemoved事件,我们可以统一订阅这两个事件,当childForm加载时,那么就在WINDOWS菜单项下增加一个菜单项,反之则移除该菜单项,实现代码如下:

    this.splitContainer1.Panel2.ControlAdded += Panel2_ControlChanged;
    this.splitContainer1.Panel2.ControlRemoved += Panel2_ControlChanged;
    void Panel2_ControlChanged(object sender, ControlEventArgs e)
    {
    var frm = e.Control as Form;
    string menuName = "menu_" + frm.Name;
    bool exists = this.splitContainer1.Panel2.Controls.Contains(frm);
    if (exists)
    {
    var menuItem = GetMenuItem(menuName);
    if (menuItem != null)
    {
    menuItem.Checked = true;
    frm.BringToFront();
    frm.Focus();
    }
    else
    {
    windowsToolStripMenuItem.DropDownItems.Add(new ToolStripMenuItem() { Text = frm.Text, Name = menuName, Tag = frm, Checked = true });
    }
    }
    else
    {
    var menuItem = GetMenuItem(menuName);
    if (menuItem != null)
    {
    windowsToolStripMenuItem.DropDownItems.Remove(menuItem);
    menuItem.Dispose();
    }
    }
    }
    private ToolStripMenuItem GetMenuItem(string menuName)
    {
    var menuItems = windowsToolStripMenuItem.DropDownItems.Cast<ToolStripMenuItem>();
    menuItems.ToList().ForEach(m => m.Checked = false);
    return menuItems.Where(m => m.Name == menuName).SingleOrDefault();
    }

    同时为了实现点击WINDOWS菜单项的子菜单能够快速切换子窗口,需要订阅WINDOWS菜单项的DropDownItemClicked事件,当然也可以为新增的子菜单项订阅Click事件,实现代码如下:

    windowsToolStripMenuItem.DropDownItemClicked += windowsToolStripMenuItem_DropDownItemClicked;
    void windowsToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
    {
    var menuItem = GetMenuItem(e.ClickedItem.Name);
    menuItem.Checked = true;
    var childForm = menuItem.Tag as Form;
    childForm.BringToFront();
    childForm.Focus();
    }
    private void CheckWindowsMenuItem(string menuName)
    {
    var menuItem = GetMenuItem(menuName);
    if (menuItem != null)
    {
    menuItem.Checked = true;
    }
    } 

    这样就基本实现了在WINDOWS菜单项下显示已打开的子窗口列表,并点击指定的菜单项能够切换当前活动的子窗口,但仍有一个不足的地方,那就是,当直接点击子窗口来切换当前活动窗口时(说白了就是当点击某个子窗口标题栏,该窗口就显示在其它所有的子窗口最前面),WINDOWS菜单项下的子菜单勾选项没有同步更新,一开始想到的是用Activated事件来进行处理,结果经测试发现有效,该Activated事件在点击子窗口标题栏时并不会被触发,所以只能换种方法,经过多次测试,发现当窗口从后面切换到前面时(称为Z顺序改变),子窗口就会发生重绘,从而触发Paint方法,我们可以订阅该事件,并进行处理,实现代码如下:

    private string currentChildFormName = null; //记录当前活动子窗口名称
    childForm.Paint += (s, e) => { 
    var frm=s as Form;
    if (!frm.Name.Equals(currentChildFormName) && this.splitContainer1.Panel2.Controls[0].Equals(frm)) //当容器中第一个控件就是当前的窗口,则表明该窗口处于所有窗口之上
    {
    CheckWindowsMenuItem("menu_" + frm.Name);
    currentChildFormName = frm.Name;
    }
    }; 

    最后贴出完整的实现代码:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    namespace WindowsFormsApplication1
    {
    public partial class FormMain : Form
    {
    private int formCount = 0;
    private string currentChildFormName = null;
    public FormMain()
    {
    InitializeComponent();
    this.IsMdiContainer = true;
    this.splitContainer1.Panel2.ControlAdded += Panel2_ControlChanged;
    this.splitContainer1.Panel2.ControlRemoved += Panel2_ControlChanged;
    windowsToolStripMenuItem.DropDownItemClicked += windowsToolStripMenuItem_DropDownItemClicked;
    }
    void windowsToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
    {
    var menuItem = GetMenuItem(e.ClickedItem.Name);
    menuItem.Checked = true;
    var childForm = menuItem.Tag as Form;
    childForm.BringToFront();
    childForm.Focus();
    }
    private void FormMain_Load(object sender, EventArgs e)
    {
    ShowChildForm<FormChild>();
    }
    private void ShowChildForm<TForm>() where TForm : Form, new()
    {
    TForm childForm = new TForm();
    childForm.Name = "frm" + Guid.NewGuid().ToString("N");
    childForm.Text = string.Format("Child Form -{0}", ++formCount);
    childForm.MdiParent = this;
    childForm.Parent = splitContainer1.Panel2;
    childForm.WindowState = FormWindowState.Maximized;
    childForm.Paint += (s, e) => { 
    var frm=s as Form;
    if (!frm.Name.Equals(currentChildFormName) && this.splitContainer1.Panel2.Controls[0].Equals(frm)) //当容器中第一个控件就是当前的窗口,则表明该窗口处于所有窗口之上
    {
    CheckWindowsMenuItem("menu_" + frm.Name);
    currentChildFormName = frm.Name;
    }
    };
    childForm.Show();
    }
    private void CheckWindowsMenuItem(string menuName)
    {
    var menuItem = GetMenuItem(menuName);
    if (menuItem != null)
    {
    menuItem.Checked = true;
    }
    }
    void Panel2_ControlChanged(object sender, ControlEventArgs e)
    {
    var frm = e.Control as Form;
    string menuName = "menu_" + frm.Name;
    bool exists = this.splitContainer1.Panel2.Controls.Contains(frm);
    if (exists)
    {
    var menuItem = GetMenuItem(menuName);
    if (menuItem != null)
    {
    menuItem.Checked = true;
    frm.BringToFront();
    frm.Focus();
    }
    else
    {
    windowsToolStripMenuItem.DropDownItems.Add(new ToolStripMenuItem() { Text = frm.Text, Name = menuName, Tag = frm, Checked = true });
    }
    }
    else
    {
    var menuItem = GetMenuItem(menuName);
    if (menuItem != null)
    {
    windowsToolStripMenuItem.DropDownItems.Remove(menuItem);
    menuItem.Dispose();
    }
    }
    }
    private ToolStripMenuItem GetMenuItem(string menuName)
    {
    var menuItems = windowsToolStripMenuItem.DropDownItems.Cast<ToolStripMenuItem>();
    menuItems.ToList().ForEach(m => m.Checked = false);
    return menuItems.Where(m => m.Name == menuName).SingleOrDefault();
    }
    private void newToolStripMenuItem_Click(object sender, EventArgs e)
    {
    ShowChildForm<FormChild>();
    }
    }
    } 

    以下是系统自动生成的代码:

    namespace WindowsFormsApplication1
    {
    partial class FormMain
    {
    /// <summary>
    /// 必需的设计器变量。
    /// </summary>
    private System.ComponentModel.IContainer components = null;
    /// <summary>
    /// 清理所有正在使用的资源。
    /// </summary>
    /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
    protected override void Dispose(bool disposing)
    {
    if (disposing && (components != null))
    {
    components.Dispose();
    }
    base.Dispose(disposing);
    }
    #region Windows 窗体设计器生成的代码
    /// <summary>
    /// 设计器支持所需的方法 - 不要
    /// 使用代码编辑器修改此方法的内容。
    /// </summary>
    private void InitializeComponent()
    {
    this.menuStrip1 = new System.Windows.Forms.MenuStrip();
    this.windowsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
    this.newToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
    this.splitContainer1 = new System.Windows.Forms.SplitContainer();
    this.menuStrip1.SuspendLayout();
    ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
    this.splitContainer1.SuspendLayout();
    this.SuspendLayout();
    // 
    // menuStrip1
    // 
    this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
    this.windowsToolStripMenuItem,
    this.newToolStripMenuItem});
    this.menuStrip1.Location = new System.Drawing.Point(0, 0);
    this.menuStrip1.MdiWindowListItem = this.windowsToolStripMenuItem;
    this.menuStrip1.Name = "menuStrip1";
    this.menuStrip1.Size = new System.Drawing.Size(1069, 25);
    this.menuStrip1.TabIndex = 1;
    this.menuStrip1.Text = "menuStrip1";
    // 
    // windowsToolStripMenuItem
    // 
    this.windowsToolStripMenuItem.Name = "windowsToolStripMenuItem";
    this.windowsToolStripMenuItem.Size = new System.Drawing.Size(73, 21);
    this.windowsToolStripMenuItem.Text = "Windows";
    this.windowsToolStripMenuItem.Click += new System.EventHandler(this.windowsToolStripMenuItem_Click);
    // 
    // newToolStripMenuItem
    // 
    this.newToolStripMenuItem.Name = "newToolStripMenuItem";
    this.newToolStripMenuItem.Size = new System.Drawing.Size(46, 21);
    this.newToolStripMenuItem.Text = "New";
    this.newToolStripMenuItem.Click += new System.EventHandler(this.newToolStripMenuItem_Click);
    // 
    // splitContainer1
    // 
    this.splitContainer1.BackColor = System.Drawing.SystemColors.ActiveCaption;
    this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
    this.splitContainer1.Location = new System.Drawing.Point(0, 25);
    this.splitContainer1.Name = "splitContainer1";
    // 
    // splitContainer1.Panel2
    // 
    this.splitContainer1.Panel2.BackColor = System.Drawing.SystemColors.ScrollBar;
    this.splitContainer1.Size = new System.Drawing.Size(1069, 526);
    this.splitContainer1.SplitterDistance = 356;
    this.splitContainer1.TabIndex = 2;
    // 
    // FormMain
    // 
    this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.ClientSize = new System.Drawing.Size(1069, 551);
    this.Controls.Add(this.splitContainer1);
    this.Controls.Add(this.menuStrip1);
    this.MainMenuStrip = this.menuStrip1;
    this.Name = "FormMain";
    this.Text = "FormMain";
    this.Load += new System.EventHandler(this.FormMain_Load);
    this.menuStrip1.ResumeLayout(false);
    this.menuStrip1.PerformLayout();
    ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
    this.splitContainer1.ResumeLayout(false);
    this.ResumeLayout(false);
    this.PerformLayout();
    }
    #endregion
    private System.Windows.Forms.MenuStrip menuStrip1;
    private System.Windows.Forms.ToolStripMenuItem windowsToolStripMenuItem;
    private System.Windows.Forms.SplitContainer splitContainer1;
    private System.Windows.Forms.ToolStripMenuItem newToolStripMenuItem;
    }
    }

    以下是效果演示截图:

    以上内容给大家分享了在winform下实现左右布局多窗口界面的方法,有什么更好的实现方法可以在下方评论,不足之处也欢迎指出,谢谢!下面将给大家介绍在winform下实现左右布局多窗口界面的方法(二)---- 之续篇,感兴趣的朋友继续关注。

    出处:http://www.jb51.net/article/80194.htm

  • 相关阅读:
    mysql实现主从备份
    Spring boot 继承 阿里 autoconfig 配置环境参数
    Spring Boot 注解的使用
    SpringBoot yml 配置
    浅谈提高工作效率
    Oracle 数据库特殊查询总结
    WPF MVVM 学习总结(一)
    VS2010部署Asp.net程序到本地IIS 7
    Asp.net MVC3表格共用分页功能
    WCF学习总结
  • 原文地址:https://www.cnblogs.com/mq0036/p/6408055.html
Copyright © 2011-2022 走看看