Separate glyphs in an image in C#, Part 2

[separate glyphs]

This is the second post describing the program that I wrote to separate glyphs in a combined image. The first post explained the program’s menus. This post explains how the program manages its red glyph selection rectangle.

This post describes three pieces of the program: mouse events, keyboard events, and drawing the selection rectangle.

Mouse Events

When you press the mouse down over the glyph PictureBox, the following code begins dragging the selection rectangle.

// Mouse events.
private bool Dragging = false;
private Point DragOffset;
private void picGlyphs_MouseDown(object sender, MouseEventArgs e)
{
    // See if the mouse is inside the current GlyphRect.
    if (!GlyphRect.Contains(e.Location)) return;

    Dragging = true;
    DragOffset = new Point(
        GlyphRect.X - e.Location.X,
        GlyphRect.Y - e.Location.Y);
}

This code first defines the variables Dragging and DragOffset. They are defined at the form level, so all of the form’s code can see them.

The MouseDown event handler uses GlyphRect.Contains to see if the mouse is over the selection rectangle. If the mouse is not over the rectangle, the event handler just exits.

If the mouse is over the rectangle, the code sets Dragging to true to indicate that the user is dragging the rectangle. It saves the offset between the mouse position and the selection rectangle’s upper left corner in variable DragOffset so the program can later position the rectangle with respect to the mouse when it moves.

Speaking of which, when you move the mouse, the following event handler executes.

private void picGlyphs_MouseMove(object sender, MouseEventArgs e)
{
    if (!Dragging) return;
    int x = e.Location.X + DragOffset.X;
    int y = e.Location.Y + DragOffset.Y;
    GlyphRect = new Rectangle(x, y, GlyphRect.Width, GlyphRect.Height);
    picGlyphs.Refresh();
}

If Dragging is false, then no drag is in progress so the event handler simply exits.

If a drag is in progress, the code calculates the new location for the selection rectangle, keeping it the same distance from the mouse’s position. It updates GlyphRect and then refreshes the glyph PictureBox to draw the repositioned rectangle.

When you release the mouse over the PictureBox, the following event handler ends the drag.

private void picGlyphs_MouseUp(object sender, MouseEventArgs e)
{
    Dragging = false;
}

This code simply sets Dragging to false to indicate that a drag is no longer in progress.

Note that the MouseUp event may fire when no drag is already in progress. For example, if you press the mouse down over part of the form not over the PictureBox, drag the mouse over the PictureBox, and then release the mouse, the event is raised. You could modify the event handler’s code to check whether Dragging is true before setting it to false, but it doesn’t hurt to set it to false in either case so the test isn’t necessary.

Also note that the MouseUp event handler does not refresh the PictureBox. Usually in programs that allow the user to drag something, the MouseMove event handler has already updated the display just before the MouseUp event occurs, so that event handler doesn’t need also update the display.

Keyboard Events>

At design time, I set the form’s KeyPreview property to true to make the form receive keyboard events. When you press a key, the following event handler executes.

// Handle arrow keys.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    int distance = 1;
    if (e.Shift) distance = 5;

    switch (e.KeyCode)
    {
        case Keys.Left:
            GlyphRect.X -= distance;
            break;
        case Keys.Right:
            GlyphRect.X += distance;
            break;
        case Keys.Up:
            GlyphRect.Y -= distance;
            break;
        case Keys.Down:
            GlyphRect.Y += distance;
            break;
    }
    picGlyphs.Refresh();
}

The code first sets distance to 1. This is the number of pixels that the program will move the glyph selection rectangle if you pressed an arrow key. If the Shift key is pressed, the code updates distance to 5 so the program moves the rectangle farther.

Next, the code uses a switch statement to see what key you pressed. If you pressed an arrow key, the code adds distance to the appropriate rectangle coordinate.

When the switch block ends, the program refreshes its PictureBox to show the rectangle in its new position.

Note that if you press some key other than an arrow key, the program still refreshes the PictureBox. In my tests, you can’t tell. If there is a flicker, you could modify the code to only refresh if the rectangle has moved.

Drawing the Selection Rectangle

When the program’s glyph PictureBox refreshes, the following Paint event handler executes.

// Draw the glyphs and glyph rectangle.
private void picGlyphs_Paint(object sender, PaintEventArgs e)
{
    if (GlyphsBm == null) return;

    e.Graphics.DrawImage(GlyphsBm, 0, 0);
    using (Pen pen = new Pen(Color.Red, 3))
    {
        e.Graphics.DrawRectangle(pen, GlyphRect);
    }
}

If the GlyphBm bitmap is null, then the user has not loaded a bitmap yet so the method simply exits.

If a bitmap is loaded, the code uses the Graphics object’s DrawImage method to draw the loaded glyph image onto the PictureBox. It then creates a thick pen and uses it to draw the glyph selection rectangle.

Summary

That’s the end of this example. Now that we can separate glyphs that are included in a single image, we can use the glyphs to make the alienese encoder/decoder. I’ll describe that program in my next post.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in graphics, image processing and tagged , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.