pictureBox一步一步运行的很好,但是执行的时候好像每次都执行两次timer tick

pictureBox works fine step by step, but when executed, it seems to execute the timer tick twice each time

我正在制作一个简单的屏幕保护程序,它显示一组图片,在显示所有图片之前不重复它们。问题是,图片框正在跳过一些更新或其他内容,或者在两张图片之间快速切换。其他时候它在同一张图片上停留的时间太长。

它在调试模式下工作得很好,即使我多次点击继续,除非我点击继续太快。

图片框更新与每 2 秒触发一次的计时器相关联。

private void timer1_Tick(object sender, EventArgs e)
    {
        if (pictureBox1.Image != null) { pictureBox1.Image.Dispose();}
        pictureBox1.Image = (Image)siguienteImagenAMostrar.Clone(); 
        //siguienteImagenAMostrar is an Image, and it´s the one i want to show next 
        pictureBox1.Invalidate();
        pictureBox1.Update();
        if (siguienteImagenAMostrar != null) { siguienteImagenAMostrar.Dispose(); }
        siguienteImagenAMostrar = siguienteImagen(); //I try to preload the Image         
    }

这是 siguienteImagen() 代码,以防它与我使用的 Random 有关:

private Image siguienteImagen()
        {
            int imagenAmostrar;
            do
            {
                imagenAmostrar = rand.Next(0, files.Length);
            } while (currentImage == imagenAmostrar && files.Length > 1);

            int original = imagenAmostrar;

            if (mostrada[imagenAmostrar]) {
                imagenAmostrar = (imagenAmostrar + 1) % files.Length;
                while (mostrada[imagenAmostrar] && original != imagenAmostrar)
                {
                    imagenAmostrar = (imagenAmostrar + 1) % files.Length;
                }
                if (imagenAmostrar == original) 
                {
                    mostrada = Enumerable.Repeat(false, files.Length).ToArray();
                }
            }
            mostrada[imagenAmostrar] = true;
            currentImage = imagenAmostrar;
            string imagenMostrarString = files[imagenAmostrar];
            return Image.FromFile(imagenMostrarString);

        }

编辑:这个功能似乎不是问题,因为简单地选择下一张图片 currentImage = (currentImage + 1) % files.Length 仍然存在无法正确显示图片的问题。

另外 mostrada 是一个布尔数组,它知道该图片是否已经显示。 files 是一个包含图片路径的数组。相同的索引代表两者上的相同图像。

我敢打赌,如果您避免获得可能已被使用的随机数,这将使您的代码更清晰,对您和执行的工作更少。使用布尔数组来跟踪这一点可能会浪费循环时间,因为随机数生成器可能会生成一个已经选择的值。我想你会想避免这种情况。

一种可能的解决方案是从图像集合中创建 List<int> 索引。例如图像集合有五 (5) 张图像,那么这个列表看起来像......

Index    value
  0        0
  1        1
  2        2
  3        3
  4        4

我们希望“保留”此列表的副本,因为在浏览完所有图像后我们将需要它。因此,假设 rand.Next(0, listAbove.Count); 中的第一个随机数是 3。然后我们将从索引 3 中获取值,这也是索引三 (3)。我们在索引三 (3) 处获取图像并从列表中“删除”三 (3)。在此之后,列表看起来像......

Index    value
  0        0
  1        1
  2        2
  3        4

以这种方式继续,直到列表为空,此时我们只需重新填充即可。

鉴于这会创建两个 List<int> 变量…

List<int> fullImageListIndexes;
List<int> currentImageIndexes;
Random rand = new Random();

现在我们需要一种方法,该方法 returns 从该列表中随机获取图像。 Random 调用的边界将为列表大小的零 (0)。找到随机索引后,我们将其从列表中“删除”。这将减小列表大小并保证始终只有一 (1) 次调用随机数生成器。以这种方式继续,我们只需要检查图像列表是否为空,这表明我们已经使用了所有图像并且需要用原始值“重新填充”列表。我希望这是有道理的。

下面是returns下一个随机图像的方法...首先检查列表是否为空,如果是,只需重新填充即可。根据列表的大小获取下一个随机索引,获取原始图像索引的值,然后获取该图像,最后“删除”我们刚刚使用的图像索引。

private Image GetNextRandomImage() {
  if (currentImageIndexes.Count == 0) {
    //textBox1.Text += "Refill" + Environment.NewLine;
    currentImageIndexes = new List<int>(fullImageListIndexes);
  }
  int randomIndex = rand.Next(0, currentImageIndexes.Count);
  int valueToRemove = currentImageIndexes[randomIndex];
  Image nextImage = imageList1.Images[valueToRemove];
  currentImageIndexes.Remove(valueToRemove);
  //textBox1.Text += "Tick : RI: " + randomIndex + "  SV: " + valueToRemove + Environment.NewLine;
  return nextImage;
}

定时器滴答事件…

private void timer1_Tick(object sender, EventArgs e) {
  pictureBox1.Image = GetNextRandomImage();
}

最后把它们放在一起...... imageList1 是一个 .Net 图像列表对象,其图像集合中添加了一些图像…

public Form1() {
  InitializeComponent();
  fullImageListIndexes = new List<int>();
  for (int i = 0; i < imageList1.Images.Count; i++) {
    fullImageListIndexes.Add(i);
  }
  currentImageIndexes = new List<int>(fullImageListIndexes);
}

希望这是有道理的。

发生的事情是我在 form_load() 函数中有 timer1.Tick += new EventHandler(timer1_Tick);。我仍然不确定为什么它在逐步模式下工作

删除明显多余的 EventHandler,解决了我的问题。