Use a TextFieldParser to read fixed-width data in C#

[TextFieldParser]

This example uses a TextFieldParser object to load fixed-width data from a file that contains names and addresses. Each field has a fixed width. Some records also have ZIP+4 format ZIP codes (for example, 08109-2120) and the program should discard the +4 part of the data. Finally the data file contains some blank lines in the middle and at the end, and the program should ignore them.


The following text shows the file.

Barbara             Roberts             2044 22nd St                  San Pablo           CA24806
Ken                 Carson              565 Atlanta South Pkwy        Atlanta             GA10349
Horatio             Crunch              565 Atlanta South Pkwy        Atlanta             GA70349-5958
Patricia            Reichardt           3655 Millbranch Rd            Memphis             TN18116-4817

Aloysius            Snuffleupagus       9252 N 49th St                Pennsauken          NJ08109-2120
Edgar               Mallory             3655 Millbranch Rd            Memphis             TN38116
Jonas               Grumby              2832 Amerson Way              Ellenwood           GA30294
Roy                 Hinkley             29426 Christiana Way          Laguna Niguel       CA92677


The example program uses the following code to read and display the data.

// Load the data.
private void Form1_Load(object sender, EventArgs e)
{
    // Open a TextFieldParser using these delimiters.
    using (TextFieldParser parser =
        FileSystem.OpenTextFieldParser("Names.txt"))
    {
        // Set the field widths.
        parser.TextFieldType = FieldType.FixedWidth;
        parser.FieldWidths = new int[] { 20, 20, 30, 20, 2, 5 };

        // Process the file's lines.
        while (!parser.EndOfData)
        {
            try
            {
                string[] fields = parser.ReadFields();
                ListViewItem item = lvwPeople.Items.Add(fields[0]);
                for (int i = 1; i <= 5; i++)
                {
                    item.SubItems.Add(fields[i]);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }

    lvwPeople.AutoResizeColumns(
        ColumnHeaderAutoResizeStyle.HeaderSize);
}

The code starts by creating a TextFieldParser. It sets the parser’s TextFieldType property to FixedWidth and its FieldWidths property to an array holding the fields’ widths in characters.

Note that the TextFieldParser class and the FileSystem class used here are in the Microsoft.VisualBasic.FileIO namespace. The program includes the following using directive to make using the namespace easier. I also added a reference to the Microsoft.VisualBasic library at design time.

// Add a reference to Microsoft.VisualBasic.
using Microsoft.VisualBasic.FileIO;

After creating the parser, the program loops while the parser’s EndOfData property returns false. The EndOfData property automatically changes to true after the parser reads the last record in the data file even if the file ends with some blank lines, so the parser won’t get confused.

As long as EndOfData is false, the program calls the parser’s ReadFields method to read the next record’s fields into an array of strings. The program must then interpret the fields appropriately. In this example the program simply displays the first 6 fields in a ListView control, the first one as a ListView item and the others as sub-items.

See also Use a TextFieldParser to read delimited data in C#.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in classes, database, files, parsing | Tagged , , , , , , , , , , , , , , , | Leave a comment

Use a TextFieldParser to read delimited data in C#

[TextFieldParser]

This example uses a TextFieldParser object to parse a data file that contains name and address data. The data contains fields delimited by commas and semi-colons. Some records also have ZIP+4 format ZIP codes (for example, 08109-2120) and the program should discard the +4 part of the data. Finally the data file contains some blank lines in the middle and at the end. The program should ignore them.

The following text shows the test data file.

Barbara,Roberts;2044 22nd St;San Pablo;CA;24806
Ken,Carson;565 Atlanta South Pkwy;Atlanta;GA;10349
Horatio,Crunch;565 Atlanta South Pkwy;Atlanta;GA;70349-5958
Patricia,Reichardt;3655 Millbranch Rd;Memphis;TN;18116-4817

Aloysius,Snuffleupagus;9252 N 49th St;Pennsauken;NJ;08109-2120
Edgar,Mallory;3655 Millbranch Rd;Memphis;TN;38116
Jonas,Grumby;2832 Amerson Way;Ellenwood;GA;30294
Roy,Hinkley;29426 Christiana Way;Laguna Niguel;CA;92677

The example program uses the following code to read and display the data.

// Open a TextFieldParser using these delimiters.
string[] delimiters = { ";", ",", "-" };
using (TextFieldParser parser =
    FileSystem.OpenTextFieldParser("Names.txt", delimiters))
{
    // Process the file's lines.
    while (!parser.EndOfData)
    {
        try
        {
            string[] fields = parser.ReadFields();
            ListViewItem item = lvwPeople.Items.Add(fields[0]);
            for (int i = 1; i <= 5; i++)
            {
                item.SubItems.Add(fields[i]);
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
}

The code starts by creating an array holding the delimiters that the file uses. Including – in the list allows the program to treat the +4 part of the ZIP code (if it is present) as a separate field.

The program then creates a TextFieldParser object. It uses the FileSystem.OpenTextFieldParser factory method to create a new instance of the class. It passes that method the array of delimiters so the parser knows what characters to use as delimiters. Notice that the code uses a using statement so the parser’s Dispose method is automatically called when the object is no longer needed.

Note also that the TextFieldParser class and the FileSystem class are contained in the Microsoft.VisualBasic.FileIO namespace. The program includes the following using directive to make using the namespace easier. I also had to add a reference to the Microsoft.VisualBasic library at design time.

// Add a reference to Microsoft.VisualBasic.
using Microsoft.VisualBasic.FileIO;

After creating the parser, the program loops while the parser’s EndOfData property returns false. The EndOfData property automatically changes to true after the parser reads the last record in the data file even if the file ends with some blank lines so the parser won’t get confused.

As long as EndOfData is false, the program calls the parser’s ReadFields method to read the next record’s fields into an array of strings. The program must then interpret the fields appropriately. In this example the program simply displays the first 6 fields in a ListView control, one as a ListView item and the others as sub-items.

This is nothing that you couldn’t do yourself by using File.ReadAllLines and String.Split, but the TextFieldParser is somewhat simpler.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in classes, database, files, parsing | Tagged , , , , , , , , , , , , , | 2 Comments

Suspend or hibernate the system in C#

[hibernate]

The Application.SetSuspendState method lets an application make the system suspend or hibernate. A suspended system enters a low power mode. A hibernating system saves its memory contents to disk and then enters low power mode.

Because it doesn’t need to restore the saved memory, a suspended system can resume more quickly than a hibernating system. However, if the computer loses power while suspended, running programs are not properly restored.

The following code lets the program suspend or hibernate the system.

// Suspend.
private void btnSuspend_Click(object sender, EventArgs e)
{
    Application.SetSuspendState(PowerState.Suspend, false, false);
}

// Hibernate.
private void btnHibernate_Click(object sender, EventArgs e)
{
    Application.SetSuspendState(PowerState.Hibernate, false, false);
}

For more information about the SetSuspendState method, see Application.SetSuspendState Method.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in system | Tagged , , , , , , , , , , , , | Leave a comment

Make light pixels transparent in an image in C#

[example]

Recently I had an image and I wanted to make all of the light pixels transparent. Ideally I could simply make the white pixels transparent, but the image was scanned so few of the pixels were pure white. What I really needed to do was make pixels that were mostly white transparent.

This example lets you load an image. When you adjust the scroll bar, it finds the pixels with red, green, and blue color components that are all greater than the cutoff value and it makes them transparent.

The following ShowImage method creates and displays the adjusted image.

// Make an image setting pixels brighter
// than the cutoff value to magenta.
private void ShowImage()
{
    if (OriginalImage == null) return;

    // Get the cutoff.
    int cutoff = scrBrightness.Value;

    // Prepare the ImageAttributes.
    Color low_color = Color.FromArgb(cutoff, cutoff, cutoff);
    Color high_color = Color.FromArgb(255, 255, 255);
    ImageAttributes image_attr = new ImageAttributes();
    image_attr.SetColorKey(low_color, high_color);

    // Make the result image.
    int wid = OriginalImage.Width;
    int hgt  = OriginalImage.Height;
    Bitmap bm = new Bitmap(wid, hgt);

    // Process the image.
    using (Graphics gr = Graphics.FromImage(bm))
    {
        // Fill with magenta.
        gr.Clear(Color.Magenta);

        // Copy the original image onto the result
        // image while using the ImageAttributes.
        Rectangle dest_rect = new Rectangle(0, 0, wid, hgt);
        gr.DrawImage(OriginalImage, dest_rect,
            0, 0, wid, hgt, GraphicsUnit.Pixel, image_attr);
    }

    // Display the image.
    picResult.Image = bm;
}

If no image has yet been loaded, the method simply returns. If it continues, the gets the cutoff value from the scroll bar scrBrightness.

Next the method creates two colors low_color and high_color to represent the lowest and highest color values that it will convert to transparent. It creates a new ImageAttributes object and calls its SetColorKey method to give it the low and high color values.

Nxet the program creates a Bitmap with the same size as the original image. It creates an associated Graphics object and clears it with the color magenta. At this point the new image is completely magenta.

Next the code uses the Graphics object’s DrawImage method to draw the original image on top of the magenta background. The final parameter to DrawImage is the ImageAttributes object.

If a pixel’s red, green, and blue color components are all between the corresponding values of the low and high colors saved in the ImageAttributes object’s color key, the result pixel is transparent. Because the bitmap’s background is magenta, the magenta shows through at these pixels. (I use magenta instead of allowing those pixels to be transparent so you can see them easily.)

The method finishes by displaying the resulting bitmap.

When you use the File menu’s Save command, the program copies the result bitmap, converts the magenta pixels to transparent, and saves the result.

Note that the PNG file format supports transparency but most other formats such as BMP and JPG do not. For that reason, be sure to save the file in PNG format.

Note also that there are other ways you can set the pixel transparency. For example, you can use the Bitmap object’s GetPixel and SetPixel methods or you can use the Bitmap32 class that I’ve used in other posts. The ImageAttributes object is much faster.

For the best results if you will later display the image on a light-colored background, adjust the cutoff value so a few of the pixels near the dark shapes are not transparent. You can see them in the picture above as the light-colored pixels between the dark shapes and the magenta background. Those pixels will provide a smooth edge between the shapes and the background.

Download the example to see additional details such as how the program loads and saves files.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in graphics, image processing | Tagged , , , , , , , , , , , | Leave a comment

Draw a smiley face with WPF in C#

[example]

Often I need to use images for demonstration purposes or for a book, and a smiley face makes a neutral, pleasant image. This example shows how to draw a smiley face with XAML and WPF, and then save an image of the face into a PNG file.

The following code shows how the program draws the smiley face on the left.

<Grid Margin="10">
    <Grid.RowDefinitions>
        <RowDefinition Height="100"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="100"/>
        <ColumnDefinition Width="10"/>
        <ColumnDefinition Width="100"/>
    </Grid.ColumnDefinitions>
    <Grid Grid.Row="0" Grid.Column="0">
        <Canvas Name="canvas1" Background="Transparent">
            <Ellipse Width="100" Height="100"
                Fill="Yellow" Stroke="Red" StrokeThickness="3"/>

            <Ellipse Width="20" Height="30"
                Canvas.Left="20" Canvas.Top="20"
                Fill="White" Stroke="Black" StrokeThickness="1"/>
            <Ellipse Width="10" Height="20"
                Canvas.Left="30" Canvas.Top="25"
                Fill="Black" Stroke="Black" StrokeThickness="1"/>

            <Ellipse Width="20" Height="30"
                Canvas.Left="60" Canvas.Top="20"
                Fill="White" Stroke="Black" StrokeThickness="1"/>
            <Ellipse Width="10" Height="20"
                Canvas.Left="70" Canvas.Top="25"
                Fill="Black" Stroke="Black" StrokeThickness="1"/>

            <Ellipse Width="15" Height="25"
                Canvas.Left="42.5" Canvas.Top="45"
                Fill="LightBlue" Stroke="Blue" StrokeThickness="1"/>

            <Path Stroke="Black" StrokeThickness="2"  
                Data="M 15,50 A 35,35 0 1 0 85,50" />
        </Canvas>
    </Grid>

    ...
</Grid>

The code first creates a Grid control that defines three columns: two for smiley face drawings and one to form a margin between them.

Inside that Grid control’s first cell is another Grid that contains a Canvas control named canvas1.

The Canvas holds ellipses of various colors to make up most of the smiley face. The final control inside the Canvas is a Path object. Its Data property uses the path minilanguage to create an arc to represent the smiley face’s smile.

After this inner Grid is another Grid that contains controls to draw the smiley face on the right. Its Canvas control is named canvas2. The only difference is that the second Canvas control has its Background property set to a LinearGradientBrush instead of the color Transparent.

When the program starts, it executes the following code.

// Save the canvas images.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    SaveControlImage(canvas1, "Smiley no bg.png");
    SaveControlImage(canvas2, "Smiley with bg.png");
}

// Save a control's image.
private void SaveControlImage(FrameworkElement control,
    string filename)
{
    // Get the size of the Visual and its descendants.
    Rect rect = VisualTreeHelper.GetDescendantBounds(control);

    // Make a DrawingVisual to make a screen
    // representation of the control.
    DrawingVisual dv = new DrawingVisual();

    // Fill a rectangle the same size as the control
    // with a brush containing images of the control.
    using (DrawingContext ctx = dv.RenderOpen())
    {
        VisualBrush brush = new VisualBrush(control);
        ctx.DrawRectangle(brush, null, new Rect(rect.Size));
    }

    // Make a bitmap and draw on it.
    int width = (int)control.ActualWidth;
    int height = (int)control.ActualHeight;
    RenderTargetBitmap rtb = new RenderTargetBitmap(
        width, height, 96, 96, PixelFormats.Pbgra32);
    rtb.Render(dv);

    // Make a PNG encoder.
    PngBitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(rtb));

    // Save the file.
    using (FileStream fs = new FileStream(filename,
        FileMode.Create, FileAccess.Write, FileShare.None))
    {
        encoder.Save(fs);
    }
}

The Window_Loaded event handler simply calls the SaveControlImage method, passing it the canvas controls and the file names where their images should be saved.

The SaveControlImage method first gets the bounds of the Canvas control’s child hierarchy.

Next the method creates a DrawingVisual on which to draw. It then opens the DrawingVisual and creates a VisualBrush that can fill areas with images of the Canvas control. It uses the DrawRectangle method to fill the control’s child hierarchy bounds with the brush. The result of this is to create a rectangle filled with an image of the Canvas control containing the smiley face image.

Next the method gets the size of the Canvas control and creates a RenderTargetBitmap big enough to hold it. It then renders the DrawingVisual on the RenderTargetBitmap. The result of this is that the RenderTargetBitmap now holds the image of the Canvas control.

The method then creates a PngBitmapEncoder and adds the RenderTargetBitmap to it. It finishes by opening a FileStream to the file where we want to save the image and then calling the encoder’s Save method to save the image into the file.

If you run the program and then look in its executable directory, you will find the two smiley face image files.

If this all seems very roundabout and confusing, you’re right. This is in keeping with WPF’s unofficial slogan, “Twice as flexible and only five times as hard.”

Despite WPF’s non-intuitive nature, the program lets you easily create pictures in WPF and save them into PNG files. You can modify the XAML code to generate other images if you like, and the code behind will save the result into a file.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in drawing, graphics, image processing, wpf, XAML | Tagged , , , , , , , , , , , , , , | Leave a comment

Rotate images that are scaled in C#

[rotate images]

The example Interactively rotate images in C# lets you click and drag to rotate images but it doesn’t always work well if the image you are rotating is too big to fit on the screen. The example Rotate images inside a scrolled panel in C# lets you scroll to part of a large image so you can use that part to align the image.

Sometimes, however, it might be better to see a small version of the entire image instead of a small piece of the image. This example displays a scaled version of the image and lets you rotate it.

To do that, the program displays the image in a PictureBox. In the original version of the program the PictureBox control’s ScaleMode property was set to AutoSize so the PictureBox sized itself to fit the image. If the image was too big, the PictureBox was too large to manage effectively.

In this example the PictureBox control’s SizeMode property is set to Zoom. That makes the control retain its original size and scale its image so it is as large as possible while still fitting completely inside the PictureBox.

Note that this means the image will be enlarged if it is smaller than the PictureBox. That may not be necessary but probably won’t hurt either.

The program uses mouse events to let you click and drag to rotate the image. To do that, it needs to calculate the mouse’s position relative to the center of the image. In the previous example, the program used the following code to calculate the offset from the center of the image.

float dx = e.X - ImageCenter.X;
float dy = e.Y - ImageCenter.Y;

Here ImageCenter was a point representing the center of the image. It was calculated when the result image was created.

In the new program the image has been scaled but the mouse coordinates are not scaled. That means the effective center of the image has been moved.

The new program uses the following code to calculate the offset from the mouse to the center of the image.

float dx = e.X - (picRotated.ClientSize.Width / 2f);
float dy = e.Y - (picRotated.ClientSize.Height / 2f);

Instead of using the center of the image in pixels, it uses the center of the PictureBox. The PictureBox scales and centers the image, so this is the position of the scaled image’s center.

The rest of the code is exactly the same as before. Download the example and see the previous examples for more details.


Download Example   Follow me on Twitter   RSS feed   Donate


Posted in algorithms, graphics, image processing, transformations | Tagged , , , , , , , , , , , , , , | 1 Comment

Rotate images inside a scrolled panel in C#

[rotate images]

The example Interactively rotate images in C# lets you click and drag to rotate images. Unfortunately it doesn’t work well with images that are too big to fit on the screen. If an image is too big, the program lets you rotate it but you may be unable to see enough of the image to rotate it effectively.

This example displays the image inside a Panel that provides scroll bars if the image is big. You can then scroll to the part of the image that you want to see while you are rotating it.

Fortunately the program’s code doesn’t require any changes. The only changes are the new Panel and moving the PictureBox that displays the image into the Panel.

Download the example and see the previous post for more details.


Download Example   Follow me on Twitter   RSS feed   Donate


Posted in algorithms, graphics, image processing, transformations | Tagged , , , , , , , , , , , , | Leave a comment

Explore the Visual Studio Image Library in C#

[image library]

This example explains where you can find standard images in the Visual Studio Image Library that you can use in your applications.

The example Give transparent backgrounds to images displayed on buttons in C# explains how to make some pixels in a bitmap transparent so an image looks nice on a button. Bitmap, jpg, and many other graphic files cannot store transparent pixels but PNG images can. That means you can create an image with transparent pixels, save it in a PNG file, and then load the PNG file into a button to get a nice result.

Sometimes you may want standard images for common commands such as next, previous, undo, filter, magnify, and so forth. The Visual Studio Image Library contains more than 1,000 images including hundreds of button images in PNG format. This example shows samples of buttons using those PNG images.

The library used to be installed when you installed Visual Studio, but I don’t think it is any more. (I’m not completely sure because I have so many versions of Visual Studio installed.) If the image library is installed, it will probably be in a zip file with a name similar to VS2010ImageLibrary.zip. This file is typically installed in a folder such as ..\Program Files\Microsoft Visual Studio 10.0\Common7\VS2010ImageLibrary\1033\.

If the library isn’t installed, you can download it here. That page lets you select different versions of the library. Currently you can select the VS 2012 version (19.4MB), the VS 2013 version (285.6 MB), or the VS 2015 version (2.9 GB!).

The image library’s current description on the download page says:

The Visual Studio Image Library contains application images that appear in Microsoft Visual Studio, Microsoft Windows, the Office system and other Microsoft software.

This example uses the Visual Studio 2012 library because I didn’t want to wait 2 hours to download the VS 2015 version. The program displays PNG files in the \VS2012 Modern Image Library\Objects\png subdirectory.

To make managing the PNG files easier within the project, I right-clicked the project in Solution Explorer, opened the Add menu, and selected New Folder. I named the folder Buttons and then used Windows Explorer to copy the 32×32 pixel PNG files into the new directory.

Tip: That directory contains 752 PNG files, only 64 of which are 32×32 pixels. To find the images with a certain size, open Windows Explorer in Details view, right-click on the column headings and check Dimensions. Then click on the Dimensions column to order the images by their dimensions.

Next I right-clicked the Buttons folder in Solution Explorer, opened the Add command, and selected Existing Item. I selected all of the files (changed the dialog’s filter to All Files, because it initially only lists C# code files) and clicked Add.

Finally I selected all of the PNG files in Solution Explorer and set their “Copy to Output Directory” properties to “Copy if newer.” This may all seem like a hassle but it lets the program assume that the files will be in the startup directory’s Buttons subdirectory.

When it starts, the program uses the following code to display the images in the Buttons folder.

// Display all of the images in the Buttons folder.
private void Form1_Load(object sender, EventArgs e)
{
    const int wid = 32;
    const int hgt = 32;
    const int margin = 3;
    int x = margin;
    int y = margin;
    const int num_columns = 10;
    const int xmax = num_columns * (wid + margin);

    // Find the images.
    foreach (string filename in
        Directory.GetFiles("Buttons", "*.png"))
    {
        // Make a new Button.
        Button btn = new Button();
        btn.Parent = this;
        btn.Image = new Bitmap(filename);
        btn.Size = new Size(32, 32);
        btn.Location = new Point(x, y);
        x += wid + margin;
        if (x > xmax)
        {
            x = margin;
            y += hgt + margin;
        }

        FileInfo file_info = new FileInfo(filename);
        tipButton.SetToolTip(btn, file_info.Name);
    }

    // Size the form to fit.
    this.ClientSize = new Size(
        xmax + margin,
        y + hgt + margin);
}

The code uses the Directory.GetFiles method to find PNG files in the Buttons directory. It loops over the files and creates a Button control for each.

For each file, the program adds the Button to the form, positions it, and sets its Image to display its PNG file. It then sets the Button control’s tooltip to display the file’s name. It uses a FileInfo object to display only the file’s name without the path.

Now download one of the image libraries and explore. You’ll find thousands of PNG, BMP, and ICO files taht you can include in your applications. That is if you can find the images that you want.

You may also want to search the internet for images. Often you can find more colorful and engaging images that you can use.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, graphics | Tagged , , , , , , , , , , , , | Leave a comment

List controls on a form in C#

[list controls]

There are several ways you can list controls on a form. At design time, you can open the form and then use the dropdown at the top of the Properties window. You can also look inside the file Form1.Designer.cs.

At run time it’s harder to list controls on a form than you might think. The Control class has a Controls property that contains references to the controls inside a particular control. For example, a form’s Controls collection lists all of the controls contained directly on the form.

Unfortunately the Controls collection doesn’t include controls contained in other controls. For example, if a form contains a TabControl that contains a PictureBox, then the PictureBox is not listed in the form’s Controls collection. To find the PictureBox you need to recursively descend through the control tree.

That’s the basic approach. Start at the form and recursively descend into the control tree.

Unfortunately it’s not quite that simple. Some controls don’t use their Controls collection to hold references to the items they contain. For example, a MenuStrip control holds its menu items in its Items property.

To make matters even worse, some objects that you might think are controls are actually components so they don’t even have a Controls property. For example, a ToolStripMenuItem is a component but not a control, and it stores its sub-items in its DropDown property’s Items property.

So to list the form’s controls and control-like components, you need to recursively descend into the user interface hierarchy, following the appropriate properties to find sub-items.

This example uses the following code to add items representing user interface components to a ListBox control.

// List the controls in a ListBox.
private void ListControls(ListBox lst, Object parent, int indent)
{
    string spaces = new string(' ', indent);
    if (parent is ToolStrip)
    {
        // Note that a StatusStrip is also a ToolStrip.
        ToolStrip tool_strip = parent as ToolStrip;
        lst.Items.Add(spaces +
            tool_strip.Name + " (" +
            tool_strip.GetType().Name + ")");
        foreach (ToolStripItem item in tool_strip.Items)
        {
            ListControls(lst, item, indent + 4);
        }
    }
    else if (parent is ToolStripDropDownButton)
    {
        // ToolStripDropDownButton inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripDropDownButton dropdown_button =
            parent as ToolStripDropDownButton;
        lst.Items.Add(spaces +
            dropdown_button.Name + " (" +
            dropdown_button.GetType().Name + ")");
        ListControls(lst, dropdown_button.DropDown, indent + 4);
    }
    else if (parent is ToolStripSplitButton)
    {
        // ToolStripSplitButton inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripSplitButton split_button =
            parent as ToolStripSplitButton;
        lst.Items.Add(spaces +
            split_button.Name + " (" +
            split_button.GetType().Name + ")");
        ListControls(lst, split_button.DropDown, indent + 4);
    }
    else if (parent is ToolStripMenuItem)
    {
        // ToolStripMenuItem inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripMenuItem item = parent as ToolStripMenuItem;
        lst.Items.Add(spaces +
            item.Name + " (" +
            item.GetType().Name + ")");
        ListControls(lst, item.DropDown, indent + 4);
    }
    else if (parent is ToolStripItem)
    {
        ToolStripItem item = parent as ToolStripItem;
        lst.Items.Add(spaces +
            item.Name + " (" +
            item.GetType().Name + ")");
    }
    else if (parent is Control)
    {
        Control control = parent as Control;
        lst.Items.Add(spaces +
            control.Name + " (" +
            control.GetType().Name + ")");
        foreach (Control child in control.Controls)
        {
            ListControls(lst, child, indent + 4);
        }
    }
}

The method takes as parameters the ListBox that should hold the components’ names, a component that should be added to the list, and a number of spaces to indent the component’s entry.

The code uses a series of if-else-if statements to see what kind of object the component is. Each if section follows the same pattern. It converts the component into an object of the appropriate type and adds its name to the ListBox. It then loops through the component’s list of items that it contains and recursively calls the ListControls method for those items. The main difference is in the collection that the component uses to hold its items.

Tool strip menu items are a special case. They have a DropDown property that refers to a ToolStripDropDownMenu. That control inherits from ToolStrip so it holds its sub-items in its Items property.

The following table lists the component types and the properties they use to hold their sub-items.

Object Type Sub-items Property
ToolStrip Items
ToolStripDropDownButton DropDown
ToolStripSplitButton DropDown
ToolStripMenuItem DropDown
ToolStripItem ---
Control Controls

The example program also lists the items in a TreeView control. The following overloaded version of the ListControls method works much as the previous version does except it adds items to a TreeNodeCollection to place them in a TreeView.

// List the controls in a TreeView.
private void ListControls(TreeNodeCollection nodes, Object parent)
{
    if (parent is ToolStrip)
    {
        // Note that a StatusStrip is also a ToolStrip.
        ToolStrip tool_strip = parent as ToolStrip;
        TreeNode new_node = nodes.Add(
            tool_strip.Name + " (" +
            tool_strip.GetType().Name + ")");
        foreach (ToolStripItem item in tool_strip.Items)
        {
            ListControls(new_node.Nodes, item);
        }
    }
    else if (parent is ToolStripDropDownButton)
    {
        // ToolStripDropDownButton inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripDropDownButton dropdown_button =
            parent as ToolStripDropDownButton;
        TreeNode new_node = nodes.Add(
            dropdown_button.Name + " (" +
            dropdown_button.GetType().Name + ")");
        ListControls(new_node.Nodes, dropdown_button.DropDown);
    }
    else if (parent is ToolStripSplitButton)
    {
        // ToolStripSplitButton inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripSplitButton split_button =
            parent as ToolStripSplitButton;
        TreeNode new_node = nodes.Add(
            split_button.Name + " (" +
            split_button.GetType().Name + ")");
        ListControls(new_node.Nodes, split_button.DropDown);
    }
    else if (parent is ToolStripMenuItem)
    {
        // ToolStripMenuItem inherits from ToolStripItem
        // so it must come first in this if-else-if sequence.
        ToolStripMenuItem item = parent as ToolStripMenuItem;
        TreeNode new_node = nodes.Add(
            item.Name + " (" +
            item.GetType().Name + ")");
        ListControls(new_node.Nodes, item.DropDown);
    }
    else if (parent is ToolStripItem)
    {
        ToolStripItem item = parent as ToolStripItem;
        TreeNode new_node = nodes.Add(
            item.Name + " (" +
            item.GetType().Name + ")");
    }
    else if (parent is Control)
    {
        Control control = parent as Control;
        TreeNode new_node = nodes.Add(
            control.Name + " (" +
            control.GetType().Name + ")");
        foreach (Control child in control.Controls)
        {
            ListControls(new_node.Nodes, child);
        }
    }
}

The following code shows how the main program uses the two versions of ListControls to list the form’s interface elements.

// List all of the controls on the form.
private void Form1_Load(object sender, EventArgs e)
{
    // List the controls in a ListBox.
    ListControls(lstControls, this, 0);

    // List the controls in a TreeView.
    ListControls(trvControls.Nodes, this);
    trvControls.ExpandAll();
}

Note that this code still doesn’t list every component on the form. For example, it won’t list a Timer control. The form’s components.Components property seems to hold timers at least.

If you find other controls that this example doesn’t search properly, for example if a control uses some other property to hold its sub-items, please post a note in the comments below.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, forms, system | Tagged , , , , , , , , , | Leave a comment

Give transparent backgrounds to images displayed on buttons in C#

[transparent backgrounds]

This example shows how to give transparent backgrounds to the images displayed on a button.

If you give buttons images that have transparent backgrounds, then the button’s background can show through. If the images don’t have transparent backgrounds, the result are rectangular blocks sitting on top of the buttons. There are a couple of ways you can work around this.

First, you can give the images transparent backgrounds as described in the post Make a tool that creates PNG files with transparent backgrounds in C#.

[transparent backgrounds]Second, you can color the images’ backgrounds so they match the button’s backgrounds. Note that the appearance of buttons may differ in different versions of Windows so this may not work very well. For example, in the picture on the right the buttons don’t have solid colored backgrounds.

This example uses the following MakeButtonTransparent method to give a buttons’ images a transparent background at run time.

// Give the button a transparent background.
private void MakeButtonTransparent(Button btn)
{
    Bitmap bm = (Bitmap)btn.Image;
    bm.MakeTransparent(bm.GetPixel(0, 0));
}

This method gets the button’s current image as a Bitmap. It calls the Bitmap object’s MakeTransparent method to convert all of the pixels of a particular color into a transparent color. The color that the code converts is whatever color is in the image’s upper left corner. The image is already displayed in the button so the change appears automatically.

So the procedure is to make the button’s image so all of the background pixels have the same color as the pixel in the upper left corner. Then when the form loads, call MakeButtonTransparent for the button.

Note that some controls such as ToolStripButton, ToolStripSplitButton, and ToolStripMenuItem have an ImageTransoarentColor property that does this for you. Simply set this property to the color of the background pixels in the image and you’re all set.


Download Example   Follow me on Twitter   RSS feed   Donate




Posted in controls, graphics, image processing | Tagged , , , , , , , , , , , | Leave a comment