winform应用程序是一种智能的客户端技术;我们可以使用winform应用程序帮助我们获得信息或者传输信息等;它是CS交互模式下的软件,要求我们的电脑必须安装
客户端软件;
传智不拖控件不是指winform,指的是asp.net做网站的时候
做网站拖控件会产生大量的代码,那些代码大部分对你来说是没用的,当一个网站所有东西都是拖出来的,那么会有很多垃圾代码,当网站运行的时候,垃圾代码
也会被执行,因此你拖的控件越多,网站的性能就越低;做网站的时候,所有的东西都是一点一点敲出来的,不是拖控件的,但是winform就只能去拖控件了。
有一门做winformUI层的技术叫做wpf,它用到的一门语言是XAML
不管是窗体应用程序还是控制台应用程序Main函数都是主入口;
program.cs中
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); //创建一个Form1的对象,控制台创建的对象都看不见,但是winform创建的对象都可见;
}
}
public partial class Form1:Form
{
public Form1()
{
InitialComponent();
}
}
正方体是方法的图标,蓝色长方体是字段的图标,枚举的图标是二个黄色的小方块,属性是一个小板子
private void InitializeComponent()
{
this.SuspendLayout();
//
//
//
// form1的一大堆属性
}
Form1.Designer.cs 窗体自动生成的代码;
Form1.resx窗体应用程序的资源文件,音乐图片这些,
Form1后台代码
Form1和Form1.Designer.cs 都有partial form1类 他们共同组成了Form1类
如何在后台快速切换到前台,后台右击空白处,点第一个查看设计器
winform中看到的每一种控件其实都是每种类;往上面托控件,就是创建该类的对象的过程;
当我们关闭窗体的时候会执行释放资源的方法
private System.ComponentModel.IContainer component = null;
protected override void Dispose(bool disposing)
{
if(disposing&&(component != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
给控件设置属性可以在Form1.Designer.cs里面的代码中进行设置;或者选中控件,右键,属性;或者F4导出属性栏,F5运行,F6生成解决方案;
2.属性
Name:在后台要获得前台的控件对象,需要使用Name属性;
BackgroundImageLayOut:控件的背景图片完整填充控件;
ContextMenuStrip:右键菜单; 要添加右键菜单的话,找到工具箱,菜单和工具栏,ContextMenuStrip拖过来,显示在窗体底下,在左上角设置;然后就在
这个控件的属性中的contxetMenustrip绑定起来;
Cursor:光标类型;移到设置的控件中才有效;
Enable指示控件是否可用,
Visiable指示控件是否可见;
3.事件
发生一件事情;
注册事件:属性上面的雷标记里就是事件,控件里面被选中的事件都是我们最常用的事件;在对应事件名称中双击即可注册事件,事件本质上就是一个方法;
Winform中的MessageBox.Show() 就是控制台里面的Console.WriteLine();
触发事件:
事件方法的两个参数:第一个参数object sender,表示触发这个事件的对象;是谁触发了这个事件;第二个参数就是EventArgs e表示执行这个事件所需的资源;
object sender说明控件里面的这些类依然继承于object类
我们写winform应用程序是由各种事件累积而成;
在项目目录里,右键,添加,就可以添加多个form窗体;
在Main函数当中创建的窗体对象,我们称之为这个窗体应用程序的主窗体;
也就意味着,当你将主窗体关闭了,整个应用程序就都关闭了;
如果说你想给某个控件注册它的默认被选中的事件,你直接双击这个控件就可以了;
From2 frm2 = new Form2();
frm2.show();
如何在别的窗体中获得主窗体的对象;
新建一个类;
public static class Test //静态类在整个项目当中资源共享,静态类不能创建对象,我们说静态类数据共享,所以我们存一些共享的数据在里面;
{
public static Form1 _frm1Test; 声明一个静态字段;
}
然后在程序运行的时候,把主窗体对象扔到_frm1Test里面;
在winform应用程序里面;你要想关闭所有应用程序你就得关闭主窗体,但是在form3窗体里面拿不到主窗体对象;因为根本就不在一个类里面;现在要想在form3中
获得主窗体的对象,我们就通过静态类传过来,其实是通过静态字段传过来,在Form3中虽然访问不到Form1里面的对象,但是我能访问到Test静态类,因为在一个项目里
因此也能访问到Test里面的公有字段;
我们要在程序一运行的时候,就把对象存进去;因此就在Form_Load事件里写
Test._frm1Test = this;
在Form3中写
Test._frm1Test.Close();
其实就是通过搭建中间桥梁的作用,静态类中的静态字段就是中间桥梁;
MouseEnter事件;鼠标进入控件所触发的事件;
this.Close(); 关闭当前窗体;
this.Width 是窗体的宽度,是个死值;
this.ClientSize.Width是当前窗体的宽度,随着窗体拉大他也变大;
this.Height
this.ClientSize.Height同理
button1.Location = new Point(r.Next(0,x+1),r.Next(0,y+1))按钮的坐标;
拖出来一个控件如果有小箭头,那么就点开来看看;
TextBox
Multiline属性如果为True,则可以多行显示
WordWrap属性如果为True,则可以自动换行;
ScrollBars属性滚动条,横向,纵向,双向
凡是通过鼠标设置的属性,都可以通过后台代码设置;
PasswordChar 让文本框显示一个单一的字符
默认的事件是TextChanged
同一件事情做好多遍就要用到工具箱,组件当中的Timer,默认Enable是false。Interval事件执行的频率,以毫秒为单位;
只有一个事件Tick
跑马灯就是字符串截取(substring)第一个字符截取到最后,在一个Timer中反复执行;
在Label事件显示就是 lblTme.Text = DateTime.Now.Tostring();但是在刚开始的那一秒不会动,因为计时器是在一秒之后才启动,为了
解决这个问题,要在窗体加载的时候,将当前系统的时间赋值给我的Label lblTme.Text = DateTime.Now.Tostring();一个写在时钟事件里
一个写在Form_Load事件里;
DateTime.Now.Hour
DateTime.Now.Minute
DateTime.Now.Second
SoundPlayer sp = new SoundPlayer(); //创建一个播放音乐对象
[email protected]"" //播放文件的路径,只能播放.wav的文件;
sp.play(); 播放
可以通过visible属性来控制不同权限,不同用户看到的界面;
TextBox1.Clear();清空文本框;
TextBox1.Focus();文本框获得焦点;
一个属性的true和false可以通过一个按钮来控制;
if(button1.Text == "自动换行")
{
TextBox1.WordWrap = false;
button1.Text == "取消自动换行";
}
else if
{
TextBox1.WordWrap = true;
button1.Text == "自动换行";
}
checkbox指示该控件有没有被选中;单选和多选都有
如何给控件分组呢,这时候需要用到容器 groupbox,把2个radiobutton放进去,这时候放进去的就成了一组;
默认情况下在一个窗体中,所有的单选按钮只允许选择一个,可以使用groupbox进行分组;
MDI窗体,一个父窗体里面包含很多子窗体,而且这些子窗体移不出父窗体;
MDI窗体设计
1,首先确定一个父窗体; 找到窗体的属性IsMdiContainer 设置为True就是父窗体了
菜单就是工具箱下面的菜单和工具栏里的MenuStrip,要给里面的按钮注册事件就直接双击对应的按钮;
2,创建子窗体,并且设置他们的父窗体;
form2 frm2 = new form2();
frm2.MdiParent = this;
frm2.show();
子窗体在Mdi窗体里横向排列
LayoutMdi(LayoutMdi.TileHorizontal);
子窗体在Mdi窗体里纵向排列
LayoutMdi(LayoutMdi.TileVertical);
PictureBox显示图片的控件
属性 SizeMode: StretchImage 将图片完整得显示在图片框里;
PictureBox.Image = Image.FromFile(@"dizhi");
操作文件的类是file,操作路径的类是path,操作文件夹的类是directory
获得指定文件夹的所有文件的全路径
string[] path = Directory.GetFiles(@"路径");
设置图片如何在picturebox中显示 picturebox1.SizeMode = PictureBoxSizeMode.StretchImage;
FileStream读不出word.excel这样的文件;读这样的文件要用.net提供的其他类库;
----------------------------------------------------------------------------------------------
创建文件夹 Directory.CreateDirectory(@"路径名称");
删除文件夹 Directory.Delete(@"路径名称");如果文件夹里面有东西,则删不了 回收站也没有,是个彻底删除的操作;
删除文件夹 Directory.Delete(@"路径名称",true);即使里面有东西,也能删除; 回收站也没有,是个彻底删除的操作;
剪切文件夹 Directory.Move("原路径","新路径");
找到文件夹下.jpg结尾的文件 string[] path = Directory.GetFiles(@"路径","*.jpg");
string[] path = Directory.GetDirectories();得到文件夹下所有文件夹的路径
Directory.Exists("路径");是否存在这个文件夹;
浏览器控件 webbrowser控件,很多窗体应用程序里都可以打开网页,用的就是Webbrower 主要属性是url,
string text = Textbox1.Text;
Uri uri = new Uri("http://"+text);
WebBrower1.Url = uri;
ComboBox.items.Add("张三"); 给combox添加内容;添加的类型是object;
ComboBox.items.AddRange();添加集合;
Combobox.items.Clear();把集合给清空;
Dropdownstyle:控制下拉框的样式
给combobox起名字的时候,一般都是cbo+...
combobox默认的事件是selectindexchanged事件;
为了防止连续添加,应该在添加之前,把原来的清空;
想拿到combobox的值,用cbomonth.SelectedItem.Tostring();SelectedText和SelectedValue取不到
str.split(new char[]{‘月‘},stringsplitoptions.RemoveEmptyEntries);
((year%400==0)||(year%4==0&&year%100!=0))判断闰年的条件;
listbox1.items.Add() //往listbox里面添加元素;
Path.GetFileName(); //得到路径中的文件名
listbox常用事件 doubleclick
listbox.SelectedIndex 当前选中项的索引;
要把一部分要重复用到的代码写成一个方法的时候,选中要的代码,右键,重构,提取方法,写入方法名称
如何出现对话框,无非就是创建对话框对象,打开对话框openfiledialog,保存对话框savefiledialog,字体对话框fontdialog,颜色对话框colordialog
openfiledialog ofd = new openfiledialog();
ofd.Title = "123";//设置对话框的标题;
ofd.Multiselect = true; //设置对话框可以多选;
ofd.InitialDirectory = @"...桌面的路径";//设置对话框打开的初始界面;
ofd.Filter = "文本文件|*.txt|所有文件|*.*"; //显示你想要看的文件类型;
ofd.showDialog; //设置属性一定要在对话框显示的前面设置,不然就没有用了;
string path = ofd.FileName; //获得在打开对话框中选中文件的路径;
string[] path = ofd.FileNames;
using(FileStream fsrRead = new FileStream(path,FileMode.OpenOrCreate,FileAccess.Read))
{
byte[] buffer = new byte[1024*1024*5];
int r = fsrRead.Read(buffer,0,buffer.Length); //实际读取到的字节数;
TextBox1.Text = Encoding.Default.GetString(buffer,0,r);
}
savefiledialog sfd= new savefiledialog();
sfd.ShowDialog();
sfd.Title
sfd.InitialDirectory
sfd.Filter
string path = sfd.FileName;//获得路径;
using(FileStream fsWrite = new FileStream(path,FileMode.OpenOrCreate,FileAccess.Write))
{
byte[] buffer = Encoding.Default.GetBytes(TextBox1.Text);
fsWrite.Write(buffer,0,buffer,length);
}
FontDialog fd = new FontDialog();
fd.ShowDialog();
textBox1.Font = fd.Font;
colordialog cd = new colordialog();
cd.ShowDialog();
textBox1.ForeColor = cd.Color;
工具箱,容器,Panel
Panel.Visiable = false; //在Panel中的控件也都消失了;
工具箱,菜单和工具栏中有MenuStrip就是菜单栏;拖进去即可;
string FileName = Path.GetFileName(path); //用Path类获得路径中的文件名
.....ToolStripMenuItem.Text == "";获得菜单栏的文本
进程可以理解为每一个应用程序都是一个进程;.net操作进程的类是process
Process[] pros = Process.GetProcesses(); //类名.方法名调用这个静态方法,得到计算机正在运行的所有进程,返回进程类型的数组;
Process pro = new Process();
pro.kill();关闭进程;
Procsee.Start("calc"); 通过进程的方式打开计算机;
Procsee.Start("mspaint");
Procsee.Start("notepad");
Procsee.Start("iexplore","www.baidu.com");
//通过进程打开指定的文件;
Process pro = new Process();//创建进程对象;
processinfo psi = new processinfo(@"文件路径"); //创建的原因,p.start的时候需要这种类型的对象;
pro.StartInfo = psi;
p.start();
每一个进程都是由多个线程组成的;
单线程给我们带来的问题;
winform中要看到输出就在调试,窗口,输出打开即可;
在VS中,每运行一个程序,计算机都会分配一个主线程(只有一个)来执行这样的一个程序,
拖动窗体,操作窗体都是主线程在做的事;如果主线程去干别的事了,那么窗体就会出现假死;
VS中操作线程的类是Thread
创建一个线程对象
Thread th = new Thread(Test);//传进去的是让线程执行的方法(委托); 这个是线程,但不是主线程;
private void Test()
{
for(int i = 0;i < 10000;i++)
{
Console.WriteLine(i);
}
}
th.start() //标记这个线程准备就绪了,可以随时被执行;线程执行是由CPU决定,我们是不能手动的调用线程的;
调用方法占一个线程?
线程分为2种,一种是前台线程,一种是后台线程;
前台线程:只有所有的前台线程都关闭才能完成程序关闭;
后台线程:只要所有的前台线程结束,后台线程自动结束;
我们默认情况下自己创建的线程都是前台线程;
主线程也属于前台线程
把线程设置为前台线程 th.IsBackground = true;
单线程的弊端;
1.如果让程序做很多程序,会出现假死的状态;多线程的目的就是为了能让程序做多件事情;
主窗体和窗体中的控件是由主线程创建的,
Thread th = new Thread(Test);
private void Test()
{
for(int i = 0;i < 10000;i++)
{
TextBox1.text = i; //如果改成这样就出错了,因为TextBox1是主线程创建的,而th是我们的新线程,出现了新线程去访问主线程的资源,在.netframework下是不允许跨线程的访问的;
}
}
th.start()
在执行上述代码的时候,如果在运行过程中关闭程序,就可能出现错误,错误是释放资源出错,因为主线程关了,导致了文本框等消失了,此时新线程还没有结束,但是没有文本框了,不能访问了,
所以报错了;
解决办法是在FormClosing事件里判断新线程是否为null;如果为null的话,说明他已经关了,如果不为null,就把它关闭;
if(th != null)
{
th.Abort();//结束这个线程,当线程被结束之后,就不能start了;
}
Contral.CheckForIllegalCrossThreadCalls = false; 取消检查跨线程访问,写在FormLoad事件里
Control类是winform所有控件的基类;
Thread.Sleep(1000) 静态方法,可以使当前线程停止一段时间运行;1000表示1000毫秒;
Name线程名
Thread.CurrentThread获得当前的线程引用;
我们不能通过代码操作CPU
string[] path = ofd.FileNames; //得到打开框里所有的文件;
//把多选的文件加入到列表框当中;
for(int i = 0; i < path.length;i++)
{
listbox1.Items.Add(Path.GetFileName(path[i]));
}
点击播放下一首
int index = listbox1.SelectedIndex;
index++;
if(index == listbox1.Items.Count)
{
index = 0;
}
listbox1.SelectedIndex = Index; //这句话很关键,必须把新索引复制给listbox1.SelectedIndex;不然索引是没变的;
线程分为前台线程和后台线程,我们应该使用后台线程;
Thread th = new Thread(Test);
private void Test(string s)
{
for(int i = 0;i < 10000;i++)
{
Console.WriteLine(i);
}
}
程序报错,原因如下;
如果线程执行的方法需要参数,那么要求这个参数必须是object类型;
Thread th = new Thread(Test);
th.IsBackground = true;
th.Start("123");
private void Test(object s)
{
for(int i = 0;i < 10000;i++)
{
Console.WriteLine(i);
}
}
//这样就不会出错了;
摇奖机
外面
bool b = false;
private void PlayGame()
{
Random r = new Random();
while(b)
{
label1.Text = r.Next(0,10).ToString();
label2.Text = r.Next(0,10).ToString();
label3.Text = r.Next(0,10).ToString();
}
}
按钮单击事件中:
if(b == false)
{
b = true;
Button1.Text = "停止";
Thread th = new Thread(PlayGame);
th.background = true;
th.start();
}
else
{
b = false;
Button1.Text = "开始";
}
FormLoad事件中:
Contral.CheckForIllegalCrossThreadCalls = false;
// avg = Convert.ToDouble(avg.ToString("0.00")); 真正的保留两位,原值改变了
// Console.WriteLine("{0:0.00}" , avg);输出的时候保留两位,原值没变;
通过冒泡排序对整数数组{ 1, 3, 5, 7, 90, 2, 4, 6, 8, 10 }进行升序排列
int[] nums = { 1, 3, 5, 7, 90, 2, 4, 6, 8, 10 };
for(int i = 0;i < nums.length - 1;i++)
{
for(int j = 0; j < nums.length - 1-i;j++)
{
if(nums[j] > nums[j+1])
{
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
}
升序最快 Array.sort(nums);
降序 Array.Reverse(nums);
while (index != -1)
{
i++;
index = str.IndexOf("咳嗽",index + 1);
if (index == -1)
{
break;
}
Console.WriteLine("第{0}次出现咳嗽的位置是{1}", i, index);
//搜索一个词在字符串中出现几次,在那个位置的关键方法;
" hello world,你 好 世界 ! "
string[] sNew = str.Split(new char[]{‘‘},StringSplitOptions.RemoveEmptyEntries);
string strNew = string.join("",sNew);
string s = "";
string ss = " ";
这两个不是一个东西,上面那个是空,下面那个不为空,有个空格字符串;
Reverse()方法是
for(int i = 0 , i<str.length/2,i++)
{
int temp = str[i];
str[i] = str[str.length-1-i];
str[str.length-1-i] = temp;
}
如果要把一个方法重写,就要把他标记为virtual,或者是abstract的,普通的方法不能去重写;
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public string Name
{
get;
set;
}
下面那种是自动属性,跟上面那种是一样的效果;