c# 使用了定时器却不能访问主界面的按钮

liliuteng 2012-11-12 10:25:17
小弟最近做个项目,想用隔一段时间读一次串口的数据并且显示在主界面上,最初的想法是用while死循环,里面用thread.Sleep函数做延时,后来发现这样程序一旦执行就关不掉了(程序死在while循环里了),连主界面上的其他按钮也访问不了了。 因此后来想用多线程,但新开的线程函数似乎不能访问当前窗体的线程的资源,比如不能在另外一个线程里面对当前窗体的textbox控件的text属性赋值,如果非要这么做有点麻烦,似乎要用到委托什么的。 后来又想到了可以访问窗体控件的定时器System.Windows.Forms.Timer,也就是定时一定时间更新一次textbox的text属性,但一运行程序就又卡住了(主窗体上的其他按钮包括关闭按钮都按不了了),并且我加长了定时时间和注释了一些定时触发函数里面的代码,却还是不能点击其他按钮。
求大神指点一下呀。
附:主界面如下:

部分代码为
private void BtnEnd_Click(object sender, EventArgs e)
{
if (port.IsOpen)
port.Close();
}

private void timer1_Tick(object sender, EventArgs e)
{
ComReadThread(sender);
}

public void ComReadThread(object obj)
{
while (port.IsOpen)
{
if (port.BytesToRead > 0)
{
strRecv = port.ReadExisting();
//this.text_showGps.Text += strRecv;
//text_showGps.SelectionStart = text_showGps.TextLength;
//text_showGps.ScrollToCaret();

GetGps();
if (Convert.ToDouble(Longitude) > 0)
{
if (Convert.ToDouble(Longitude) > max_lon)
max_lon = Convert.ToDouble(Longitude);
if (Convert.ToDouble(Latitude) > max_lat)
max_lat = Convert.ToDouble(Latitude);

if (Convert.ToDouble(Longitude) < min_lon && Convert.ToDouble(Longitude) > 0)
min_lon = Convert.ToDouble(Longitude);
if (Convert.ToDouble(Latitude) < min_lat && Convert.ToDouble(Latitude) > 0)
min_lat = Convert.ToDouble(Latitude);

text_maxLon.Text = max_lon.ToString();
text_maxLat.Text = max_lat.ToString();
text_minLon.Text = min_lon.ToString();
text_minLat.Text = min_lat.ToString();


double error_lat = (max_lat - min_lat) * Rj / 180; //获得纬度上的距离 L = Rj * ( lat1 -lat0 ) / 180
//获得经度上的距离 L = Rc * cos(lat0) * ( lon1 -lon0 ) / 180
double error_lon = (max_lon - min_lon) * Rc / 180 * Math.Cos(min_lat / 180);
text_error.Text = (Math.Sqrt(error_lon * error_lon + error_lat * error_lat)).ToString();
//text_error.Text = (Sqrt(error_lon * error_lon + error_lat * error_lat) * 6370000 / 60).ToString();

}
//Thread.Sleep(500);
}
}
}
...全文
639 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
liliuteng 2012-11-14
  • 打赏
  • 举报
回复
谢谢各位了,的确是我循环开多了,在timer控件响应的函数里面很二逼地加了个while,结果导致主界面不响应了,可能是之前写单片机程序写多了,while用习惯了吧。
嘶吼的蚂蚁 2012-11-13
  • 打赏
  • 举报
回复
线程中委托给窗体ui线程处理就好了 this.Invoke((EventHandler)delegate { this.button1.text="线程中调用窗体控件"; });
ooo7880000 2012-11-13
  • 打赏
  • 举报
回复
用System.Timers.Timer。。UI更新就像楼上说的用委托。invoke()
liliuteng 2012-11-13
  • 打赏
  • 举报
回复
之所以会用到timer控件,主要是接下来的任务里面可能需要做一点GPS导航,我希望能定时更新显示相对位置变化, 目前timer控件使用了之后主窗体就不能响应其他消息了,那这样的控件是用来干嘛的呢?或者说是我没用好这个控件吧,使用timer控件需要注意哪些问题呢?
hhddzz 2012-11-13
  • 打赏
  • 举报
回复
不懂串口 你的port会自动关掉吗 不会的话你这样不还是个死循环吗
绿领巾童鞋 2012-11-13
  • 打赏
  • 举报
回复
明显的WINCE 的WINFORM界面,如果用donetcf,少了很多东西,界面控件异步操作只能通过invoke 处理。
嘶吼的蚂蚁 2012-11-13
  • 打赏
  • 举报
