计时器小程序——由浅入深实例讲解

  本菜在实现简单的计时器过程中遇到问题的一些成长笔记,有不完整观点的话请多多见谅,也看了众多大神的博客才整理的笔记,下面来实现个人写的小程序。

首先第一个实例(很简单):

  winform窗体包含两个控件:label、button控件,点击控件开始计时,代码如下:

namespace Timer_Test
{public partial class CommonInstance : Form{private static int startTime = 0;public CommonInstance(){InitializeComponent();}private void btn_Start_Click(object sender, EventArgs e){GetTimes(); //方法在外部封装,调用即可,你应该知道封装的好处咯
        }//写个方法,用于计时运算,不能是静态方法,static和this不能共存;private void GetTimes()  {startTime += 1;this.lb_getTimes.Text = Convert.ToString(startTime);}}
}

  哈哈,这个很简单实现吧,那么怎样才能让计时器自动计时呢,相信你已经想到timer控件,没错接下来实现下!

  实现代码如下:

namespace Timer_Test
{public partial class CommonInstance : Form{private static int startTime = 0;public CommonInstance(){InitializeComponent();}private void btn_Start_Click(object sender, EventArgs e){//GetTimes();
            timer1.Start();}
private void timer1_Tick(object sender, EventArgs e){startTime += 1;lb_getTimes.Text = startTime.ToString();}private void CommonInstance_Load(object sender, EventArgs e){//窗体加载时设置好timer的Enable属性为true:可用timer1.Enabled = true;timer1.Interval = 1000; //设置间隔时间为1s
        }}
}

  其实你会发现,使用timer控件实现也很简单嘛,很多工作都是timer自己做了,省事多了,但我写这编文字的重点不仅仅这些,下面来说下重点吧:

  多线程实现的计时器,不用timer控件了,自己写个机制实现它(这会让我们学到更多的知识),老实说,我还是第一次接触线程,刚开始真的是摸

  不着头脑咋用来着捏,下面就细细说来.....

使用线程前,先引入命名空间:using System.Threading;    具体代码如下:

namespace Timer_Test
{public partial class CommonInstance : Form{private static int startTime = 0;Thread thread = null;//声明一个线程public CommonInstance(){InitializeComponent();}private void btn_Start_Click(object sender, EventArgs e){//GetTimes();//timer1.Start();
thread = new Thread(new ThreadStart(GetTimes)); //创建开始线程实例,将要执行的方法作为参数thread.Start();}private void GetTimes()  {startTime += 1;this.lb_getTimes.Text = Convert.ToString(startTime);}
}

  

  这时你就会暗暗自喜,线程也不过如此嘛,当你点击开始计时后就报错了哦,报错是你给lable控件赋值之时,为什么会错呢,因为你跨线程给UI界面控件赋值了,这关系

到数据的安全问题。

 

  c#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它。此时它将会在内部调用new MethodInvoker(LoadGlobalImage)来完成下面的步骤,这个做法保证了控件的安全,你可以这样理解,有人想找你借钱,他可以直接在你的钱包中拿,这样太不安全,因此必须让别人先要告诉你,你再从自己的钱包把钱拿出来借给别人,这样就安全了。

这样就可以很好的理解上面那个winform程序中 this.BeginInvoke(fc);这行code了,这个执行后其实也就是主线程在调用fc中绑定的方法ThreadFuntion()了,这种方式其实相当于把这个新开的线程“注入”到了主控制线程中,它取得了主线程的控制。只要这个线程不返回,那么主线程将永远都无法响应。就算新开的线程中不使用无限循环,使可以返回了。这种方式的使用多线程也失去了它本来的意义。(copy过来的,源地址在最后面)

  

  解决方法一在点击事件里加这句代码:Control.CheckForIllegalCrossThreadCalls = false;      // 默认为true;

  意思是:不检查跨线程,这是不安全的,不推荐使用;

  解决方法二:(这篇文章的意义所在了)

  通常的方法是使用委托delegate委托主线程处理(解释是后面的啰嗦),和BeginInvoke()方法、IsBackground属性值(默认为false:即非后台线程)以及属

性InvokeRequired;

