【问题标题】:pictureBox works fine step by step, but when executed, it seems to execute the timer tick twice each time图片框一步一步工作正常,但执行时,似乎每次执行两次定时器滴答
【发布时间】:2020-10-28 10:58:59
【问题描述】:

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

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

图片框更新与每 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 也是一个 bool 数组,它知道该图片是否已经显示。 files 是一个包含图片路径的数组。相同的索引在两者上代表相同的图像。

【问题讨论】:

  • 你得到一个随机数。然后给它加一个,还要取模它。这似乎是多余的。
  • @John 那段代码是我发现的在 bool 数组中循环的方式,试图找到一些错误值,这意味着我还没有显示该图像。
  • 我会创建一个列表的副本,虽然它不是空的,但选择并删除一个随机项目。 - 另外remommended 将处理图像
  • @TaW 我没想过这样做。这似乎是一种更好的方法

标签: c# .net winforms picturebox


【解决方案1】:

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

一种可能的解决方案是从图像集合中创建索引的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();

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

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

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);
}

希望这是有道理的。

【讨论】:

  • 首先,感谢您提供如此详细的回答。我已经尝试过了,它确实以与我的算法相同的方式以更好的方式选择图像。问题是,即使 GetNextRandomImage() 只是 currentImage+1,图片仍然不总是显示
  • @yaexiste2... 我已经测试了发布的代码,它按预期工作。很难理解你的意思……“即使 GetNextRandomImage() 只是 currentImage+1”……这没有意义。当前图像 + 1 是什么?
  • 我遇到的问题是图片框的更新,而不是选择它们的算法。我已经发现了这个问题,我在这篇文章的答案中说明了这个问题,但它并没有让我再接受几个小时。问题是tick事件被调用了两次,因此有时会产生奇怪的事情
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多