RSS Search

News  Feeds  Tags  Search Shortcuts

FeedsFarm.com > Wallpaper Cycler

Wallpaper Cycler

13th Nov 2006, 20:25 GMT

This sample demonstrate simple wallpaper cycler. It expects a folder in which it will find images. Upon startup, it will change the wallpaper, and it will even modify the placement behavior based on the size of the image found. Arian Kulp Arian Kulp's Blog Difficulty: Easy Time Required: 1-3 hours Cost: Free Software: Visual Basic or Visual C# Express Editions Hardware: Download: C# Download VB Download A number of articles ago, a simple wallpaper utility was written. I thought it would be nice to put together some of the concepts that we've looked at recently and create a new, enhanced wallpaper changer. Specifically, this application is no longer based on a specific file. Instead, it expects a folder in which it will find images. Upon startup, it will change the wallpaper, and it will even modify the placement behavior based on the size of the image found. You can read the article now, but for added benefit download a copy of Visual Studio 2005 Express Edition for C# or Visual Basic. These are free if downloaded during most of 2006, and provide all of the tools necessary to create great applications. After you install Visual Studio Express, download the code for this article from the links at the top. Choose from C# or Visual Basic, according to your personal preference—the applications are functionally identical. As with most recent In the Box columns, this application will start with no visible interface beyond its notification icon in the system tray. The available options will be to display the settings, change the wallpaper on-demand, or exit. The "Show Settings" option is in bold. This is a visual cue that if you double-click the icon, this is the action that will take place. There is no built-in support for this feature. Simply set the menu item's Font.Bold property to "True" and create a MouseDoubleClick event handler for the NotifyIcon control. Figure 1: The notification icon menu Scanning folders The heart of the application is its ability to scan a folder randomly to find an image to display as the desktop background. This is surprisingly easy using the System.IO.Directory class. Its static/shared GetFiles method returns a collection of all files in a given folder. You can optionally pass a wildcard pattern, and a recursive qualifier. It would have made sense to specify a wildcard pattern including extensions like .JPG and .GIF, but apparently only a single expression can be used. The third parameter takes an argument of type System.IO.SearchOption. This is where you can specify a top-level file listing (TopDirectoryOnly), or a recursive (AllDirectories) one. Visual Basic ' Specify top-level or sub-folders Dim opt As System.IO.SearchOption = _ System.IO.SearchOption.TopDirectoryOnly If subfoldersCheckbox.Checked Then opt = System.IO.SearchOption.AllDirectories End If ' Grab complete list of files Dim files As String() = System.IO.Directory.GetFiles( _ picturesPathTextBox.Text, "*", opt) Visual C# // Specify top-level or sub-folders System.IO.SearchOption opt = System.IO.SearchOption.TopDirectoryOnly; if( FsubfoldersCheckbox.Checked ) opt = System.IO.SearchOption.AllDirectories; // Grab complete list of files string[] files = System.IO.Directory.GetFiles( picturesPathTextBox.Text, "*", opt); At this point, the files object contains an array of strings. Each entry is a fully-qualified filename from within the supplied folder. It would be nice to just randomly select an entry from this collection, but recall that we were not able to filter based on file extension. This must be done now. Two other exclusions also apply. First, we don't want to select the file that was used last time (we save one time back). Second, we don't want to select the temporary image that we generate (discussed later). The following code demonstrates copying the array into a generic List collection, element by element, provided that each element meets our exacting criteria. Visual Basic ' Filter list to remove non-images, last image shown, ' and the app-generated BMP file from a previous run. Dim filteredFiles As New List(Of String)() For Each file As String In files Dim ext As String = file.Substring(file.LastIndexOf(".")) If ".jpg .bmp .gif".IndexOf(ext) > -1 AndAlso _ file.EndsWith("coding4fun-desktop.bmp") = False AndAlso _ Not file = My.Settings.LastImageShown Then filteredFiles.Add(file) End If Next Visual C# // Filter list to remove non-images, last image shown, // and the app-generated BMP file from a previous run. List filteredFiles = new List(); foreach (string file in files) { string ext = file.Substring(file.LastIndexOf(".")); if (".jpg .bmp .gif".IndexOf(ext) > -1 && !file.EndsWith("coding4fun-desktop.bmp") && file != settings.LastImageShown) { filteredFiles.Add(file); } } After all of this processing, it is possible that no files remain in our collection. Perhaps the folder was empty initially, none of the files were images, or the only image found was used last time. Either nothing will be returned, or a random index will be generated to grab one element out of the collection. Recall that these elements are full pathnames. We will save that pathname as the LastImageShown setting, create a Bitmap object given the pathname, then return that object. Visual Basic ' Make sure there are any files left If filteredFiles.Count = 0 Then Return Nothing ' Randomly grab a file Dim filename As String = filteredFiles(rnd.Next(filteredFiles.Count)) ' Remember last image shown My.Settings.LastImageShown = filename My.Settings.Save() ' Return the bitmap object from this filename Return New Bitmap(filename) Visual C# // Make sure there are any files left if (filteredFiles.Count == 0) return null; // Randomly grab a file string filename = filteredFiles[rnd.Next(filteredFiles.Count)]; // Remember last image shown settings.LastImageShown = filename; settings.Save(); // Return the bitmap object from this filename return new Bitmap(filename); Finally the image is saved as a BMP file in the My Pictures folder, and passed to the appropriate system API function, SystemParametersInfo , to effect the change. Most of this is the same as in the original In the Box column referenced above, but the original required an image to be in BMP format to begin with. As it turns out, once you have loaded an image into a Bitmap object, saving as a BMP file format is a single line of code: Visual Basic ' Convert to BMP and save img.Save(picturesPath, System.Drawing.Imaging.ImageFormat.Bmp) Visual C# // Convert to BMP and save) img.Save(picturesPath, System.Drawing.Imaging.ImageFormat.Bmp); Study the SetDesktopBackground static/shared method in WindowsAPI.vb/.cs to see the implementation details. Settings Because the image to display can vary wildly each time, the settings dialog includes a number of behavioral settings. The first checkbox allows you to specify if sub-folders should be scanned or not. If you are pointing at a collection of home photos divided into sub-folders for albums, this could be useful. The three ComboBox controls allow some flexibility in how images are displayed depending on their size relative to the desktop size. By default, images larger than the desktop will be stretched to fit. Now the term "stretched" is taken from the Windows Display control panel. It's a bit of a misnomer, since what it really means is "stretched or shrunk" in either direction to exactly fill the screen. It's really ugly if you have a widescreen display and conventional (4:3) images. Images smaller than the screen will be centered. The final category, Tiled, is a bit more flexible. If you have very small images, you may want to tile them for a repeating pattern. Just specify how small is small (128 pixels in both directions, by default), specify the action (it doesn't need to be Tiled), and watch it go. I personally like the defaults, but it made some sense to allow them to be preferences so anyone can change them easily. Figure 2: Settings dialog All of the settings directly correspond to project settings defined in Visual Studio. This nifty feature lets you define settings at the user or application level, set a datatype, and even a default value. Then, to complete the coolness, you can actually databind these settings to the controls. All you need to do is load and save when necessary. The mechanics of copying data between controls and settings are taken care of for you! Figure 3: Databinding settings Working with the Registry The application must write to the registry in order to set the stretched/tiled/centered attributes. This is very easy using the Registry object. Just use a static property, such as CurrentUser to access the HKEY_CURRENT_USER key. You can dig deeper by using a method like OpenSubKey to open nested keys and access their values. The wallpaper cycler application also uses the registry to add itself to Windows startup. The auto-start CheckBox control calls some shared/static methods in the WindowsAPI class to add and remove itself: Visual Basic ' Based on checkbox, call API functions to add or remove ' application path from registry Run section for current user. If autostartCheckbox.Checked Then WindowsAPI.AddStartupItem("BackgroundCycler", _ System.Reflection.Assembly.GetEntryAssembly().Location) Else WindowsAPI.RemoveStartupItem("BackgroundCycler") End If Visual C# // Based on checkbox, call API functions to add or remove // application path from registry Run section for current user. if (autostartCheckbox.Checked) { WindowsAPI.AddStartupItem("BackgroundCycler", System.Reflection.Assembly.GetEntryAssembly().Location); } else { WindowsAPI.RemoveStartupItem("BackgroundCycler"); } Notice the call to System.Reflection.Assembly class. The GetEntryAssembly method returns a reference to the assembly that contained the startup code for the current application. The Location property returns the assembly filename, in this case the path to the executable file. In the AddStartupItem method, the sub-key for the current user's Run entries is opened, and a new value is added. So simple, but so powerful: Visual Basic Dim key As RegistryKey = _ Registry.CurrentUser.OpenSubKey( _ "Software\Microsoft\Windows\CurrentVersion\Run", True) key.SetValue(name, path) Visual C# RegistryKey key = Registry.CurrentUser.OpenSubKey( @"Software\Microsoft\Windows\CurrentVersion\Run", true); key.SetValue(name, path); Potential Enhancements The application is ready to use, and fun too! You can change wallpaper frequently, even if your images are not already in BMP format, and you don't need to go into Desktop properties to do it. It might also be fun to add an option to automatically change images on a timed interval. Another challenge would be to provide the ability to download images at random from URLs. You could provide a URL to an image gallery, scan the HTML for image links, then randomly select one to download, convert, and show as wallpaper. Lots of options! Conclusion I hope this got you thinking about things to do with the Bitmap object, the Registry object, and desktop interaction. Be sure to visit http://msdn.microsoft.com/vstudio/express/ to download your preferred version of Visual Studio 2005 Express Edition. Then, take a look at the source code for this project, learn, and do even more. Good luck, and best of all, have fun!

View full story at blogs.msdn.com

Wallpaper Cycler related news:

Latest news from Coding4Fun's WebLog: