Please note: The large size of the downloads is caused by the images included with the demo project. The compiled DLL library is only 44 KB.
Introduction
As a minor part of the image processing sub-system of my project, I needed a way to allow users to select an identifying region on the set of images they are working with. This region for each individual image is then to be shown at magnification (as compared to the full/cropped images shown as thumbnails).
While my need was very specific -- I wanted to know the co-ordinates of a rectangle selected on the surface of a PictureBox
control -- I decided to write a more versatile class which should be able to draw a rectangle on any object which inherits from System.Windows.Forms.Control
and return the rectangle co-ordinates to the invoking program.
The class I wrote to accomplish this goal is: TdhMarchingAnts_NativeWindow
. This class may be used by instantiating it directly via code.
I also wrote a component class, TdhMarchingAnts
, to act as a development-environment "wrapper" for TdhMarchingAnts_NativeWindow
.
The demo program uses/tests both classes.
Using the Classes -- The Code
To use the TdhMarchingAnts
classes as I've written them, add a reference in your project to the class library 'TDHMarchingAnts.dll'. The namespace used in this library is:
using TDHControls.TDHMarchingAnts;
An example of the 'Windows Form Designer generated code' for the TdhMarchingAnts
component is:
private void InitializeComponent()
{
this.tdhAnts
= new TDHControls.TDHMarchingAnts.TdhMarchingAnts(this.components);
this.tdhAnts.AntAttachedControl = this.pnlDemo;
this.tdhAnts.AntBackColor = System.Drawing.Color.Black; this.tdhAnts.AntForeColor = System.Drawing.Color.White; this.tdhAnts.AntsActive = true; this.tdhAnts.RegionDeselectEvent += new
TDHControls.TDHMarchingAnts.RegionDeselectEventHandler(
this.tdhAnts_RegionDeselectEvent);
this.tdhAnts.RegionSelectEvent += new
TDHControls.TDHMarchingAnts.RegionSelectEventHandler(
this.tdhAnts_RegionSelectEvent);
}
Example code for instantiating the TdhMarchingAnts_NativeWindow
class independently of the TdhMarchingAnts
component is:
private TDHControls.TDHMarchingAnts.TdhMarchingAnts_NativeWindow native_PicBox;
private TDHControls.TDHMarchingAnts.TdhMarchingAnts_NativeWindow native_Panel;
{
this.native_PicBox
= new TDHControls.TDHMarchingAnts.TdhMarchingAnts_NativeWindow(this.pbxImage);
this.native_PicBox.AntsActive = true; this.native_PicBox.RegionSelectEvent += new
TDHControls.TDHMarchingAnts.RegionSelectEventHandler(
this._PicBox_RegionSelectEvent);
this.native_PicBox.RegionDeselectEvent += new
TDHControls.TDHMarchingAnts.RegionDeselectEventHandler(
this._PicBox_RegionDeselectEvent);
this.native_Panel
= new TDHControls.TDHMarchingAnts.TdhMarchingAnts_NativeWindow
(this.pnlForSomething, Color.Blue, Color.Yellow);
}
Using the Classes -- The Code (The EventHandlers)
The TdhMarchingAnts_NativeWindow
class and the TdhMarchingAnts
component raise potentially six events (that is, three each for either mouse button).
Assuming the appropriate boolean properties are true
, the event _RegionSelectEvent()
(and the corresponding event _RightRegionSelectEvent()
) is raised when the left (or right) mouse button is released following a "click-and-drag."
Assuming the appropriate boolean properties are true
, the events _ClickEvent()
and _RegionDeselectEvent()
(and the corresponding events _RightClickEvent()
and _RightRegionDeselectEvent()
) are raised when the left (or right) mouse button is clicked. Thus, _ClickEvent()
(or _RightClickEvent()
) may be raised either alone or in conjunction with _RegionDeselectEvent()
(or _RightRegionDeselectEvent()
).
The signatures of the event handler methods are as follows:
private void _ClickEvent(object sender, System.Drawing.Point ClickedPoint)
{
}
private void _RegionDeselectEvent(object sender, System.Drawing.Point ClickedPoint)
{
}
private void _RegionSelectEvent(object sender, System.Drawing.Rectangle SelectedRect)
{
}
private void _RightClickEvent(object sender, System.Drawing.Point ClickedPoint)
{
}
private void _RightRegionDeselectEvent(object sender,
System.Drawing.Point ClickedPoint)
{
}
private void _RightRegionSelectEvent(object sender,
System.Drawing.Rectangle SelectedRect)
{
}
Please note: With version 1.0.004, the signatures of all the event handler methods have been changed (I apologize if this causes an inconvenience). The event handler parameter-lists should have included "object sender
" originally.
Using the Classes -- The Interface
Beginning with version 1.0.002, the TdhMarchingAnts
classes may be used with either the left mouse button or the right (or both). The "default" button is the left: that is, the previously named properties, methods, and events are also defined for mouse left-button activity; the corresponding properties, methods, and events defined for mouse right-button activity are preceded with the word "Right_" (for properties and methods) or "Right" (for events).
Both the TdhMarchingAnts
component and the TdhMarchingAnts_NativeWindow
class have essentially the same public interface.
The public (static) methods limited to the TdhMarchingAnts
component class are:
public static System.Drawing.Point ReallyEmptyPoint()
- This method returns a System.Drawing.Point
object with the .X and .Y properties set to -1.
public static bool IsReallyEmptyPoint(System.Drawing.Point pt)
- This method returns 'true
' if the .X and .Y properties of the System.Drawing.Point
object 'pt
' both equal -1, else it returns 'false
'.
public static System.Drawing.Rectangle ReallyEmptyRectangle()
- This method returns a System.Drawing.Rectangle
object with the .X, .Y, .Width, and .Height properties set to -1.
public static bool IsReallyEmptyRectangle(System.Drawing.Rectangle rec)
- This method returns 'true
' if the .X, .Y, .Width, and .Height properties of the System.Drawing.Point
object 'rec
' all equal -1, else it returns 'false
.'
"Global" properties of both classes are:
AntAttachedControl
- (I'm sorry about the property's name, but I wanted it to be alphabetically first so that the auto-generated code will set it first.) This property is used to attach the instance of TdhMarchingAnts_NativeWindow
to a specific control.
Enabled
- This boolean value determines whether the class as a whole is enabled/active and thus responsive to the user's mouse activity.
"Left-button" properties, methods, and event handler signatures of both classes are:
AntsActive
- This boolean value determines whether the class is responsive to the user's mouse left-button select and deselect activity.
Note: The default value of this property is 'false
.' It must be set to 'true
' to activate the class for left-button select and deselect activity.
AntBackColor
- The System.Drawing.Color
of the path followed by the "ants" determined by the mouse left-button select activity.
Note: In general, set AntBackColor
before setting AntForeColor
. When AntBackColor
is set, the class automatically sets AntForeColor
to a (hopefully ideal) contrasting color.
AntForeColor
- the System.Drawing.Color
of the "ants" (themselves) determined by the mouse left-button select activity.
Note: To have the class draw a solid line, set AntForeColor
to the same value that AntBackColor
was previously set. (Alternately, this may be accomplished via the ExterminateAnts()
method.)
AntsMarch
- This boolean value determines whether the "ants" determined by the mouse left-button select activity will be animated.
SelectedPointTL
- This property returns a System.Drawing.Point
representing the top-left co-ordinate of the selected region. If there is not yet a selected region, the .X and .Y values are -1.
SelectedPointBR
- This property returns a System.Drawing.Point
representing the bottom-right co-ordinate of the selected region. If there is not yet a selected region, the .X and .Y values are -1.
SelectedRect
- This property returns a System.Drawing.Rectangle
representing the selected region. If there is not yet a selected region, the .Width and .Height values are -1.
public void EraseAntPath()
- This method removes the visual representation of the selected region, while retaining the rectangle co-ordinates themselves.
public void ForgetAntPath()
- This method removes the visual representation of the selected region *and* disposes of the rectangle co-ordinates.
public void ExterminateAnts()
- This method sets AntForeColor
to the current value of AntBackColor
-- i.e., it changes the drawn rectangle to a solid line.
public void SetAntPath(System.Drawing.Rectangle PathRect)
- This method draws a rectangle on the attached control with the co-ordinates of the given rectangle.
Note: This method will generate a 'RegionSelectEvent
' as though the user had selected the region represented by the rectangle.
public delegate void ClickEventHandler(object sender, System.Drawing.Point ClickedPoint)
- [If (.Enabled=true
)] This event occurs when the user left-clicks on the control attached to the TdhMarchingAnts
component.
public delegate void RegionDeselectEventHandler(object sender, System.Drawing.Point ClickedPoint)
- [If (.Enabled=true
) and (.AntsActive=true
) and a region is currently selected] This event occurs when the user left-clicks on the control attached to the TdhMarchingAnts
component.
Note: In this case, both the ClickEvent
and RegionDeselectEvent
events are raised.
public delegate void RegionSelectEventHandler(object sender, System.Drawing.Rectangle SelectedRect)
- [If (.Enabled=true
) and (.AntsActive=true
)] This event is raised when the left mouse button is released following a "click-and-drag."
"Right-button" properties, methods, and event handler signatures of both classes are:
Right_AntsActive
- This boolean value determines whether the class is responsive to the user's mouse right-button select and deselect activity.
Note: The default value of this property is 'false
'. It must be set to 'true
' to activate the class for right-button select and deselect activity.
Right_AntBackColor
- The System.Drawing.Color
of the path followed by the "ants" determined by the mouse right-button select activity.
Note: In general, set AntBackColor
before setting AntForeColor
. When AntBackColor
is set, the class automatically sets AntForeColor
to a (hopefully ideal) contrasting color.
Right_AntForeColor
- the System.Drawing.Color
of the "ants" (themselves) determined by the mouse right-button select activity.
Note: To have the class draw a solid line, set AntForeColor
to the same value that AntBackColor
was previously set. (Alternately, this may be accomplished via the ExterminateAnts()
method.)
Right_AntsMarch
- This boolean value determines whether the "ants" determined by the mouse right-button select activity will be animated.
Right_SelectedPointTL
- This property returns a System.Drawing.Point
representing the top-left co-ordinate of the selected region. If there is not yet a selected region, the .X and .Y values are -1.
Right_SelectedPointBR
- This property returns a System.Drawing.Point
representing the bottom-right co-ordinate of the selected region. If there is not yet a selected region, the .X and .Y values are -1.
Right_SelectedRect
- This property returns a System.Drawing.Rectangle
representing the selected region. If there is not yet a selected region, the .Width and .Height values are -1.
public void Right_EraseAntPath()
- This method removes the visual representation of the selected region, while retaining the rectangle co-ordinates themselves.
public void Right_ForgetAntPath()
- This method removes the visual representation of the selected region *and* disposes of the rectangle co-ordinates.
public void Right_ExterminateAnts()
- This method sets Right_AntForeColor
to the current value of Right_AntBackColor
-- i.e., it changes the drawn rectangle to a solid line.
public void Right_SetAntPath(System.Drawing.Rectangle PathRect)
- This method draws a rectangle on the attached control with the co-ordinates of the given rectangle.
Note: This method will generate a 'RightRegionSelectEvent
' as though the user had selected the region represented by the rectangle.
public delegate void RightClickEventHandler(object sender, System.Drawing.Point ClickedPoint)
- [If (.Enabled=true
)] This event occurs when the user right-clicks on the control attached to the TdhMarchingAnts
component.
public delegate void RightRegionDeselectEventHandler(object sender, System.Drawing.Point ClickedPoint)
- [If (.Enabled=true
) and (.Right_AntsActive=true
) and a region is currently selected] This event occurs when the user right-clicks on the control attached to the TdhMarchingAnts
component.
Note: In this case, both the RightClickEvent
and RightRegionDeselectEvent
events are raised.
public delegate void RightRegionSelectEventHandler(object sender, System.Drawing.Rectangle SelectedRect)
- [If (.Enabled=true
) and (.Right_AntsActive=true
)] This event is raised when the right mouse button is released following a "click-and-drag."
History
- 2006 December 08: Submission of
TdhMarchingAnts
ver. 1.0.001 to The Code Project.
- 2006 December 12: ver. 1.0.002.
Added the following events (and the corresponding properties and methods):
ClickEvent(object sender, System.Drawing.Point ClickedPoint)
RightClickEvent(object sender, System.Drawing.Point ClickedPoint)
RightRegionSelectEvent(object sender, System.Drawing.Rectangle SelectedRect)
RightRegionDeselectEvent(object sender, System.Drawing.Point ClickedPoint)
- 2006 December 13: ver. 1.0.003
- 2006 December 15: ver. 1.0.004
- Corrected the logic flaw in the
TdhMarchingAnts_NativeWindow.InvalidateAntPaths()
method. Due to a timing issue in the this._parentControl.Paint()
event which ultimately is raised by the [this._parentControl.Invalidate(true);
] statement at the start of the .InvalidateAntPaths()
method, it was futile to invoke the .DrawAntPath()
method as an attempt to redraw the 'AntPath(s)'. This is because the this._parentControl.Paint()
event tends to occur *after* .DrawAntPath()
.
- But the serious logic flaw (as contrasted to a mere futility) is that due to the parameter-list of that invocation of the
.DrawAntPath()
method, 'RegionSelectEvent
' was being raised (yet again) following a right-click.
- Added '
object sender
' to the parameter-list of all TDHMarchingAnts.TdhMarchingAnts
EventHandlers.
- 2007 January 8: ver. 1.0.006
- Added logic to intercept a timing-issue problem occurring when disabling the "marching ants" (which includes disposing the
Path
). Apparently, a timer-tick event might already have been scheduled, which would lead to an unhandled exception when that method executed, due to the Path
having been set to null
.
- 2007 January 11: ver. 1.0.007
- Added a check for the condition [
this._parentControl.Visible
] before setting [this._parentControl.Cursor = cursorOriginal;
]. Setting the '_parentControl
' cursor was causing an excepting under VS2005 when '_parentControl
' isn't visible.