  下面就要用到InvokeRequired这个propety

  

解决问题代码如下:

namespace Timer_Test
{public partial class CommonInstance : Form{private delegate void FlushClient(); //定义一个委托代理,前面要和委托代理函数签名一致private static int startTime = 0;Thread thread = null;//声明一个线程public CommonInstance(){InitializeComponent();}private void btn_Start_Click(object sender, EventArgs e){//GetTimes();//timer1.Start();
thread = new Thread(new ThreadStart(GetTimes));thread.IsBackground = true;  //设置为后台线程
            thread.Start();}//写个方法,用于计时运算,不能是静态方法,static和this不能共存;private void GetTimes()  {while (true)  //无限循环
            {Thread.Sleep(1000);  //睡眠时间为一秒
                ThreadFunction();}}//写个委托代理函数private void ThreadFunction(){if (this.InvokeRequired) //等待异步
                {FlushClient fc = new FlushClient(ThreadFunction);//实例化委托this.BeginInvoke(fc); //通过代理刷新UI
                }else{startTime += 1;this.lb_getTimes.Text = Convert.ToString(startTime);}}

  这里我就啰嗦一下咯........

  怎么说呢:这时你应该弄清楚 线程 是如何工作的?

  在C#中,非主线程(即非UI线程,就是通过new Thread创建的线程)是不能直接操作UI元素的,必须通过Handler与UI线程通讯,通知UI线程更新.而C#则采用委托的方式更

新UI元素。

  线程分为前台线程和后台线程,线程默认为前台线程(主线程),这意味着任何前台线程在运行都会保持程序存活。

      后台线程:只要有一个前台线程在运行,应用程序的进程就在运行。如果多个前台线程在运行,而Main()方法结束了,应用程序的进程就是激活的,直到所有前台线程完成其任务为止。

      前台线程和后台线程的唯一的区别是— 后台线程不会阻止进程终止。

