日期:2014-06-10  浏览次数:20846 次

前言

  在做winfrom项目的时候我们可能会用到嵌套窗体,就是说一个容器中有多个窗体,可以分别管理和应用这些窗体,.net中提供了一种机制就是MDI,可能大家都会用,这边就简单的介绍下。

简单应用

  winfrom中怎么用MDI呢,其实只要设置窗体的一个属性就可以了:

  IsMdiContainer属性设置为true就表示该窗体为MDI窗体,很简单,那我们可以在窗体加载的时候这些写:

 1         private void Form1_Load(object sender, EventArgs e)
 2         {
 3             Form childForm1 = new Form();
 4             childForm1.Text = "窗口1";
 5             childForm1.MdiParent = this;
 6             childForm1.Show();
 7 
 8             Form childForm2 = new Form();
 9             childForm2.Text = "窗口2";
10             childForm2.MdiParent = this;
11             childForm2.Show();
12         }

  childForm1.MdiParent = this;这句代码的意思就是设置子窗体的MDI父窗体为本窗体,看下运行效果:

基本方法

  关于MDI相关的方法主要是窗体的布局方法LayoutMdi(),参数是MdiLayout枚举:

 成员名称说明
  ArrangeIcons 所有 MDI 子图标均排列在 MDI 父窗体的工作区内。
  Cascade 所有 MDI 子窗口均层叠在 MDI 父窗体的工作区内。
  TileHorizontal 所有 MDI 子窗口均水平平铺在 MDI 父窗体的工作区内。
  TileVertical 所有 MDI 子窗口均垂直平铺在 MDI 父窗体的工作区内。

  LayoutMdi(MdiLayout.Cascade);效果:

  LayoutMdi(MdiLayout.TileHorizontal);效果:

