Before I start my third article, let me thank to Chandana Subasinghe for his article about the TreeView
. I was looking to create my application using drive and file controls, but because I found his code, and it was easy to understand, I took it and enhanced it and implemented into my application. After all, I think we should do that often to learn new things.
Introduction
This application is called "Virtual Photo Album". I didn't use any third party components, so it should be easy for you to download the code and play with it. I will try not to use any third party components while I am learning C#.
Features
- Locate and create separate album files of any images in your computer or combination of network computers
- Rotate and save images
- Start Slideshows for any album you selected
The idea of this program is that if you do have many photos and just want to show a few from here and a few from there to your friends and families... you don't have to move them into one folder, instead you can make a list of the images you want to show to different people. It creates different files with ".vpa" extension (Visual Photo Album) which are text files that go into "data" folder, which also sits in the application folder. Even if your photos are organized very well, it's just to make things easier if you want to combine a few photos from separate locations.
Background
There are no databases but only files to keep the path of the images. Each is named differently and can be accessed through the drop down in the menu bar. Even though I showed some basic code in my past articles, I would like to refresh some of them here. Since this is the beginner section, there is no harm in repeating stuff.
Using the Code
This program has less items in it. Only one form and a class module.
Form1
(Main Form)
- FileExplorer.cs (Class module that does
TreeView
loading) I kept its original name from Chandana Subasinghe's article
Since the entire code is available for download, I will start with some simple stuff, and probably keep it simple in this entire article. Please feel free to play with the code, and see if you can come up with something better.
private void FileListCheck()
{
if (Directory.Exists(@"data") == false) {
Directory.CreateDirectory(@"data");
WriteReadmeText(); }
else
{
if (File.Exists(@"data\\readme.txt") == false) {
WriteReadmeText(); }
}
string[] MyFiles = Directory.GetFiles(@"data","*.vpa");
if (MyFiles.Length > 0) {
char Splitchr = (char)92; string[] SplitText;
TSFiles.Items.Clear();
foreach (string ReadFiles in MyFiles)
{
SplitText = ReadFiles.Split(Splitchr);
TSFiles.Items.Add(SplitText.GetValue(SplitText.GetUpperBound(0)));
}
}
}
'Directory.Exists'
and 'File.Exists'
here from System.IO
namespace check if my folder and file already exist. In my past applications, I used SystemFile
object to do that, I honestly didn't know System.IO
was available for me.
You can also see how 'Split' is done and how I actually used 'GetUpperBound
' of the 'Split
' method to fill my ListVie
w's 'Name
' field.
private void WriteReadmeText() {
StreamWriter ReadMeFile;
ReadMeFile = new StreamWriter(@"data\\readme.txt");
ReadMeFile.WriteLine("Please do not delete files in this folder.");
ReadMeFile.WriteLine("This folder used by 'Virtual Photo Album' - Copyrights (2010)");
ReadMeFile.WriteLine("If you'd like more information about the
software and/or its author,");
ReadMeFile.WriteLine("please contact 'Leo Koach' or click on
'help' button on the program.");
ReadMeFile.Close();
}
This is a very simple 'File Write' method. Here I am creating my 'Readme.txt' file. Sometimes, we should leave some sort of clues to people what the files are in our application folders, so they won't play with them and break the program.
private void fleExp_AfterSelect(object sender, TreeViewEventArgs e)
{
picBox.ImageLocation = "";
if (fleExp.SelectedNode.ImageIndex == 3) {
picBox.ImageLocation = fleExp.SelectedNode.FullPath; }
}
Here I used (cheat) 'ImageIndex'
to find out my images in TreeView
to show them on the PictureBox
. All image files that I can show in the PictureBox
get the same icon, which is #3 here. 'fleExp.SelectedNode.FullPath'
gets me the whole path for the file.
private void ImgRotation(string IRotateValue, string ICurrentImagePath)
{
try
{
if (picBox.ImageLocation == @"missing.png") {
MessageBox.Show("Can not rotate default image", "Invalid Image",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return; } else {
Bitmap Rotate_Bitmap = new Bitmap(ICurrentImagePath);
switch (IRotateValue) {
case "0": Rotate_Bitmap.RotateFlip(RotateFlipType.RotateNoneFlipNone);
break;
case "1": Rotate_Bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);
break;
case "2": Rotate_Bitmap.RotateFlip(RotateFlipType.Rotate270FlipNone);
break;
case "3": Rotate_Bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);
break; }
picBox.Image = Rotate_Bitmap; }
}
catch
{
MessageBox.Show("There is no image on the viewer", "Empty Viewer",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
This method does the image rotation which is called from the menu buttons. If you look at it, it's very simple, even for a PictureBox
... but, everything is easy after we learn it. ;) 'RotateFlipType'
has other properties that you might want to try for your own codes.
private void TSFiles_SelectedIndexChanged(object sender, EventArgs e)
{
lstView.Items.Clear();
StreamReader OpenAfile = new StreamReader(@"data\\" + TSFiles.Text.Trim());
char Splitchr = (char)92;
string[] SplitText;
string LineData;
while (OpenAfile.EndOfStream != true)
{
LineData = OpenAfile.ReadLine();
ListViewItem s_Items;
s_Items = lstView.Items.Add(Convert.ToString(LineData));
SplitText = Convert.ToString(LineData).Split(Splitchr);
s_Items.SubItems.Add(Convert.ToString
(SplitText.GetValue(SplitText.GetUpperBound(0))));
}
picBox.ImageLocation = ""; SSLabel.Text = "Album Images : " + Convert.ToString(lstView.Items.Count);
}
Since I am repeating things in this article, this method has Split, once again, and how to enter data into ListView
columns (in detailed mode). If you read my other two articles, you'd know how much I love to work with ListView
control. I can keep many things in there that saves me tons of coding and probably memory too. Here I kept the full path of the image in the first column, with its width set to '0
' so you can't see it, and the file name for the second column... the only thing visible in the Album list.
private void TSSaveimage_Click(object sender, EventArgs e)
{
string[] SplitText;
SplitText = picBox.ImageLocation.Split('.');
switch (Convert.ToString(SplitText.GetValue(SplitText.GetUpperBound(0))).ToLower())
{
case "jpg":
picBox.Image.Save(picBox.ImageLocation,
System.Drawing.Imaging.ImageFormat.Jpeg);
break;
case "tif":
picBox.Image.Save(picBox.ImageLocation,
System.Drawing.Imaging.ImageFormat.Tiff);
break;
case "gif":
picBox.Image.Save(picBox.ImageLocation,
System.Drawing.Imaging.ImageFormat.Gif);
break;
case "png":
picBox.Image.Save(picBox.ImageLocation,
System.Drawing.Imaging.ImageFormat.Png);
break;
}
This is something new. If you do work or would like to work with PictureBoxes
, here is how you can save the files in the PictureBox
after some work done. In my case, rotation is the work. There is 'file size' problem though. It compresses the file when saved. I didn't want to spend much more time for this, I will let you find out the solution. :)
private void TSDeleteFile_Click(object sender, EventArgs e)
{
if (TSFiles.Text == "Select/Enter Album") {
MessageBox.Show("select a file first!", "Selection missing",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; }
if (MessageBox.Show("Are you sure?", "Delete File", MessageBoxButtons.YesNo,
MessageBoxIcon.Question) == DialogResult.No) { return; }
lstView.Items.Clear();
picBox.ImageLocation = "";
File.Delete(@"data\\" + TSFiles.Text);
FileListCheck(); TSFiles.Text = "Select/Enter Album";
SSLabel.Text = "Album Images : 0";
}
This is how to delete a file. Obviously very simple 'File.Delete(FilPath)'
but, I also wanted to show you my indentations, which is more compact if you see the entire code.
private void EnableDisableControls(bool StartStop)
{
TSNewFile.Enabled = StartStop;
TSDeleteFile.Enabled = StartStop;
TSPlay.Enabled = StartStop;
TSStop.Enabled = !StartStop;
TSRotLeft.Enabled = StartStop;
TSRotRight.Enabled = StartStop;
TSFlip.Enabled = StartStop;
TSReload.Enabled = StartStop;
TSFit.Enabled = StartStop;
TSSaveimage.Enabled = StartStop;
TSEnterImage.Enabled = StartStop;
TSRemoveImage.Enabled = StartStop;
TSFiles.Enabled = StartStop;
fleExp.Enabled = StartStop;
lstView.Enabled = StartStop;
}
When the slideshow starts, most of the controls need to be disabled and enabled back when stopped. Now, I wrote this method to save tons of lines, but check out the 'TSStop.Enabled = !StartStop'...
boolean switches from 'true
' to 'false
' or from 'false
' to 'true
' because I need that control disabled and enabled opposite from the other controls. :)
int icons = 0;
foreach (FileInfo file in rootDir.GetFiles())
{
TreeNode node = new TreeNode();
node.Text = file.Name;
switch (file.Extension.ToLower())
{
case ".jpg": case ".gif": case ".tif": case ".png": icons = 3;
break;
case ".txt": case ".rtf":
icons = 7;
break;
case ".pdf":
icons = 8;
break;
case ".doc": case ".docx":
icons = 4;
break;
case ".mdb": case ".accdb":
icons = 5;
break;
case ".exe": case ".dll":
icons = 9;
break;
case ".zip": case ".rar":
icons = 10;
break;
case ".bmp":
icons = 12;
break;
default:
icons = 11;
break;
}
node.ImageIndex = icons;
node.SelectedImageIndex = icons;
parentNode.Nodes.Add(node);
}
}
Please see the whole code for TreeView
creation. I only would like to show this portion which sets the icons of the items in the TreeView
. As I mentioned at the beginning of the article, I kind of cheated to find out which files are images so I can show them in PictureBox
... #3 icon for all the image files which can be loaded into the PictureBox
control. There might be other files too, but 4 format is enough for this program. 'node.SelectedImageIndex = icons
is the key here. If you don't put that line of code, you would end up having different icons showing on the clicked items of the TreeView
.
private void TSExit_Click(object sender, EventArgs e)
{
if (Application.MessageLoop)
{
Application.Exit();
}
else
{
Environment.Exit(1);
}
}
And this is my application exit routine. I saw it somewhere and made sense to me to use it all together like this.
Last Few Words
Try to close anything you open in your code. Try to use Exception catchers (Try
...catch
) to make your code stronger. Comment your code whenever you have time and organize your code when you think your brain is getting slower... Commenting and organizing your code while relaxing your brain helps you go through all the code once again and keeps you fresh with the whole code... and sometimes helps you to find bugs before you actually run the code.
Points of Interest
C# is one of the more fun languages (my second, so this is the best one after VB). I enjoy each moment of my programs when it actually works (well, hell yeah)... but I also enjoy trying to find the answers for my problems. These articles are so far only for beginners just like me. I will be starting a bit more better coding, some more difficult coding. I hope you follow me and take advantage of my code to enhance yours, like I did with this one... or, just let me know what else I can do to make my code better. ;)
Download the entire code and test it. If you like the idea, enhance it and make it your own. There are many other functions and controls that can be put into this application, or just have the idea and write your code from scratch.