picturebox刷新问题

龙啸雪 2017-04-10 09:22:19
最近在用C#搞一个软件,从一个内存中读取一个bool数组,然后显示指示灯颜色。但是颜色却一直没变,单步调试时没有问题,但程序跑起来颜色却不会变化。写了个代码试了下也没达到预期目标一个个变色,而是一起变色。应该和这个原理差不多,请问大佬们我该怎么做才能让bool值改变后立刻改变图片颜色?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
listp.Add(pictureBox1);
listp.Add(pictureBox2);
listp.Add(pictureBox3);
listp.Add(pictureBox4);
}
List<PictureBox> listp = new List<PictureBox>();
bool[] bRed = new bool[4];
private void timer1_Tick(object sender, EventArgs e)
{
for (int i = 0; i < 4; i++)
{
if(bRed[i]==false)
{
listp[i].BackColor = Color.Blue;
bRed[i] = true;
}
else
{
listp[i].BackColor = Color.Red;
bRed[i] = false;
}
System.Threading.Thread.Sleep(200);
listp[i].Invalidate();
}
}
}
}
...全文
427 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
xuggzu 2017-04-11
  • 打赏
  • 举报
回复
一个流程不等于代码非要挤到一起。
这样试试:
……,设置form.timer控件间隔小点比如10ms,timer.start(),进入tick(timer.stop(),取数,显示,timer.start()),……
大概这个流程吧(看清括号……)。
龙啸雪 2017-04-11
  • 打赏
  • 举报
回复
引用 5 楼 xuggzu 的回复:
一个循环内做完? 在主线程内难度很大,而且cpu占用率会很高。不建议这么用。就算放到其它线程里做,想一个循环完工也很麻烦。
有些累了,先去休息了。祝大佬好梦。
  • 打赏
  • 举报
回复
顺便我说一下大致是在 VB4~VB6 中使用 Application.DoEvents 方法的问题。它是在 VB 这种不支持多线程的程序中,来模拟类似于“do loop 死循环 + 并发操作”的方式。也就是说,它其实并不是仅仅为了刷新显示。 它强制地提前调用触发 windows UI 消息泵中后边排队的消息,这极容易造成 windows 消息溢出(例如你一个用户移动鼠标的消息处理过程中又间接地触发了用户移动鼠标等),而且如果你调试程序的话,会发现事件处理过程完全“乱跳”,你当前的事件处理过程执行了一部分,然后其它时间处理过程被执行,间接地,又执行其它事件处理,然后又调回之前的事件处理过程的中间..... 这主要是用在 VB。在大量 VB 编程中,假设我们需要“后台处理数据”,就好象你在 c# 中使用子线程来处理数据采集、计算过程一样,那么我们不得不使用 Application.DoEvents,因为 VB 天然就是不支持多线程的。 但是在 VB 中,遇到了大量令人苦恼的 windows 消息处理疯狂溢出、系统内存狂涨、交互处理过程混乱、处理流程死循环等等问题。所以在使用 Application.DoEvents 时要非常非常谨慎,而且要进行无限复杂的测试才可能发现一小部分 bug。所以在 .net 程序中请尽量不要使用 Applciation.DoEvents。在.net 中如果需要并发多线程处理后台数据处理,使用各种各样丰富的子线程、异步编程机制。
龙啸雪 2017-04-11
  • 打赏
  • 举报
回复
谢谢,也就是ui必须释放后才能够刷新。我去试试。
sp1234_maJia 2017-04-11
  • 打赏
  • 举报
回复
sorry,上面少一个 Stop() 语句。
private void Form1_Load(object sender, EventArgs e)
{
    var i = 0;
    timer1.Tick += (s, arg) =>
    {
        label1.Text = "i=" + i.ToString();
        ++i;
        if (i > 20)
        {
            label1.Text = "结束";
            timer1.Stop();
        }
    };
    label1.Text = "启动";
    timer1.Interval = 200;
    timer1.Start();
}
  • 打赏
  • 举报
回复
上面那个例子,在 javascript 中就是写
<script type="text/javascript">
    let i = 0;
    let x = setInterval(function() {
        document.getElementById("xxx").innerText = "i=" + i.toString();
        ++i;
        if (i > 20)
            clearInterval(x);
    }, 200);
</script>
其实设计模式是一样的。只是语法不用而已。 那么为什么网页程序员不会纠结这类问题,而写个 winform 或者 WPF 程序那么高达上的程序,要纠结呢?在 csdn 上还有真么多纠结得帖子呢? 我想说这是 winform、WPF 文章作者太垃圾,只知道抄人家 msdn 之类的介绍语法的文字,不知道从设计模式来讲问题的恶果。因为 javascript 的语法就是那样直接了当的,所以网页程序员很轻地掌握了定时器中操作 javascript 变量地方法,而winform 程序员竟然连在定时器中操作变量 i 都不会,这就是各种“7天学会XXXX”之类的书籍很容易出现的坑爹结果。
  • 打赏
  • 举报