仿Notepad小程序

  我们在办公的时候可能都用过Notepad++,很方便,其实Notepad++里面的窗体就有点MDI的感觉:

  我们也可以利用MDI做出类似的感效果,Notepad++是文本编辑器,里面每个窗体其实就是单独的Notepad,首先我们需要先建一个文件编辑器的窗体,其实就是一个RichTextBox控件,因为RichTextBox控件是富文本编辑器,所以我们可以进行字体和颜色的调整,调整字体和颜色用的是winfrom的组件,关于文本编辑器就不详述了,贴下代码:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Text;
  7 using System.Windows.Forms;
  8 
  9 namespace MDINotepad
 10 {
 11     public partial class NotepadForm : Form
 12     {
 13         private int _currentCharIndex;
 14 
 15         #region Code segment for constructors.
 16 
 17         public NotepadForm()
 18         {
 19             InitializeComponent();
 20         }
 21 
 22         public NotepadForm(string filePath): this()
 23         {
 24             //判断文件的后缀名,不同的文件类型使用不同的参数打开。
 25 
 26             if (filePath.EndsWith(".rtf", true, null))
 27                 rtbEditor.LoadFile(filePath,
 28                     RichTextBoxStreamType.RichText);
 29             else
 30                 rtbEditor.LoadFile(filePath,
 31                     RichTextBoxStreamType.PlainText);
 32 
 33             Text = filePath;
 34         }
 35 
 36         #endregion
 37 
 38         #region Code segment for private operations.
 39 
 40         private void Save(string filePath)
 41         {
 42             try
 43             {
 44                 //判断文件的后缀名,不同的文件类型使用不同的参数保存。
 45 
 46                 if (filePath.EndsWith(".rtf", true, null))
 47                     rtbEditor.SaveFile(filePath,
 48                         RichTextBoxStreamType.RichText);
 49                 else
 50                     rtbEditor.SaveFile(filePath,
 51                         RichTextBoxStreamType.PlainText);
 52             }
 53             catch (Exception ex)
 54             {
 55                 MessageBox.Show(ex.ToString());
 56             }
 57         }
 58 
 59         private void SaveAs()
 60         {
 61             sfdDemo.FilterIndex = Text.EndsWith(".rtf", true, null) ? 1 : 2;
 62 
 63             if (sfdDemo.ShowDialog() == DialogResult.OK)
 64             {
 65                 Save(sfdDemo.FileName);
 66                 Text = sfdDemo.FileName;
 67             }
 68         }
 69 
 70         #endregion
 71 
 72         #region Code segment for event handlers.
 73 
 74         private void tsmiSaveFile_Click(object sender, EventArgs e)
 75         {
 76             if (!System.IO.File.Exists(Text))
 77                 SaveAs();
 78             else
 79                 Save(Text);
 80         }
 81 
 82         private void tsmiSaveAs_Click(object sender, EventArgs e)
 83         {
 84             SaveAs();
 85         }
 86 
 87         private void tsmiBackColor_Click(object sender, EventArgs e)
 88         {
 89             cdDemo.Color = rtbEditor.SelectionBackColor;
 90             if (cdDemo.ShowDialog() == DialogResult.OK)
 91             {
 92                 rtbEditor.SelectionBackColor = cdDemo.Color;
 93             }
 94         }
 95 
 96         private void rtbEditor_SelectionChanged(object sender, EventArgs e)
 97         {
 98             if (rtbEditor.SelectionLength == 0)
 99             {
100                 tsmiBackColor.Enabled = false;
101                 tsmiFont.Enabled = false;
102             }
103             else
104             {
105                 tsmiBackColor.Enabled = true;
106                 tsmiFont.Enabled = true;
107             }
108         }
109 
110         private void tsmiFont_Click(object sender, EventArgs e)
111         {
112             fdDemo.Color = rtbEditor.SelectionColor;
113             fdDemo.Font = rtbEditor.SelectionFont;
114             if (fdDemo.ShowDialog() == DialogResult.OK)
115             {
116                 rtbEditor.SelectionColor = fdDemo.Color;
117                 rtbEditor.SelectionFont = fdDemo.Font;
118             }
119         }
120 
121         private void pdEditor_PrintPage(object sender,
122             System.Drawing.Printing.PrintPageEventArgs e)
123         {
124             //存放当前已经处理的高度
125 
126             float allHeight = 0;
127             //存放当前已经处理的宽度
128 
129             float allWidth = 0;
130             //存放当前行的高度
131             float lineHeight = 0;
132             //存放当前行的宽度
133             float lineWidth = e.MarginBounds.Right - e.MarginBounds.Left;
134 
135             //当前页没有显示满且文件没有打印完,进行循环
136 
137             while (allHeight < e.MarginBounds.Height
138                 && _currentCharIndex < rtbEditor.Text.Length)
139             {
140                 //选择一个字符
141 
142                 rtbEditor.Select(_currentCharIndex, 1);
143                 //获取选中的字体
144 
145                 Font currentFont = rtbEditor.SelectionFont;
146                 //获取文字的尺寸
147 
148                 SizeF currentTextSize =
149                     e.Graphics.MeasureString(rtbEditor.SelectedText, currentFont);
150 
151                 //获取的文字宽度,对于字母间隙可以小一些,
152                 //对于空格间隙可以大些,对于汉字间隙适当调整。
153 
154                 if (rtbEditor.SelectedText[0] == ' ')
155                     currentTextSize.Width = currentTextSize.Width * 1.5f;
156                 else if (rtbEditor.SelectedText[0] < 255)
157                     currentTextSize.Width = currentTextSize.Width * 0.6f;
158                 else
159                     currentTextSize.Width = currentTextSize.Width * 0.75f;
160 
161                 //初始位置修正2个像素,进行背景色填充
162 
163                 e.Graphics.FillRectangle(new SolidBrush(rtbEditor.SelectionBackColor),
164                     e.MarginBounds.Left + allWidth + 2, e.MarginBounds.Top + allHeight, 
165                     currentTextSize.Width, currentTextSize.Height);
166                 
167                 //使用指定颜色和字体画出当前字符
168 
169                 e.Graphics.DrawString(rtbEditor.SelectedText, currentFont, 
170                     new SolidBrush(rtbEditor.SelectionColor), 
171                     e.MarginBounds.Left + allWidth, e.MarginBounds.Top + allHeight);
172 
173                 allWidth += currentTextSize.Width;
174 
175                 //获取最大字体高度作为行高
176 
177                 if (lineHeight < currentFont.Height)
178                     lineHeight = currentFont.Height;
179 
180                 //是换行符或当前行已满,allHeight加上当前行高度,
181                 //allWidth和lineHeight都设为0。
182 
183                 if (rtbEditor.SelectedText == "\n"
184                     || e.MarginBounds.Right - e.MarginBounds.Left < allWidth)
185                 {
186                     allHeight += lineHeight;
187                     allWidth = 0;
188                     lineHeight = 0;
189                 }
190                 //继续下一个字符
191 
192                 _currentCharIndex++;
193             }
194 
195             //后面还有内容,则还有下一页
196 
197             if (_currentCharIndex < rtbEditor.Text.Length)
198                 e.HasMorePages = true;
199             else
200                 e.HasMorePages = false;
201         }
202 
203         private void tsmiPrint_Click(object sender, EventArgs e)
204         {
205             if (pdDemo.ShowDialog() == DialogResult.OK)
206             {
207                 //用户确定了打印机和设置后,进行打印。
208 
209                 pdEditor.Print();
210             }
211         }
212 
213         private void tsmiPageSetup_Click(object sender, EventArgs e)
214         {
215             psdDemo.ShowDialog();
216         }
217 
218         private void tsmiPrintPreview_Click(object sender, EventArgs e)
219         {
220             ppdDemo.ShowDialog();
221         }
222 
223         private void pdEditor_BeginPrint(object sender, 
224             System.Drawing.Printing.PrintEventArgs e)
225         {
226             _currentCharIndex = 0;
227         }
228 
229         #endregion
230     }
231 }
View Code

  文件编辑器做好了,下面就是主窗体,首先IsMdiContainer属性设置为true,在上面我们加下菜单:

  新建Notepad的代码:

1         private void tsmiNewTxt_Click(object sender, EventArgs e)
2         {
3             NotepadForm childForm = new NotepadForm();
4             childForm.Text = "新建文本文档.txt";
5             childForm.MdiParent = this;
6             childForm.Show();
7         }

  运行效果:

  程序下载:MDI窗体.rar

  附录:小菜学习编程-Winform系列(初学者)