3

I am creating a simple form based message display system, each message is a jpeg image, what I want to achieve is when the program loads (just after a user has logged on) one of the jpg's is randomly selected and shown, if the user clicks the Next button another jpg is shown until all have been displayed. I think I need to read each image into an array and then randomly select one from the array and then when a user clicks Next move on to the next item in the array. One caveat is that I don't want the program to lock open the jpg files as others need to be able to delete them.

My current code is below, I would appreciate any help and advice you can offer.

private void Form1_Load(object sender, EventArgs e)
 {
      var rand = new Random();
      var files = Directory.GetFiles(@"\\server\screens\", "*.jpg");
      pictureBox1.Image = System.Drawing.Bitmap.FromFile(files[rand.Next(files.Length)]);  
 }

private void buttonNextImage_Click(object sender, EventArgs e)
 {
      var rand = new Random();
      var files = Directory.GetFiles(@"\\server\screens\", "*.jpg");
      pictureBox1.Image = System.Drawing.Bitmap.FromFile(files[rand.Next(files.Length)]);
 }

Many thanks Steven

Steve Wood
  • 665
  • 5
  • 11
  • 15
  • What's wrong with the code you posted, exactly? – Blorgbeard Jan 10 '11 at 10:25
  • The current code locks the file open and I don't know how to create an array of images. Thanks – Steve Wood Jan 10 '11 at 10:30
  • One thing worth pointing out... Using `rand.Next`, there's a possibility you won't go through all the files in the array. Please refer to [my answer below](http://stackoverflow.com/questions/4645704/c-display-images-randomly-and-one-after-another/4645955#4645955) for how to go about the shuffling/randomisation. – Alex Essilfie Jan 10 '11 at 11:44

7 Answers7

3

Don't use Bitmap.FromFile, use Bitmap.FromStream:

using(var fs = new FileStream(files[rand.Next(files.Length),
                              FileMode.Open, FileAccess.Read))
{
    pictureBox1.Image = System.Drawing.Bitmap.FromStream(fs);
}

I don't know how to create an array of images

var files = Directory.GetFiles("\\\\server\\screens\\", "*.jpg");
var images = new Image[files.Length];
for(int i = 0; i < files.Length; ++i)
{
    using(var fs = new FileStream(files[i], FileMode.Open, FileAccess.Read))
    {
        images[i] = System.Drawing.Image.FromStream(fs);
    }
}
max
  • 33,369
  • 7
  • 73
  • 84
  • Hi Max, This works well but display the same image more than once, how can I fix this? Thanks – Steve Wood Jan 10 '11 at 11:17
  • I do not have edit privileges, however, I believe the first line of code is missing a right bracket and should read: using(var fs = new FileStream(files[rand.Next(files.Length)], FileMode.Open, FileAccess.Read)) – joeschwa Sep 04 '11 at 00:46
2

Two things here:

  1. Move your random instance out to a class member so that it wil only be instantiated once.
  2. After you display the image, remove it from the files array so that only the images you have not shown remain in the list. When the list is empty, you know you have shown them all.
Øyvind Bråthen
  • 59,338
  • 27
  • 124
  • 151
0
public static int id = 0;
private void timer1_Tick(object sender, EventArgs e)
{
    id = id + 1;
    filelocation = "E:\\example\\" + id + ".bmp";
    pictureBox1.Image = System.Drawing.Bitmap.FromFile(filelocation);
}
SztupY
  • 10,291
  • 8
  • 64
  • 87
0

Expanding on Øyvind Bråthen's answer, you could reset the array once all pictures have been shown, also you could maybe use a timer to, every so often automatically change the image?

Todd Davies
  • 5,484
  • 8
  • 47
  • 71
0

I believe that you've 2 options:

a) You load JPG files into memory streams (worst option).

b) You create temp files with the same name and a suffix like "tmp" (i.e. "1.tmp.jpg").

Directly taking "b", after creating the copies, you'd make an index of those files you want to show randomnly in the class level.

After that, using some sort of timer in order to change the image after every tick.

Finally, after every tick, you can synchronize that array of file paths to let your program show the latest and up-to-date ones.

This is my suggestion :)

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
0

List of tips:

  • Don't make an array of pictures; make a HashSet<string> of filenames you've already shown. Then, when NEXT is clicked, iterate through the folder again and ignore the filenames you've already shown. From what remains (if any), pick one at random. This way, even if folder contents change in runtime, you'll still get the most of it. And you won't waste memory by loading all images at once.
  • When it's time to display a picture, load it like you do, then Clone() it, and then Dispose() the original. That way it doesn't lock the file.
  • When showing the next image, don't forget to Dispose() the previous one to free up resources.
Vilx-
  • 104,512
  • 87
  • 279
  • 422
0

Here's a general way to go about your request.

  1. Load all the jpeg files in the directory of choice (from your sample, \\Server\Screens\) into an array.

  2. Randomize the file array. Here is a sample implementation of shuffling an array: Most efficient way to randomly shuffle a list of integers

  3. Load the first picture in the array. The array obviously contains the file names so you cannot just point the PictureBox's Image property to the desired element; you'll have to load the image.

    Since you don't want to lock the images, it is recommended to load the images from a stream (refer to @max's answer).

  4. When the user clicks on the next button, load the next picture. You'll have to check if the file exists since from your question, I infer a user might delete a file before it's loaded.

Community
  • 1
  • 1
Alex Essilfie
  • 12,339
  • 9
  • 70
  • 108