      在默认情况下,用Thread 类创建的线程都是前台线程。线程池中的线程总是后台线程。

 

参考:http://www.cnblogs.com/Linford-Xu/archive/2012/09/19/2693340.html

 

转载于:https://www.cnblogs.com/weiyuncai/p/4241942.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/291958.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux c之通过管道实现兄弟间进程通信:

1、兄弟间进程通信: 父进程创建管道,并使用fork函数创建2个进程,在第一个子进程发消息到第二个子进程,第2个子进程读取消息并处理,在父进程中不使用管道通信,所以什么都不做,直接关闭管道两端并…

理解 Azure AD 安全默认值设置

为了保护广大的Microsoft 365用户的安全,Azure AD在某些情况下会启用安全默认值,就是要求所有的账号都启用MFA。MFA的全称是 Multi-factor Authentication,中文翻译为多因子身份验证,就是说除了账号密码之外,添加额外的…

mongodb spring 超时时间_拥抱NoSQL--谈Spring Data MongoDB的简单使用

先说说MongoDB是什么。MongoDB官网也有各语言所用的API,当然也有Java的了。但是平日写的东西大部分是基于Spring框架的,自然希望对于数据库的操作也在Spring的掌控之下。前几日才Spring的官网看到了SPRING DATA MONGODB,对此很感兴趣稍微试了…

能抗 6 级风的「拇指伞」,晴雨两用、揣兜就走!

▲ 点击查看每到这个季节,天气就开始对人类不友好了:要么万里无云,紫外线爆表;要么忽然乌云密布,狂风暴雨。出门带伞,谁不知道,说着简单,可是普通的雨伞大小很尴尬,手里不…

SecureCRT 中 python 命令行使用退格键(backspace)出现 ^H 解决办法

选项-->会话选项-->映射键 勾选“其他映射”中的两个选择框 转载于:https://www.cnblogs.com/RUReady/p/6165289.html

设计模式:策略模式

本文翻译自Design Patterns: The Strategy Pattern 目前为止我们已经在这个系列中接触了三个设计模式。我们定义了4种类型的设计模式。在这篇文章中,我将讲解 策略模式,这是属于行为类别的设计模式的。 你可能会有一个疑问:我们什么时候该使用…

云计算基本概念

IT技术行业最不缺少的就是概念的炒作,今天出来个新技术名词,明天又出来个新技术名词,搞的从业人员焦虑不堪,生怕被这个时代所抛弃;但是人的精力是有限的,不可能什么都去学习,与其整天被这一帮发…

通过Dapr实现一个简单的基于.net的微服务电商系统(十八)——服务保护之多级缓存...

很久没有更新dapr系列了。今天带来的是一个小的组件集成,通过多级缓存框架来实现对服务的缓存保护,依旧是一个简易的演示以及对其设计原理思路的讲解,欢迎大家转发留言和star目录:一、通过Dapr实现一个简单的基于.net的微服务电商…

geotif 添加坐标_python – 如何获取geotif中单元格的坐标?

使用仿射变换矩阵,将像素坐标映射到世界坐标.例如,使用affine包. (还有其他方法可以使用简单的数学方法.)from affine import Affinefname /path/to/raster.tif以下是获得仿射变换矩阵T0的两种方法.例如,使用GDAL / Python:from osgeo import gdalds gdal.Open(pa…

年纪都这么大了,还在倒班工作......

1 这么大年纪都在倒班工作(素材来源网络,侵删)▼2 原来,这就是命啊(素材来源网络,侵删)▼3 天啊,都是什么狗血剧情?(素材来源网络,侵删&#xf…

VB中使用GDI+进行图像缩放的实例

VISUAL BASIC(VB)对图形图像的处理一直以来是弱项,并受到很多人的垢病。关于图形图像的放大缩小,一般使用PICTUREBOX的PAINTPICTURE方法来处理。但这个处理方法最大的问题就是图像的失真。比方说图像中原来有网格线的,…

javascript的关于刷新页面给出提示框的代码

// 页面刷新事件 ,或者关闭事件的3中方法!测试都可以!参考官方文档: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers.onbeforeunloadhttps://developer.mozilla.org/en-US/docs/Web/API 方法1:window.onb…

JavaScript格式化数字显示格式

为什么80%的码农都做不了架构师?>>> JavaScript格式化数字显示格式 /** * 格式化数字显示方式 * 用法 * formatNumber(12345.999,#,##0.00); * formatNumber(12345.999,#,##0.##); * formatNumber(123,000000); * param num * param pattern */ func…

linux c之使用#define定义多行函数总结

1、用 define的特点 函数:会带来额外的开销,开辟一片栈空间,记录返回地址,将形参压栈,从函数返回还要释放堆栈,这种开销大,函数的参数必须被声明为一种特定的类型。 宏定义:代…

tensorflow去掉某一维度_在Python中解压缩(取消堆栈)一个输入(占位符),在tensorflow中有一个None维度...

我正在尝试使用具有不同时间步长(不同帧数)的输入的LSTM. rnn.static_rnn的输入应该是tf(不是tf!)的序列.所以,我应该将输入转换为序列.我试图使用tf.unstack和tf.split,但是他们都需要知道输入的确切大小,而我的输入的一个维度(时间步长)正在通过不同的输入改变.以…

js点击图片查看大图,并可以拖动,且滚动滑轮放大缩小

方法一:此方法在页面没有滚动条时无法缩放 JQuery function hideMax(){$(".MAX_div").remove();$("#Cover_Div").hide();}function showMax(url){$("#Cover_Div").show();var Imagefunction(){return document.createElement("i…

太努力工作的年轻人,都有病吧!?

全世界只有3.14 % 的人关注了爆炸吧知识前段时间,有人这样问超模君:为什么年轻人明明没有老一辈辛苦,病却反而更多了?在这个物质丰富的年代,如果你退出这场无限内卷的社畜游戏,选择躺平就会活得很轻松&…

lsattr/chattr

lsattr/chattr主要用于特殊权限可以用lsattr直接查看当前目录下所有文件和目录的特殊属性 默认只有一个e (ext4 /ext3)chattr a 111.txtlsattr 111.txt就会发现多了一个a 那么这个a权限有什么意义呢?我们来编辑一下111.txt 随便输入一些&…

linux之学习之路

很多同学接触Linux不多,对Linux平台的开发更是一无所知。 而现在的趋势越来越表明,作为一个优秀的软件开发人员,或计算机IT行业从业人员, 掌握Linux是一种很重要的谋生资源与手段。 下来我将会结合自己的几年的个人开发经验&…