回复
获取GPS信息的?串口只要接受处理数据,又不用给底层应答。为什么要用到timer控件? SerialPort_DataReceived事件接受数据就好了,当底层有消息发送给你的时候,会触发SerialPort_DataReceived事件
liliuteng 2012-11-13
  • 打赏
  • 举报
回复
谢谢各位的建议, 首先回复hhddzz,我的port确实没关,毕竟程序是想隔一段时间读一次port的数据,所以没必要关,当然我后来想加一个End按钮实现关port的功能,但目前问题是窗体没有响应,End按钮就失效了。 关于另外一个线程用委托去调用窗体控件,我下去再看一些书吧。 这里我还有一个问题,这里我用窗体类的一个定时器控件去更新窗体,既然定时器只是窗体的一个控件,为什么会造成窗体对其他按钮控件没有响应了呢?我的定时器触发函数没有执行很长时间啊!
Hauk 2012-11-13
  • 打赏
  • 举报
回复
在线程中访问主界面元素,需要使用invoke()的方式去调用。
hchanhc 2012-11-13
  • 打赏
  • 举报
回复
线程操作要使用委托调用窗体控件。
卧_槽 2012-11-13
  • 打赏
  • 举报
回复
你开了N多个死循环,不死才怪。
rcom10002 2012-11-13
  • 打赏
  • 举报
回复
Application.DoEvents()
mjp1234airen4385 2012-11-13
  • 打赏
  • 举报
