Page 1 of 1

Slide Show & Desktop Background Tutorial

#1 RexGrammer  Icon User is offline

  • Coding Dynamo
  • member icon

Reputation: 182
  • View blog
  • Posts: 783
  • Joined: 27-October 11

Posted 06 December 2011 - 02:15 PM

Slide Show & Desktop Background Tutorial


In this tutorial I will try to show you how to make a slide show that lets the user select some images and then have them change in the picture box, and also we will implement an advanced feature that changes the desktop backgrounds as same as the picturebox images (this will be an advanced feature)

Again some prep on slide show (Slide Show on Wikipedia)

Let's do a basic step:

Open your IDE and create a project called 'Slide Show' (if you want)

I know you're eager to code but let's first think a bit:

So I imagined the app like this:

1. There will be a picturebox in the middle (I named it picBox)
2. An exit button under it (I named it extBtn)
3. A start button and a stop button over it (I named them startBtn and stopBtn)
4. A button to select the images above all (I named it selectImgsBtn)
5. A textbox to set the timer interval (I named it timerIntervalBox)
6. And a checkbox to select if you want to change the desktop background (I named it setAsWallpaper)
7. A button to reset the original desktop wallpaper (I named it restoreBtn)

But how are we going to realize that:

1. Well we will import some methods from 'user32.dll' to set the desktop wallpaper
2. And we will also need to have a method to get the current wallpaper
3. We would need a string array to hold the file paths, also we need two int (one to hold the total number of images and the other to be the current image counter)

Now we need to design the GUI:

So I came something like this:

Posted Image

I know it looks a little crowded but hey it's nice...

We will leave the methods for setting the desktop wallpaper for the end...

Declarations


So we will need to declare the variables we will be using for the project:

1. As I said we will need a string array to hold the file paths
2. An indicator to set the max number of images
3. An indicator to see what is the current image index
4. And a indicator to see what was the original wallpaper


        //Declare the variables that are used in this project
        //The string array to hold the file paths
        private string[] _filenames;
        //The max number of images
        private int _maxNum;
        //The current image number
        private int _currNum;
        //Declare a string to hold the original wallpaper
        private string _originalWallpaper;



Button Events


Open Button


So now we will code the button that opens the images.

So now you need to add an openFileDialog to the project (you can do that by draging the openFileDialog control from the toolbox to the form)

NOTE: Set the filter property of the openFileDialog to
Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*



NOTE2: Set the 'Multiselect' property of the openFileDialog to true. That will allow to select multiple images as a background.

This will show just images in your dialog (kneat huh?)

Next we will show the dialog and get it's result (what button was pressed)

            //Show the openFileDialog
            DialogResult result = openFileDialog.ShowDialog();




Now we need to check if the user has clicked open

 if (result == DialogResult.OK)
{
}



Next we need to get all the files selected and put them into our string array and set the total number of images

                //Set the array file names to the files the user selected
                _filenames = openFileDialog1.FileNames;
                //Sets the max number of images
                _maxNum = _filenames.GetLength(0);




So the code for the open button click event would be:

Spoiler


Start Button


When you click start the program should try to parse the textbox and if it succeds starts the slideshow

So first we need to limit the textbox input to numbers only:

I found a nice way to do this:

Now take a break from this program, and let's create a custom control:

We want a textBox that accepts only numbers, so the most appropriate name I can think of is numer text box. So name it and drag a textBox to the designer.
The only difference between our control and a textBox is that ours will accept only numbers. So we'll need only to add some code:

Write this in the keypress event of the textbox

Declare a local variable to hold the number (if it is a number)
And set the e.Handled to the opposite of int.TryParse(e.KeyChar.ToString(), out _isNumber)

     int _isNumber = 0;
     e.Handled = !int.TryParse(e.KeyChar.ToString(), out _isNumber);



Next let's do the actual code for the button click event

            //Declares a local variable to hold the timer interval
            int _interval;
            //Tries to parse the timer interval
            //If it is parsed then, if not show a message to the user
            if (int.TryParse(textBox1.Text, out _interval))
            {
                //Sets the timer interval
                timer.Interval = _interval * 1000;
                //Starts the timer
                timer.Start();
            }
            else
                MessageBox.Show("First enter a correct time interval!");



