|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
Please note: The large size of the downloads is caused by the images included with the demo project. The compiled .dll library is only 44Kb.

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 '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 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 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 conjuction 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 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:
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 .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 .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 eventhandler 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 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 mouse left-button select activity.
Note: To have the class draw a solid line, set AntForeColor to the same vaue that AntBackColor was previously set. (Alternately, this may be accomplished via the ExterminateAnts() method.)
AntsMarch - This boolean value determines whether the "ants" determined by 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 eventhandler 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 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 mouse right-button select activity.
Note: To have the class draw a solid line, set AntForeColor to the same vaue 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 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 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
- Moved methods from class
TdhMarchingAnts_NativeWindow to class TdhMarchingAnts (and made them 'public'):
- public static
System.Drawing.Point ReallyEmptyPoint()
- public static bool
IsReallyEmptyPoint(System.Drawing.Point pt)
- Created new public methods in class
TdhMarchingAnts:
- public static
System.Drawing.Rectangle ReallyEmptyRectangle()
- public static bool
IsReallyEmptyRectangle(System.Drawing.Rectangle rec)
- 2006 December 15: ver 1.0.004
- Corrected logic flaw in the TdhMarchingAnts_NativeWindow.InvalidateAntPaths() method. Due to a timing issue 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 redrawn 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 the due to the parameter-list of that invocation of the .DrawAntPath() method, the 'RegionSelectEvent' was being raised (yet again) following a right-click.
- Added 'object sender,' to parameter-list 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 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.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 25 (Total in Forum: 25) (Refresh) | FirstPrevNext |
|
 |
|
|
 |
