有了创建一个Windows窗体应用程序的经验,就可以开始尝试运用更多的控件实现更多丰富的功能界面。以下分享我基于项目Helloworld_WinForm使用常用C#Windows窗体控件实现一些小功能。
每一节标题为所用到的控件,全文以实际制作过程为序编制。
目录
- WinForm窗体应用程序开发步骤
- 常用控件实例
- MenuStrip 菜单栏
- richTextBox富文本框
- SaveFileDialog保存对话框
- FontDialog字体对话框
- richTextBox的属性WordWrap
- ColorDialog颜色对话框
- Timer计时器
- PictureBox-如何加文字
- PictureBox-画图
- 问题与解决
- 解决子窗体被父窗体控件挡住问题
- 发布做好的程序
WinForm窗体应用程序开发步骤
1、创建窗体Form
项目创建时会默认创建一个窗体,默认为父窗体。
新建的其他窗体为子窗体,子窗体调用时会在父窗体中显示。
项目创建方法见:Helloworld_WinForm,本文直接基于之前创建的项目搭建功能。
2、创建控件Control
控件显示在工具箱中,通过双击或拖拽的方式显示在当前打开的设计窗口中,可在属性栏修改其属性。
3、指定布局Layout
根据应用拖动控件位置,或在属性中调整坐标等。
4、响应事件Event
事件包括双击控件、按下鼠标、向文本框输入内容等等,可以在控件属性中点击事件图标查看所有事件。
响应是指发生事件后,触发的操作,通常以代码的形式实现功能。
描述还是比较抽象,建议动手实践。
常用控件实例
MenuStrip 菜单栏
新建MenuStrip控件,修改属性如下
- Name:tools
- Text:工具
在工具下,继续新建TextBox,修改它们属性的Text。
如果在子窗体中也加入Menustrip,则需在父窗体的Menustrip属性中按下图所示修改,否则子窗体菜单栏不会显示出来,默认二者菜单栏合并。
父窗体:
子窗体:
richTextBox富文本框
参考链接
在项目中右键添加子窗体,命名Text。
Anchor属性选择“Top,Bottom,Left,Right”,这样当窗体大小改变时,RichTextBox控件的大小也会跟着改变
新建 richTextBox控件。属性BackColor改为ControlLightLiight,ReadOnly改为True。修改Dock属性为Fill,使控件铺满窗口。
将父窗体属性中的IsMdiContainer改为true。
并双击父窗体菜单栏的“新建”,编辑程序,使点击新建时打开子窗体。
private void toolStripTextBox3_Click(object sender, EventArgs e)
{
Text newMDIChild = new Helloworld_WinForm.Text();
// Set the Parent Form of the Child window.
newMDIChild.MdiParent = this;
// Display the new form.
newMDIChild.Show();
}
SaveFileDialog保存对话框
参考链接:c#保存textbox中的字符串到txt文件中
点击记事本的【文件】→【保存】菜单项时,使用SaveFileDialog保存文件。
用程序创建SaveFileDialog及修改属性。
// 菜单栏中的保存按钮。也可用Button
private void 保存ToolStripMenuItem_Click(object sender, EventArgs e)
{
// 新建SaveFileDialog,Name为saveFileDialog
SaveFileDialog saveFileDialog = new SaveFileDialog();
// 修改属性,定义保存文件类型
saveFileDialog.Filter = "(*.txt)|*.txt|(*.*)|*.*|97-2003Word文档|*.doc";
// 文件名是日期时间
saveFileDialog.FileName = "D:\\text\\" + DateTime.Now.ToString("yyyyMMddHHmm") + ".txt";
// 对话框打开
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
// 新建数据流
StreamWriter streamWriter = new StreamWriter(saveFileDialog.FileName, true);
// 写入数据
streamWriter.Write(this.richTextBox1.Text);
// 关闭当前streamWriter对象和基础流
streamWriter.Close();
}
}
// 富文本,Name为richTextBox1
private void richTextBox1_TextChanged_1(object sender, EventArgs e)
{
}
上述程序启动后,点击保存,会弹出保存窗口,如下:
可以选择保存为txt或doc格式。
试一试效果:
FontDialog字体对话框
继续增加菜单栏选项:字体。其属性Name为字体ToolStripMenuItem。
双击字体,编写代码,新建字体对话框,并将设置的字体赋给富文本中的Text。
private void 字体ToolStripMenuItem_Click(object sender, EventArgs e)
{
FontDialog fontDialog = new FontDialog();
if(fontDialog.ShowDialog() == DialogResult.OK)
{
richTextBox1.SelectionFont = fontDialog.Font;
}
}
试一下效果:
先设置字体,再输入文本。也可在输入文本后,选中需要修改字体的文本,再点击字体修改。
richTextBox的属性WordWrap
增加菜单栏选项:自动换行。其Name属性为自动换行ToolStripMenuItem。
自动换行的Checked属性默认为“False”,文本内容按照文本框的宽度自动换行,否则只按段落标记换行。
可以修改富文本属性WordWrap,以决定是否默认自动换行,此处为默认自动换行:
将自动换行选项的默认状态Checked改为被点击的True状态:
双击自动换行,编辑代码如下:
private void 自动换行ToolStripMenuItem_Click(object sender, EventArgs e)
{
// 判断自动换行状态标记
if(自动换行ToolStripMenuItem.Checked == false)
{
// 被按下后更新状态
自动换行ToolStripMenuItem.Checked = true;
// 自动换行
richTextBox1.WordWrap = true;
}
else
{
// 被按下后更新状态
自动换行ToolStripMenuItem.Checked = false;
// 不自动换行
richTextBox1.WordWrap = false;
}
}
实现的效果就是默认自动换行,点击自动换行后取消自动换行,再次点击则变为自动换行。
ColorDialog颜色对话框
利用ColorDialog修改字体颜色。
增加菜单栏字体颜色,其Name属性为字体颜色ToolStripMenuItem。
双击它编辑代码如下:
// 第一种
private void 字体颜色ToolStripMenuItem_Click(object sender, EventArgs e)
{
ColorDialog colorDialog = new ColorDialog();
if (colorDialog.ShowDialog() == DialogResult.OK)
{
richTextBox1.SelectionColor = colorDialog.Color;
}
}
试一下效果:
若先设置字体颜色,再输入文本,则此前输入的文本不会变化,变更只适用于此后输入的文本。
也可在输入文本后,选中需要修改字体颜色的文本,再点击字体颜色修改,变更适用于选中的文本。
修改为橙色:
如果在未选中文本时修改字体颜色,要将所有文本字体颜色同时修改,则可以这样写:
选中文本再修改颜色,只会修改选中文本的颜色。
// 第二种
private void 字体颜色ToolStripMenuItem_Click(object sender, EventArgs e)
{
ColorDialog colorDialog = new ColorDialog();
if (this.colorDialog1.ShowDialog() == DialogResult.OK)
{
if (this.richTextBox1.SelectedText == "") // 若未选中文本,则将设置颜色适用于所有文本
{
this.richTextBox1.ForeColor = this.colorDialog1.Color;
}
else
{
this.richTextBox1.SelectionColor = this.colorDialog1.Color;
}
}
}
Timer计时器
参考链接
在项目中新建Windows窗体,命名为Clock.cs。
在父窗体中,双击菜单栏Clock,编写代码,添加子窗体Clock。属性BackColor改为ControlLightLiight,ReadOnly改为True。
代码如下:
private void toolStripTextBox2_Click(object sender, EventArgs e)
{
Clock newMDIChild = new Helloworld_WinForm.Clock();
// Set the Parent Form of the Child window.
newMDIChild.MdiParent = this;
// Display the new form.
newMDIChild.Show();
}
在Clock窗体中,拖拽Label控件,Name为label1,修改属性字体颜色为喜欢的字体。修改属性Text为yyyy-MM-dd HH:mm:ss。
拖拽Timer计时器控件,Name为timer1,修改属性Enable为True,Interval为1000。使能定时,每1000ms执行一次函数timer1_Tick中的内容。
双击timer1,编写代码,使其显示实时时间。
private void timer1_Tick(object sender, EventArgs e)
{
label1.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); //年-月-日 小时:分钟:秒
}
其中,HH为24小时进制,hh为12小时进制。
让Label文字居中的方法:设置Autosize的值为false,拉大这个label框的宽度,设置label属性里的TextAlign为MiddleCenter,意思是让框里的文字内容居中。
启动后效果如下:每过一秒,时间更新一次。
PictureBox-如何加文字
参考链接
在父窗口的菜单栏工具中添加一项:Panel。并添加子菜单 加水印 和 清屏。本节实现加水印的功能,后一节实现清屏。
从工具箱拖拽一个PictureBox控件到窗口,属性Dock改为Fill。
属性BackgroundImage可以上传一个图片,使PictureBox控件区域默认显示该图片。
还有SizeMode属性选Zoom,SizeMode属性包含:
- Normal:图片大小不变;
- strechImage:拉伸图片适应PictureBox(图片会变形)
- AutoSize:PictureBox适应图片;
- CenterImage:图片居中显示;
- Zoom:图片填充PictureBox(不变形)
双击“加水印”,编辑程序如下:实现将文字显示在对应坐标。
private void 加水印ToolStripMenuItem_Click(object sender, EventArgs e)
{
// 在pictureBox上创建画图板
Graphics g = pictureBox1.CreateGraphics();
// 设置字体的样式
Font f = new Font("黑体", 24);
// 实例化一个实心画刷,颜色是白色
SolidBrush brush = new SolidBrush(Color.White);
// 与左上角坐标的距离
PointF point = new PointF(400, 300);
// 开始绘制
g.DrawString("From: Electrical_IT", f, brush, point);
}
启动运行,点击加水印,效果如下:
PictureBox-画图
参考链接:C#控件picturebox实现画图功能
C#控件画图方法
打开指定路径图片的方法
本部分实现鼠标在PictureBox区域中使用鼠标绘制的功能。
PictureBox控件属性设置参考上一节。菜单栏也如上一节添加。
要实现绘图功能,需要用到PictureBox的事件响应,位置在PictureBox的属性框中,点击PictureBox,点击事件图标即可看到:
重命名事件MouseDown为drawstart,事件MouseMove为drawmove,事件MouseUp为drawstop。
每次命名后会自动切换到代码编辑界面。
修改代码如下:
private void 清屏ToolStripMenuItem_Click(object sender, EventArgs e)
{
Graphics g = pictureBox1.CreateGraphics();
// 用原背景图清屏
g.DrawImage(pictureBox1.BackgroundImage, 0, 0);
}
// 定义鼠标绘制的终点(起点永远是鼠标当前坐标)
private Point endpoint;
// 绘制标志
private static bool drawing = false;
private void drawstart(object sender, MouseEventArgs e)
{
// 创建终点
endpoint = new Point(e.X, e.Y);
// 鼠标按下开始绘制
drawing = true;
}
private void drawstop(object sender, MouseEventArgs e)
{
// 鼠标松开结束绘制
drawing = false;
}
private void drawmove(object sender, MouseEventArgs e)
{
// 鼠标移动进行绘制,创建画布
Graphics g = pictureBox1.CreateGraphics();
// 显示时消除锯齿
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// 如果鼠标按下的按钮是左键
if(e.Button == MouseButtons.Left)
{
if(drawing)
{
// 当前坐标
Point currentpoint = new Point(e.X, e.Y);
// 用白蓝色笔绘制连接p2和当前坐标的线
g.DrawLine(new Pen(Color.AliceBlue, 2), endpoint, currentpoint);
// 更新终点坐标
endpoint.X = currentpoint.X;
endpoint.Y = currentpoint.Y;
}
}
}
用鼠标画一画,绘制效果如下:
点击清屏后效果如下:(清屏也会把水印清掉)
如果清屏想用白色清屏,参考以下代码:
private void 清屏ToolStripMenuItem_Click(object sender, EventArgs e)
{
Graphics g = pictureBox1.CreateGraphics();
g.Clear(Color.White);
}
问题与解决
解决子窗体被父窗体控件挡住问题
上述实例先创建了子窗体Hello、Clock和Text,再在父窗体中添加了控件PictureBox。
启动后,点击菜单栏Hello、Clock和文件新建时,子窗体无法显示在PictureBox控件前,原因是被父窗口的控件挡住了。
我的解决方法是在打开子窗体前,将父窗体中的控件PictureBox隐藏,点击Panel后再显示PictureBox控件。
隐藏:pictureBox1.Hide();
显示:pictureBox1.Show();
首先将HelloWorld.cs中,菜单点击事件的响应程序里添加隐藏控件的函数:
private void toolStripTextBox1_Click(object sender, EventArgs e)
{
Hello newMDIChild = new Helloworld_WinForm.Hello();
// Set the Parent Form of the Child window.
newMDIChild.MdiParent = this;
// Hide the pictureBox1
pictureBox1.Hide();
// Display the new form.
newMDIChild.Show();
}
private void toolStripTextBox3_Click(object sender, EventArgs e)
{
Text newMDIChild = new Helloworld_WinForm.Text();
// Set the Parent Form of the Child window.
newMDIChild.MdiParent = this;
//Hide the pictureBox1
pictureBox1.Hide();
// Display the new form.
newMDIChild.Show();
}
private void toolStripTextBox2_Click(object sender, EventArgs e)
{
Clock newMDIChild = new Helloworld_WinForm.Clock();
// Set the Parent Form of the Child window.
newMDIChild.MdiParent = this;
//Hide the pictureBox1
pictureBox1.Hide();
// Display the new form.
newMDIChild.Show();
}
其次,在点击菜单中需要响应主窗口控件pictureBox1的程序中,增加显示控件函数:
private void 加水印ToolStripMenuItem_Click(object sender, EventArgs e)
{
// 设置字体的样式
Font f = new Font("黑体", 24);
// 实例化一个实心画刷,颜色是白色
SolidBrush brush = new SolidBrush(Color.White);
// 与左上角坐标的距离
PointF point = new PointF(400, 300);
// 显示pictureBox1控件
pictureBox1.Show();
// 在pictureBox上创建画图板
Graphics g = pictureBox1.CreateGraphics();
// 开始绘制
g.DrawString("From: Electrical_IT", f, brush, point);
}
private void 清屏ToolStripMenuItem_Click(object sender, EventArgs e)
{
// 显示pictureBox1控件
pictureBox1.Show();
Graphics g = pictureBox1.CreateGraphics();
// 用原背景图清屏
g.DrawImage(pictureBox1.BackgroundImage, 0, 0);
}
测试后发现还一个问题:pictureBox1被隐藏后,点击菜单中的加水印,会显示pictureBox1控件背景,但不会显示水印,还需要第二次点击,才会显示水印。不清楚为什么,还希望有大神评论指点。
另外,如果主窗口中控件非常多,不建议使用这种方式,建议将主窗口的控件放在Panel控件中,使子窗口的父类设置为Panel。参考链接
发布做好的程序
如果想将程序发给朋友玩一下,就需要发布。
首先,配置设置为Release、Any CPU。
找到生成,点击发布。
根据发布向导,指定发布的位置。
选择用户下载的方式,这里选从ROM。
选择不检查更新,并点击完成。
等待片刻,就可以在路径里找到setup.exe安装包。双击运行,就可以得到应用配置文件夹和应用程序。双击Helloworld_WinForm.application就可以运行了。
如果想卸载,可以在控制面板的应用中找到并卸载它。