I'm leaving the option that the entered string in the textbox isn't a number (although it's less likely), because the user can copy something and paste it in the textbox and that wont be processed by our previously mentioned code...

Stop Button


This one is supposed to be easy, just stop the timer

timer.Stop()



Close Button


This is also easy, just close the form

Close()



Timer Tick


Now actually comes the hardest part... (but it's not that hard)

First we need to check if there are more images to show, if not then stop the timer and pop a messagebox

if (_currNum < _maxNum)
{
    //TO DO: Code Here
}
else
{
    //Stop the timer
    timer.Stop();
    //Show the message to the user
    MessageBox.Show("No more images ...!");
}



If you want to implement the desktop option later add this in the if statement, it checks if the checkbox is clicked

if (checkBox1.Checked)
{
}



Now for the image changing part:
1. We need to declare an image to hold the current image
2. We need to set the picturebox background image to the previously declared one
3. We need to increase the counter

It could be done like this:

//Image to hold the background is set to the current image
Image image = Image.FromFile(_filenames.ElementAt(_currNum));
//Sets the picturebox background
picBox.BackgroundImage = image;
//Increases the counter
_currNum++;



Note: the picturebox background image could be set in single line
picBox.BackgroundImage = Image.FromFile(_filenames.ElementAt(_currNum));



But I think it's more neat to use the above code... (It's up to you to chose how you want to use in your program)

So actually the full code would be

Spoiler


Now would be a good time to compile, build and test what have we done so far...
So do that (It shouldn't have any errors)...
Do you like that? (It's nice isn't it? :) )

NOTE: Set the 'BackgroundImageLayout' property of the pictureBox to 'stretch' that way any image will fit the pictureBox and you don't have to do it programmaticallly.

Now comes the advanced part:

PInvoke


Now for those who don't know what platform invoke is here ya go

Quote

Question:
What is Pinvoke?

Answer:

Platform invoke is a service that enables managed code to call unmanaged functions implemented in dynamic-link libraries (DLLs), such as those in the Win32 API. It locates and invokes an exported function and marshals its arguments (integers, strings, arrays, structures, and so on) across the interoperation boundary as needed.


Source: DotNetFunda

Now told in normal language it is a service that is used to implement functions located in win32 dlls

So that we can use that we need to add the corresponding using statements to our project

using System.Runtime.InteropServices;
using Microsoft.Win32;



And then we need to implement the function that changes the desktop wallpaper, but first we import the dll holding tha function (the user32.dll)

//Import the dll that holds the desktop changing method
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern Int32 SystemParametersInfo(
    UInt32 action, UInt32 uParam, String vParam, UInt32 winIni);

//Declare the variables used for the calling of the desktop change method
private const UInt32 SPI_SETDESKWALLPAPER = 0x14;
private const UInt32 SPIF_UPDATEINIFILE = 0x01;
private const UInt32 SPIF_SENDWININICHANGE = 0x02;



When we imported the dll we need to declare the variables that are bound to that function

For a list of pinvoke signatures see PINVOKE.NET

For a tutorial on using Win32 API Interop in C# see this tutorial

So now we need to declare our methods for getting and setting the desktop wallpaper

Our method for setting the wallpaper is:

private void SetDesktopWallpaper(String path)
{
    //Call the win32 api that changes the wallpaper
    SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, path,
        SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
}



Also we need to have a method for getting the original wallpaper (we will do this in a different way)

For this we will use the registry.
We will declare a local variable that will hold the reg key that actually holds the wallpaper path
Then we will declare a string that will hold the actual path, get the path the return it

private string GetWallpaper()
{
    //Get the key that holds the wallpaper
    RegistryKey wallPaper = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", false);
    //Set the wallpaper path to the one in the key
    string WallpaperPath = wallPaper.GetValue("WallPaper").ToString();
    //Close the reg key
    wallPaper.Close();
    //Return the wallpaper
    return WallpaperPath;
}



So now we need to code the button that will restore the original wallpaper

Form Load


As soon as the form loads we need to set the original wallpaper

So this goes in the form load event

            //Set the original wallpaper to the current one
            _originalWallpaper = GetWallpaper();



Restore Button


We need to set the wallpaper (using our method) to the original wallpaper

Since this is actually meddling with windows we will implement a safety mechanism... (Not that this is much of a safety mechanism HAHA! :) )

            //Try this line of code, if it throws an exception
            try
            {
                //Restore the original wallpaper
                SetDesktopWallpaper(_originalWallpaper);
            }
            catch (Exception ex)
            {
                //Catch it and show it to the user
                MessageBox.Show("There was an error in setting the desktop background! " + ex.Message);
            }