|
|
Hmm, what is your recommendation for porting this over to ASP.NET so that it could be used in a web application?
Thanks for your input
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Unfortunately, I can give you no useful input on that question. I hope you're able to pull it off (and if you do, be sure to submit an article).
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
I have the weirdest request: is there a chance you could PM me your real name?
It's all I need. See, I would like to use your TDHMarchingAnts (which works absolutely fantastic!) in one of the code modules of my Master's thesis.
As you may know, in academia proper attribution is everything to avoid plagiarism - and I want to give honour and credit where honour and credit is due.
Meaning I need to say "TDHMarchingAnts in the public domain found on codeproject.com, original author ".
Thanks! Mike
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
No need for a PM ... for one thing, since I am "no one," my name is no great secret ... for a second thing, even it it were a great secret, some months ago when I momentarily cared about trying to discuss Deep Things with the folk who frequent the SoapBox, someone there decided to make the effort to find out who I am and post the result.
I'm both mystified and gratified that someone would find my effort significant enough to use as part of his Master's thesis.
My name is "Troy Hailey."
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks for that! 
No big mystery: Instead of re-inventing the wheel, I wanted to use a nice marching ants class for my project. If I didn't go and use a lot of "pre-assembled" modules, I could never focus on the actual research part of my thesis.
That's what code reuse is all about, after all! 
Mike
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Quite so; why re-invent the wheel? Though, "enhancing" a wheel one finds or borrows can be gratifying or useful.
Given your needs, I quite understand that you likely will not be trying to think of any ways to enhance this particular wheel. And then, considering that the class is written for a specific and limited task, it may be that the only logical enhancements to it are to make it more effient or to correct logic errors that I haven't yet discovered.
But, should it turn out that as you use the code in your thesis' project you think of a way it could be made better -- or if you discover that due to my status as a self-taught beginner (that is, programming with C# and using OOL concepts, not as a programmer) I've made some sort of programming error -- please let me know.
What's the point or purpose of the program you're writing?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
It is an image-analytical project designed to allow for image-based searching of wines (!) within a catalog/collection.
While technology won't allow us (yet) to transport and store smells and tastes in a program, I am trying to determine whether it is possible to have a program "look" at a glass of wine (just as a wine drinker, like myself, would do) and compare it to others that are stored in image form.
Your class is being used to mark an "area of interest" in an image of wine in a glass, which is then processed with a variety of image-analytical processes. These results are then stored and used for comparison.
No, I didn't get a huge government grant for this. 
Mike
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
Hi,
First I'd like to thank you for putting up such an useful and nice looking control. It's being quite helpful on some work I'm doing right now. Anyway, I've encountered a little problem with it. Probably I'm just doing something wrong, I'm quite new to c# and there are lots of things I still don't know how to properly do. Anyway, I'm having some problems when closing my program. I get an InvalidOperationException about different processes in _CommonDispose() function, exactly here:
if (!gblRunModeIs_DesignMode) { this._parentControl.Cursor = cursorOriginal; }
Maybe it's a common error, because VS directs me here: http://msdn2.microsoft.com/en-us/library/ms171728.aspx I've read the page, but certainly I don't understand most of what it says 
Here's how to reproduce the error under VS2005: -Design a new form2 and attach it the marching ants -From the main form, create a new instance of form2 -The error only shows up when the form2 is hidden, so either don't show it or hide it. -Close the main application -Voila
So, Can anyone reproduce the error, or it's just me? Is this a bug, or am I doing something wrong? Commenting the line avoids the error, but I'm quite positive that's not an acceptable way 
Thanks for everything, Albert
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I'm sorry you're getting an exception. I wasn't able to duplicate it -- but I also don't have VS2005 (perhaps the error you're getting is a combination of what my code is attempting to do in a VS2005 environment).
Try replacing this line:
this._parentControl.Cursor = cursorOriginal; With the following:
if (this._parentControl.Visible) { this._parentControl.Cursor = cursorOriginal; }
And please let me know if this resolves your problem, so that I can incorporate this code into the control.
-- modified at 16:47 Thursday 11th January, 2007
"Maybe it's a common error, because VS directs me here: http://msdn2.microsoft.com/en-us/library/ms171728.aspx I've read the page, but certainly I don't understand most of what it says " That page is called "How to: Make Thread-Safe Calls to Windows Forms Controls" Now, the odd thing about this is that this particular control doesn't use (multi-)threading.
But, I don't doubt that "InvalidOperationException" is quite common; I expect it's a grab-bag exception. So, perhaps that page doesn't really have much to do with the exact error you're getting.
The page says, "If you have two or more threads manipulating the state of a control, it is possible to force the control into an inconsistent state." Even though the marching-ants control doesn't use threading, it does sound as though the circumstance you're experiencing is due to something about your (hidden) form having been forced into "an inconsistent state"
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
Many thanks for your prompt answer.
That code did solve the problem, but it kind of feels like cheating 
The exact error I'm getting is "Control PicBox accessed from a thread other than the thread it was created on.", which is the error discussed in the link I posted before. Like you say, the form is probably carried to another thread when hidden.
In the same web there's this note: "You can disable this exception by setting the value of the CheckForIllegalCrossThreadCalls property to false. This causes your control to run the same way as it would run under Visual Studio 2003." Effectively, adding the line System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false; also solves the problem and would explain why you're not getting the error, but I'd rather not add code like that unless I'm absolutely sure of what it involves, and in this case I'm clearly not.
So, unless someone wants to give a deep explanation on what is going on, I think I'll stick with your solution. Again, thanks for your help. Albert
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
"That code did solve the problem, but it kind of feels like cheating. " No, it's not cheating, it's error-avoidance 
Thanks for letting me know; I'll incorporate that check into my code.
BTW, I've been coding in C# for about 3 years and I still feel like a novice.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Well, after some more in-depth testing, it's still giving me the error. It's only more difficult to predict, that's all 
Seems that the thread restrictions have increased from VS2003 to VS2005. Control.CheckForIllegalCrossThreadCalls = false; "solves" the problem, but: -It's not available under 2003 -Doesn't actually solve the problem, just hides the exception. That can't be good...
Please take a look here when you find the time: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=630558&SiteID=1
Doing this kind of solves the problem: if (!gblRunModeIs_DesignMode) { if (!this._parentControl.InvokeRequired) this._parentControl.Cursor = cursorOriginal; }
That is, if there's no need to invoke it, do the job. Actually that's just part of it. The equivalent of "if (visible)" but working. If the invoke is required, you should (obviously) invoke it. Lots of questions, like where to put the delegate, or even why are not other parts of the code failing under these restrictions, I totally ignore the answers for. Anyway, hope the input helps and you can get the component to be "VS2005 compliant".
Oh, by the way, I've also had two or three OutOFMemory exceptions. I didn't mark the place, but I'll let you know if it happens again. Regards, Albert
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
"Well, after some more in-depth testing, it's still giving me the error. It's only more difficult to predict, that's all" Uggh! Don't you just hate that sort of error?
"Seems that the thread restrictions have increased from VS2003 to VS2005." But, I'm not doing any threading in this code. Perhaps the RunTime is doing some behind-the-scenes threading. Or, perhaps the eror message you're getting is unrelated to the actual error-condition.
Also, keep in mind, the particular instruction generating the error for you is not the only place where the class 'TdhMarchingAnts_NativeWindow' sets [this._parentControl.Cursor]; or, for that matter, sets other properties of [this._parentControl].
For instance, the '_InitializeComponents()' method (which is executed by the class constructor, adds EventHandlers to the parent control). And, more explicitly related to the instruction giving you the problem, when the class is active on the control it's attached to, it sets the control's cursor at both the MouseDown and MouseUp events.
I may be wrong (it should go without saying), but I really do think you're being lead down a false trail.
"Control.CheckForIllegalCrossThreadCalls = false; "solves" the problem, but: -It's not available under 2003 -Doesn't actually solve the problem, just hides the exception. That can't be good..." Certainly; hiding a problem isn't equivalent to solving it.
"Lots of questions, like where to put the delegate, or even why are not other parts of the code failing under these restrictions, I totally ignore the answers for." Precisely, "why are not other parts of the code failing under these restrictions." There is something more/else going on here.
"Oh, by the way, I've also had two or three OutOFMemory exceptions. I didn't mark the place, but I'll let you know if it happens again." Thanks. ======================
Looking again at the code in question, I see that I forgot to ensure that [this._parentControl] is not a null reference, as, for instance, I do a few steps further at the point of removing the EventHandlers my code had added in the '_InitializeComponents()' method. Could the issue be related to this in some way?
I'm wondering whether the potential over-kill I am doing with trying to clean-up the resources I allocate may not be causing the problem. As I mentioned, I still consider myself a novice; and one the the things I know I don't have a firm grasp of is Finalization/Garbage-Collection. (Just over the weekend, I was reading about this again, and I still can't synthesize the various things I've read into a coherent whole).
Anyway, the '_CommonDispose()' method, in which you're getting the error, is executed from both 'Dispose()' and '~TdhMarchingAnts_NativeWindow()' (The rationale for having this code in the '_CommonDispose()' method was to avoid the potential introduction of coding errors or discrepancies in having to maintain two methods doing the same set of tasks).
Might it be that what is happening is that in the particular way you are using this class, when the 'Dispose()' method is executed, [this._parentControl] may or may not already have been GarbageCollected, and thus the instruction [this._parentControl.Cursor = cursorOriginal;] will sporadically and unpredictbly fail? This might also explain why the error reported to you has no rational (so far as I can see) relationship to the possibilities (that is, the error reported to you has to do with threading and my class doesn't use threading).
Realizing that I'd forgotten to ensure that [this._parentControl] is not a null reference, I've modified my code thusly; though, if what I'm thinking is correct, the [&& (this._parentControl.Visible)] check is pointless:
if (!gblRunModeIs_DesignMode && (this._parentControl != null) && (this._parentControl.Visible) ) { this._parentControl.Cursor = cursorOriginal; }
Could you try this (and try it without the [&& (this._parentControl.Visible)] check) and let me know what you think? -- modified at 12:48 Tuesday 16th January, 2007
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hey there seems to be an issue with this. If I click the "test as form component button" and then create a selection rectangle then draw a selection rectangle in the "test using the tdhMarchingAnts Component" form, the uncheck the second checkbox (middle one). I get a JIT exception and it all crashes. This also happens if I uncheck the top checkbox, the re-check it.
Any ideas ???
Try it youself and see if you can repeat it.
sacha barber
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Right you are.
I've duplicated the error-condition (that was easy enough). I haven't yet looked at the code to correct the error, but I highly suspect that it's going to be a timing issue. Or rather, that I'm disposing of some graphics object out-of-sequence.
Thanks for noticing this and making me aware of it. I should have the corrected version uploaded possibly today (01/08) and certainly by tomorrow (01/09).
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Fixed.
[gripe] Man! Updating an article can be such a pain. Most of the time half the formatting disappears and it takes several attempts to get it to stick. [/gripe]
-- modified at 18:12 Monday 8th January, 2007
And today it refuses to cooperate.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Does this replace the ControlPaint.DrawReversibleFrame which does the same job, with a couple of mouseDown / MouseUp events. If it does, then im all for it. Cos I hated messing about with that
sacha barber
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
"Does this replace the ControlPaint.DrawReversibleFrame ..." No and Yes.
No, in that this code makes use of .DrawReversibleFrame() while the user is actively selecting a region with the mouse.
Yes, in that when the user has completed selecting a region, this code draws the "marching ants" -- draws the outline of the selected rectangle -- with graphics objects.
Yes (emphatically!), in that .DrawReversibleFrame() merely draws a representation of the rectangle the developer's code passes to it, whereas this code reports back to the developer's code the rectangle (or the points) of the region selected by the user.
ps. The reason I don't stick with .DrawReversibleFrame() after the user has completed his selection is because I don't like how the result of .DrawReversibleFrame() looks. I understand why it looks as it does (and why it must look as it does), but I wanted something that looks a bit more polished or looks consistent over its entirety.
-- modified at 15:36 Monday 8th January, 2007
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
fair enough... I like what youve done actually.
Good job.
Its made the monthly competition any ways, so some must also like it.
sacha barber
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
| | |