Issues covered
This article explains how to:
- Display .NET framework supported image types (JPG, JPEG, GIF, PNG, TIF...) into a form.
In addition, the code covers:
- Accessing the Registry (creating, writing, retrieving registry key values).
- Using WinForm controls like StatusBar, ToolBar, MainMenu, ImageList, Timer and, OpenFileDialog.
- Processing command-line arguments.
- To obtain the list of files in a directory.
- To create a Windows Application setup project
Introduction
You always need to access images for some reason or the other. When you have the .NET framework SDK with you, you needn't bother to buy other applications for that job - develop one for yourself! With the supremely rich .NET framework, manipulating images is very simple. This article places emphasis only on how to display images. The code on the other hand, involves a lot of other stuff including a setup, which were used to implement a number of standard features seen in popular applications. They are quite straight forward; so you could understand them by yourself.
Apart from the usual set, this application uses the following namespaces too:
System.Drawing
- For displaying images
System.Drawing.Drawing2D
- For displaying images
Microsoft.Win32
- For accessing the registry
The code explained
To load images (technically 'draw'), you use any one of the 30 overloads of: System.Drawing.Graphics.DrawImage(...)
.
As is evident, DrawImage()
is a method of the Graphics
class. So, before using DrawImage()
straightaway, you need to create a Graphics
object. This Graphics
object would be of the form you are going to draw the image onto. Typically, you create this object in the Paint Handler of the form. An example for a Paint Handler is:
private void MainForm_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
...
}
When someone calls a form's paint handler, some data regarding the form's graphics stuff is passed to it. This data is held in the
PaintEventArgs
object, in this case, the object e. This object has a property
Graphics
- and that's exactly what we want. You just use it to initialize your own
Graphics
object, like this:
Graphics g = e.Graphics;
So, now that you have a Graphics
object, you could call the DrawImage()
method. But wait, what about the arguments? That's what we are going to see. The overload I will discuss here is:
public void DrawImage(
Image image,
RectangleF rect
);
This method draws the specified Image
object (System.Drawing.Image
), at the specified location and with the specified size (passed implicitly through the RectangleF
object - rect). An Image
object holds the actual image data that is to be drawn. And with little thinking, you could easily understand that with a RectangleF
object you could define both the size and position of the image.
So how do we develop these arguments?
System.Drawing.Image
is an abstract class, designed to act as the base for System.Drawing.Bitmap
and System.Drawing.Imaging.Metafile
. What we are interested in is System.Drawing.Bitmap
. We create an Image
object using the Bitmap
class, like this:
MyBitmap = new Bitmap(...);
There are 12 overloads for the
Bitmap
constructor. The one I will discuss here is:
public Bitmap(
string filename
);
You just need to pass the path to the image file you want to load. And then, you have the initialized Image
object. What remains is the RectangleF
object which you could initialize as you wish. Once done, call the DrawImage()
method, and there you are, you have done it!
An example code listing for the actions discussed above:
private void MainForm_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
...
...
Graphics g = e.Graphics;
MyBitmap = new Bitmap("c:\\image.bmp");
g.DrawImage( MyBitmap, new RectangleF(MyPoint.X, MyPoint.Y,
MyBitmap.Width*(fScale), MyBitmap.Height*(fScale)) );
...br> ...
}
Code for the additional features
This section discusses the way the rest of the application is designed. Since an exhaustive explanation would be beyond the scope of this article, I would only give you a brief description of the regions used. Read the code, read this description; and you would understand (hopefully). Here goes:
The My Vars Declaration
region declares all the variables that are used. These variables are sub-divided according to their functionality. Some of these are initialized to their default values in the declaration itself.
The App Main Entry
region encapsulates the application Main
function as well as the main form constructors. When the app is executed, the Main
function determines whether there are any command-line arguments [file to be displayed], and invokes the required overloaded main form constructor, passing the argument if necessary. The main form constructor, would then set the current directory to that of the argument in case there exists one. It also sets the szRequestedFile
variable to the argument value.
The Main Form Load
region consists of the main form load function, which calls the GetRegistrySettings
function to retrieve values from the current user's registry, makes sure that the timer is not on, initializes the FileTypes
ArrayList, sets all the from controls to the registry values by calling the SetControlsToRegistrySettings
function, processes the current folder by calling the ProcessDirectory
function, and displays the image if necessary in either the normal mode or the slide show mode.
The Main Form Paint Handler
region comprises of the most complicated and used function in the app - the paint function. This function starts by setting the status bar text to Working...
, proceeds to initialize a Graphics
object, sees whether the 'size to fit' option is true or false, determines the position where the image is to displayed, draws it, and finally sets the status bar text to Ready
.
The Main Form Paint Handler
region consists of a number of functions designed for different activities.
GetRegistrySettings
gets the current user's registry settings from the registry and initializes the registry variables.
SetControlsToRegistrySettings
resets the form controls so as to set it to the current user's settings.
SetSize
resizes the form according to the current Image's size.
ProcessDirectory
finds out all the images within the current folder and initializes FileArray
.
GetFilePath
get's the currently selected file's path from FileArray
.
SetPicture
sets variables to the selected file's attributes and invokes the paint handler.
The EventHandlers
region consists of handlers for the menu events, toolbar events, mouse move event, form resize event as well as the timer elapsed event. Each of these events call the DoAction
function to carry out the required function if appropriate.
The DoAction
function lies within the Do Action Handler
region. This function incorporates all the possible actions that would be invoked within this app. This function was developed in order to reduce redundant code that would have to be coded for both the toolbar as well as the main menu. Plus this model reduces complexity.
For the experimentalist: in case you ever want to add more features, follow these simple steps:
- In the
My Vars Declaration
region, add the required variables in the specific section. This is to make matters organized.
- Expand the
Do Action Handler
region. Within the list of existing cases, add a new one defining the action to be carried out.
- When an event occurs where the new action is to be executed, call
DoAction
passing the name of the action just defined.
Conclusion
This is a very simple application with a simple design and simple architecture. But it works! And that's exactly what we want.
Happy programming...