Now we will return to the timer tick event...
Remember the 'TO DO' we added?

Now is the time to replace it...

We will also implement a safety mechanism here also (you remember, the useless one, that just shows a message? )

So set the desktop wallpaper to the current path (from the string array of paths we set in the open button)

                    //Try this line of code, if it throws an exception
                    try
                    {
                        //Set the desktop wallpaper
                        SetDesktopWallpaper(_filenames.ElementAt(_currNum));
                    }
                    catch (Exception ex)
                    {
                        //Catch it and show it to the user
                        MessageBox.Show("There was an error in setting the desktop background! " + ex.Message);
                    }



Well that was the end, if you need extra source download the solution I uploaded here...

NOTE: The solution uploaded here could get outdated so I suggest you visit my GitHub

Full Code Here:
Spoiler


If you still need extra guidance please post it here so that I can help you...

Also if you find any bugs post them to the GitHub interface...

This post has been edited by Atli: 07 January 2012 - 07:12 AM


Is This A Good Question/Topic? 1
  • +

Replies To: Slide Show & Desktop Background Tutorial

#2 tlhIn`toq  Icon User is online

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5625
  • View blog
  • Posts: 12,064
  • Joined: 02-June 10

Posted 06 January 2012 - 09:10 AM

Nice use of PInvoke and showing how to do intermediate-level programming.

It would be nice to see the ENTIRE code at the end, just because its sometimes hard to follow a tutorial saying "Add this after that last bit"... "Change the part we did earlier to this xxx..." and so on

string[] Really? How CIS101. Personally I'd use something more advanced like List<string>

Image image = Image.FromFile(_filenames.ElementAt(_currNum));
Image.FromFile generally is something I avoid. It keeps a link to the file on the harddrive. As long as your Image is within scope in your application you can't do anything with the file on the hard disc. As a rule its a lot better to read it in and make a clone of it then release the link to the HDD. Or read it it as a byte[] then generate an image from that.

You're using a textbox for inputing a strictly numeric value? Come on... We teach better than this. Either take the extra 5 minutes to make a numericTextBox or use a numericUpDown control. Again, this is the type of thing we see first year students doing then asking us how to fix it.

textbox1... checkbox1... We try to teach the rookies to immediately give meaningful names to their controls.
tbSlideInterval... chkUseDeskTop.... and so on. This makes your code far more maintainable especially when you revisit an application after 6 months.
Was This Post Helpful? 0
  • +
  • -

#3 RexGrammer  Icon User is offline

  • Coding Dynamo
  • member icon

Reputation: 182
  • View blog
  • Posts: 783
  • Joined: 27-October 11

Posted 07 January 2012 - 06:13 AM

I submited this tutorial about two months ago, and then honestly I was a rookie. I'm going to update the tutorial as soon as I can. So that's how I explain why I used bad naming, and didn't create a numericTextBox (Not, that it's much of a excuse tho).

As for the string[], I thought about using a list of strings, but I concluded I don't need the dynamicnes of the List. In this case a list would behave the same as an array. The main reason I use a list is because it's dynamic, unlike the array, and in this case you don't need that dynamicness so that's why I used an array instead of the list.

Oh, thanks about the information about using Image.FromFile, I didn't know that.

I'm off to updating those things you told me about.

UPDATE: I updated everything (Actually Atli did, Thanks!) except the Image.FromFile because I'm away from my dev machine and I need it to test the alternative out and the string[]/List<string> (Honestly I don't see the benefit of using a list of strings instead of a string array in this specific application. Maybe it will be of use if I update the application and add functionality, but I doubt I will update it much since I made it mostly for tutorial purposes.)

This post has been edited by RexGrammer: 08 January 2012 - 06:49 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1