回复
引用 6 楼 u013218269 的回复:
主要是现在工作需要至少在一个流程里需要从内存中抓取2次bool数组,来对颜色进行显示处理。 但是第一次的颜色总是显示不出来。 请问有什么好的方法么?实在不行再建个timer专门显示好像也可以。不过总感觉资源浪费。
现在编程教学很坑爹,许多作者只知道抄国外的编程手册上的文字,而自己不会分析说明设计模式。 实际上,“在一个流程里.......但是颜色总显示不出来”之类的这种逻辑,本身是不符合现在的计算机操作系统体系模式的,也就是说这个说法本身不懂系统 UI 机制造成了问题。你的代码必须“结束”,你必须释放你的控制,让系统的 UI 部分可以获得控制,界面才能刷新,用户的鼠标、键盘等等操作消息才能被系统使用。有人误以为 widows 操作系统是几万个什么“线程”去疯狂地分别处理各自的 UI 刷新事务,这是瞎掰。windows 必须跟你的程序顺序交互! 于是,在编程中去盲目滥用什么数学函数一样的“我输入输出调用一个方法,这个方法里边等待用户响应,给用户刷新界面”的说法,你以后可以记住,这是很可笑的设计流程。真正的交互程序过程,从用户交互开始也止于用户交互。当一个过程中有用户交互,那么用户交互就是你的事件设计的起点(就是上面的 timer1.Tick += 所注册的委托),也是你过程的结束(就好像上面 timer1.Start() 作为过程结束,而不是死等,更不是胡乱弄什么“子线程”)。 写代码是最低级的工作,稍微学懂点编程的人,起码应该会画流程图(稍微多学点,就应该会画类型关联图、活动图、用例图、时序图、状态图,等等设计图)。因为流程图能容易看懂一个人心里到底有没有悟性会设计程序。那么我们其实就经常把一个的脑子的设计变为流程图来理解,发现有的人没有搞懂如何画具有交互的流程图,他胡乱用一个什么“等待用户、给界面刷新、给控件 picturebox1 赋值”这种说法,就以为windows桌面上几百万个控件是个字疯狂地在什么子线程中刷新呢,这显然是尚未学过 UI 相关的设计模式。
  • 打赏
  • 举报
回复
引用 4 楼 u013218269 的回复:
谢谢,主要就是这里没有一个个变色反而一起变色让我搞不懂了。 那么如果我想在一个timer里实现一次循环而非跑完一个timer只更换一个,这样的话我应该怎么做才好?
timer 就是用来定时交互的,而你for 循环是不可能跟用户交互的。 timer 的编程是这样的
private void Form1_Load(object sender, EventArgs e)
{
    var i = 0;
    timer1.Tick += (s, arg) =>
    {
        label1.Text = "i=" + i.ToString();
        ++i;
        if (i > 20)
            label1.Text = "结束";
    };
    label1.Text = "启动";
    timer1.Interval = 200;
    timer1.Start();
}
这就是使用 timer 的方法。 许多时候,你需要用代码来动态控制使用 timer。入门书上可能只有“拖鼠标、用vs设置timer参数”的教程,造成有些人不求甚解而不会用代码来编程使用 timer。
龙啸雪 2017-04-10
  • 打赏
  • 举报
回复
引用 5 楼 xuggzu 的回复:
一个循环内做完? 在主线程内难度很大,而且cpu占用率会很高。不建议这么用。就算放到其它线程里做,想一个循环完工也很麻烦。
主要是现在工作需要至少在一个流程里需要从内存中抓取2次bool数组,来对颜色进行显示处理。 但是第一次的颜色总是显示不出来。 请问有什么好的方法么?实在不行再建个timer专门显示好像也可以。不过总感觉资源浪费。
xuggzu 2017-04-10
  • 打赏
  • 举报
回复
一个循环内做完?
在主线程内难度很大,而且cpu占用率会很高。不建议这么用。就算放到其它线程里做,想一个循环完工也很麻烦。
龙啸雪 2017-04-10
  • 打赏
  • 举报
回复
引用 3 楼 xuggzu 的回复:
楼主的界面会变色,只是一起变,但你代码里有: System.Threading.Thread.Sleep(200); 会阻塞timer1_Tick继续执行200ms,感觉起来界面会一卡一卡的。 timer本身就能设置时间,用不着sleep,而且sleep会阻塞线程,一般不要用到主线程里。
谢谢,主要就是这里没有一个个变色反而一起变色让我搞不懂了。 那么如果我想在一个timer里实现一次循环而非跑完一个timer只更换一个,这样的话我应该怎么做才好?
xuggzu 2017-04-10
  • 打赏
  • 举报
回复
楼主的界面会变色,只是一起变,但你代码里有: System.Threading.Thread.Sleep(200); 会阻塞timer1_Tick继续执行200ms,感觉起来界面会一卡一卡的。 timer本身就能设置时间,用不着sleep,而且sleep会阻塞线程,一般不要用到主线程里。
龙啸雪 2017-04-10
  • 打赏
  • 举报
回复
引用 1 楼 xuggzu 的回复:
楼主代码逻辑有问题,如果要挨个变色,要这样: private int nPicIndex = 0; private void timer1_Tick(object sender, EventArgs e) { int index = nPicIndex % 4; if (!bRed[index]) { listp[index].BackColor = Color.Blue; bRed[index] = true; } else { listp[index].BackColor = Color.Red; bRed[index] = false; } nPicIndex++; }
感谢回答,请问我错在哪里?界面为什么没有及时刷新。
xuggzu 2017-04-10
  • 打赏
  • 举报
回复
楼主代码逻辑有问题,如果要挨个变色,要这样: private int nPicIndex = 0; private void timer1_Tick(object sender, EventArgs e) { int index = nPicIndex % 4; if (!bRed[index]) { listp[index].BackColor = Color.Blue; bRed[index] = true; } else { listp[index].BackColor = Color.Red; bRed[index] = false; } nPicIndex++; }

110,538

社区成员

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

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

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