回复
托管神马的最简单了。 别人的例子: public void button1_Click(object sender, EventArgs e) { new Thread((ThreadStart)delegate { int r = 0; this.Invoke((EventHandler)delegate { this.Text = "begin"; }); for (int i = 0; i < 10000; i++) { r++; this.Invoke((EventHandler)delegate { this.Text = r.ToString(); }); //Application.DoEvents(); } this.Invoke((EventHandler)delegate { this.Text = "end"; }); }).Start(); } private void RunThr() { this.Invoke(new MethodInvoker(delegate { this.label1.Text = "start do worker..."; })); for (int i = 0; i < 1000000; i++) Application.DoEvents(); this.Invoke(new MethodInvoker(delegate { this.label1.Text = "end do worker..."; })); }
leafmao 2012-11-13
  • 打赏
  • 举报
回复
同样求教怎么利用多线程循环读取串口 循环读取我只想到利用计时器查询读取,怎么利用多线程就不会了,楼主能分享下方法不?
liliuteng 2012-11-13
  • 打赏
  • 举报
回复
恩,好吧,虽然还是不明白Timer控件怎么用,但是先谢谢各位了,看来还是得用多线程加委托函数了处理这个问题了,我晚上就试一下。
机器人 2012-11-12
  • 打赏
  • 举报
回复
记住更新UI的,只有UI线程如果长时间更新,窗体就没有响应了。
    前段时间有点空闲就自学了一下c#,以前也没有学过任何编程,只是对电脑操作还是很熟,会一些应用类软件,计算机相关的英文能看懂点。     看了10多节的视频教程,因为基础太差,前面学的东西老会忘,光这样学也没有多大的意义,于是就找个程序一边练一遍学。网上一搜,不知道怎么的就找了一个进程守护的软件,别人提供的源码,好像是在pudn下的,一测试可以运行,就是觉得不太适合自己的操作习惯。于是就开始改造了。牺牲了一周的业余时间,终于完成,在这分享一下,如果有需要的可以自行再改造,版权归原作者,至于我修改的地方,可以任意改,任意传播,没有版权。附上源码,包含源程序的和我改造的部分。只是希望能给像我这样的不会编程的一类朋友一点启示,只要努力,就能达到自己想要的效果。现成的东西,不一定是适合自己的,要想拿来适合自己,也许就需要付出努力。附上修改的说明及截图。没有多大的技术含量,对于会编程的人,也许2下就搞定了,对于不会编程的人,如果刚好需要这样的软件,那就可以偷懒了。测试了win7(x86x64),win8(x86),win10(x64),其他系统没有测试,如果不能运行请自行解决,vs2010编译的,dedug和Release都有编译好的版本。     修改及使用说明 1、配置文件precesses.xml,里面的进程名不要有扩展名,一定要注意。 2、配置文件中的mutl为是否多开,linecount为多开时的限制数,jgtime为守护的周期。 3、配置文件中新增linecount为相同程序限制数(如果程序本身不允许多开那就没办法),可以给每个程序配置不同限制数,但是界面上修改时,只能修改成一样。读取配置后显示最大的那个值在界面上. 4、配置文件中新增jgtime为循环时间,所有程序使用相同的循环时间,配置时可以配置成不一样的,实际没有意义,因只调用了一个定时器,但默认显示并使用最大的那个时间。 5、增加托盘图标提示及菜单 6、取消任务栏图标显示 7、默认启动最小化,如果没有任务栏,只能通过进程结束,固定了窗口不能改变大小 8、界面增加了退出按钮、清空日志按钮 9、界面点击关闭按钮后,自动最小化 10、增加进程调用的部分日志显示框,要是调试方便,日志超过30行自动清屏,未保存,可修改代码关掉或不显示,evertlog目录下多余的日志关掉了,仍然有小部分日志,,如有必要自行在代码中关掉即可。 11、底部增加多开线程输入框及保存按钮,多开进程数大于1小于100,100为无限制模式。增加间隔时间输入框及保存按钮,间隔时间大于等于500,小于等于1000000000之间的整数(毫秒),没有限制再配置中添加应用程序的个数。 12、开始监控及停止监控互锁显示。 13、默认优先读取配置中的最大的间隔时间,如果配置错误会自动初始化为23秒。 14、其他界面布局微调 15、代码自己随意修改太拖沓,会编程的可以进行大量优化。 16、没有做自守护,可以考虑用任务计划写个批处理,再守护它。win764位以上系统,防任务管理栏结束有难度哦。 17、我用的是系统自带的自定义shell启动它,还是很稳定,23秒是我测试的需要,自己可在代码中修改,我修改的地方还是加了不少注释的。 18、调用有些程序可能无法启动的情况,和本软件无关,可能是路径问题,有些程序不允许改变路径运行等,可自己在命令行下测试调用的软件是否运行,我遇到过类似的软件,加入环境变量也不行,只能在同一个目录下。 19、加入配置文件错误的一些纠缠机制(linecount没有会自动创建并赋值3,值为"",也会自动修复),当然错误的情况不够完善,只考虑了没有整项或者值为""的情况,其他情况没有处理,如果遇到其他情况只会导致程序停止,不能对配置的自修复而已,只针对linecout和jgtime做了处理,jgtime整项如果没有,会自动修复为23000毫秒。程序自修复配置文件后,会自动运行,如遇不能修复的问题根据catch出的问题,自行修改源码,加入到出错情况的处理。 20、只测试了win7x86x64,win8x86,win10x64,精简系统可能无法运行,自己测试了一个5年前的极度精简的win7系统,无法运行没有任何提示,也没有去验证到底是什么问题,但大多数精简系统都行。 21、增加鼠标悬停帮助提示,提示框可能有拖影的情况,自行修改源码中的时间参数,也可改用另一种呈现方式不会拖影,源码中有,就是没有那么好看,鼠标悬停提示有点耗cpu资源。 22、双击进程框列出的需要守护监控的进程,可以查看该进程更多详细信息。 23、配置文件中路径,一定要注意用\\表示,比如 d:\\bitboy\\bitboy.exe  还要有扩展名,name中的进程名不能有扩展名,否则找不到程序,不区分大小写。 24、本软件运行后,会自动启动配置程序路径下的软件,如果该软件不存在,则自动停止监控。所有多余的配置要自行删除,xml文件中不要有注释,没对注释做处理。 25、加入开机自启动选择项,保存到注册表中,加入了默认以管理员身份运行,解决配置文件不在system32下,开机启动找不到配置文件的问题。 26、没有对本程序做单一启动的限制,如果需要只运行一个实例,重新编译程序中注释掉的一部分代码。对多线程运行的程序,建议设置linecount为100,否则会杀死多余的线程,一个循环周期杀一个,线程数量固定不变的可在配置中设置相同的linecount数,这样能达到守护的目的。 27、加了开机启动参数的支持,在配置文件中路径后用英文的逗号作分隔,前面的是路径,后面的是启动参数。 28、支持对多线程运行程序的退出守护,配置文件中,将linecount设置为100,并且要启用多开。当linecount配置为100后,不允许在界面上修改,只能手动打开配置文件修改。启动后检查进程如果没有运行,就运行一次,如果已经存在了则不处理,因为有些程序,要开启很多个线程运行,只有等所有进程都退出之后,才会启动一次守护的进程,之后又会交给程序自适应。 29、增加循环启动时间次数的累计显示,和所有程序累计启动次数不一样,这个指的是定时器执行的次数,不管是否启动了守护的程序,这个周期都是累加,可能没多大意义,另外那个是程序启动一次才加一次。 30、防止任务管理栏结束,甚至采用服务方式启动等,对于我来说太难了,服务启动又带ui交互,好像涉及到session0穿透的问题,能力有限,没有精力搞了。

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