5,699,431 members and growing! (16,951 online)
Email Password   helpLost your password?
Multimedia » GDI+ » General     Intermediate

Combining GDI and GDI+ to Draw Rubber Band Rectangles

By cthomas

Demonstrates drawng rubber band rectangles using GDI in a .NET GDI app
C#, Windows, .NET, Visual Studio, Dev

Posted: 9 Sep 2003
Updated: 9 Sep 2003
Views: 117,829
Bookmarked: 39 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
18 votes for this Article.
Popularity: 4.94 Rating: 3.94 out of 5
3 votes, 16.7%
1
1 vote, 5.6%
2
0 votes, 0.0%
3
5 votes, 27.8%
4
9 votes, 50.0%
5

Introduction

I have been frustrated, like many others apparently, by the lack of XOR drawing capabilities in the .NET Framework. This is of particular interest when it’s needed to outline a selected Region of Interest in a graphic. I’ve seen several approaches to solve this problem that have, for the most part, stayed within the .NET Framework context, but they were fairly complex. Thus, I was inspired when I saw the article "Using GDI and GDI+ mixed drawing rubber band lines" by sedatkurt in the MFC/C++ >> GDI >> Unedited Reader Contributions in The CodeProject. I was sure it could be extended to rectangles as well.

Background

Anyone who has used a graphics program has probably also used a selection rectangle to act on only a portion of the displayed image. In historical Windows® applications, this selection rectangle is normally drawn by the mouse from a starting corner with the left mouse button depressed until the button is released. The mouse position at each move event is the second corner of the drawn rectangle. Along the way, the rectangle is therefore drawn and erased many times until the final version is drawn at mouse button up. If the drawing mode is set to an XOR raster operation (ROP), the rectangle is usually completely visible since all bits of the pixels are XORed with the color of the drawing pen. More importantly, redrawing in XOR mode along the same rectangle with the same pen automatically restores the original pixel colors, effectively erasing the rectangle. Unfortunately, the .NET Framework Team did not include ROP drawing control in GDI+.

The Core Code

While I adopted the basic concept that sedatkurt showed in his code, I was primarily interested in developing a strictly rubber band rectangle drawing capability. Consequently, all and only the rubber band rectangle related code is concentrated into the RubberbandRectangle class in the RubberbandRects namespace in the file RubberbandRects.cs. This means hardcoding the pen style to draw the rectangle border as a dotted line (PS_DOT), an XOR drawing mode for the pen (R2_XORPEN), a pen width of 1 pixel (doesn't have to be pretty, just visible), and a brush style to NOT fill in the rectangle (NULL_BRUSH) so the underlying graphics are still visible. The resultant public API of RubberbandRectangle is quite compact:

      public class RubberbandRectangle
      {
        public RubberbandRectangle();
        public int PenStyle { get/set }
        public void DrawXORRectangle( Graphics grp,
                    int X1, int Y1,
                    int X2, int Y2 );
      }
    

The default constructor sets the pen style to the default value of PS_DOT. I was not originally going to include a capability to reset this value, but I relented and made the pen style a property with get/set capability. The pen color is fixed internally in the class as a predefined BLACK_PEN in the CreatePen call, although I kept sedatkurt's RGB conversion macro in case.

The process of drawing the XORed rectangle begins with extracting the Win32 GDI device context from the GDI+ Graphics object passed to the function. A black dotted pen is created one pixel wide. The ROP drawing mode is then set to XOR and the new pen selected into the device context; the old pen's handle is saved for replacement later (always clean up resources when you're finished with them). A stock NULL_BRUSH is created and simultaneously selected into the device context, again saving the old brush handle for later. The drawing is now performed, the old brush and pen put back into the device context, and the new pen deleted. Note that stock resources do not need to be deleted since they're only borrowed anyway. The device context is released and the function is finished.

Using the Code

The demo application is in the file MainForm.cs. It is a simple WindowsForm with a number of rectangles painted on its client area in the MainForm_Paint event handler. However, I've also added a call to DrawXORRectangle() if a rubber band rectangle was present (the flag haveRect is set) so that the dotted rectangle is also then redrawn.

The rectangle drawing functionality is nearly the same as in sedatkurt's code. The rubber banding operation is initiated in MainForm_MouseDown where the mouseDown flag is set to indicate that the mouse button is down. The initial point of the mouse down event is stored in XDown and YDown. All of this presumes that it was the Left mouse button that is being pressed. I use a Right mouse button press to initiate an operation to clear the rubber band rectangle from the screen (clear the haveRect flag and call Invalidate() ).

The stage is now set for the actual drawing, which takes place in the MainForm_MouseMove event handler. Drawing will actually only occur if the mouse button is down. This prevents an attempt at drawing when the mouse is simply run across the app. If the mouse is down and moving, a rectangle has already been drawn and must be erased with a call to DrawXORRectangle(). The rectangle is then redrawn through a call to DrawXORRectangle() with one corner at the new mouse coordinates. The new coordinates are saved and the moving flag set.

The final part of the rubber band rectangle drawing occurs in the MainForm_MouseMove event handler. The mouseDown and mouseMove flags are cleared and the haveRect flag is set. We now have a dotted rectangle in the client area of the app window.

Points of Interest

This code was developed in SharpDevelop, an IDE available for free at http://www.icsharpcode.net. It is an evolving, beta level project written in C# and comes with full source code. While it still has warts, it is improving by the month and the price is right. For anything but large team, production code development, it works fine. I used version 0.96 which compiles with .NET Framework v1.1, so you will need the latest .NET version to run the demo app. There is no apparent reason it won't compile with Visual Studio 2003 or any other Visual Studio / .NET Framework pair as well.

What's Next

The code in the RubberbandRectangle class is a stripped down version I had evolved keeping a lot of the enums and functions implied by sedatkurt's code and adding the enums and functions appropriate for the rectangle (or rounded rectangle or ellipse or polygon) drawing cases. In the end, I stripped it all out since I had no interest in demonstrating it and the extension of what's left is fairly straight forward. A possible extension in the same vein as rubber banding is the ability to move bitmaps around the client area with the mouse. A brush made from the bitmap should be as effecting in XOR drawing mode as a dotted pen. At any rate, enjoy.

History

  • New code - no changes.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

cthomas



Occupation: Web Developer
Location: United States United States

Other popular GDI+ articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 47 (Total in Forum: 47) (Refresh)FirstPrevNext
GeneralProblem removing the framememberbuyValu7:13 23 Aug '08  
GeneralHow to Select Multiple Controls at Runtimemember22:40 14 Mar '07  
GeneralAlternative approachmemberzanderxo19:43 26 Dec '06  
NewsControlPaint.DrawReversibleFrame()members-arhipenko23:27 25 Sep '06  
GeneralBug when using code in a scrollable panelmemberFrédéric BEAULIEU4:52 12 May '06  
QuestionNeed to draw a rubberband rectangle and capture coordinatesmembersowjanya_d20:19 7 Dec '05  
GeneralDifferent waymemberTellyB18:01 25 Sep '05  
GeneralRe: Different waymembergabegabe21:12 12 Apr '07  
GeneralRe: Different way - no, not really.memberhugh12313:28 23 Jul '07  
GeneralDrwaing on top of web browser controlmemberBalaji Vishnumolakala12:37 25 Aug '05  
GeneralRe: Drwaing on top of web browser controlmembercthomas14:56 26 Aug '05  
Generalchange background of Rubber Band Rectanglesussis_vlb509:35 7 Jun '05  
GeneralRe: change background of Rubber Band Rectanglemembercthomas17:35 7 Jun '05  
GeneralRe: change background of Rubber Band Rectanglememberis_vlb5022:22 7 Jun '05  
GeneralRe: change background of Rubber Band Rectanglemembercthomas18:40 8 Jun '05  
GeneralWhere did those constants come from?memberDavid Piepgrass8:12 28 Apr '05  
GeneralRe: Where did those constants come from?memberDavid Piepgrass8:21 28 Apr '05  
GeneralRe: Where did those constants come from?memberDavid Piepgrass8:34 28 Apr '05  
GeneralRe: Where did those constants come from?membercthomas14:51 26 Aug '05  
GeneralBetter get a license for this...supporterMike Stevenson14:18 19 Apr '04  
GeneralSolid brush doesn't seem to appearsussdavemc16:19 22 Nov '03  
GeneralRe: Solid brush doesn't seem to appearmembercthomas18:40 22 Nov '03  
GeneralRe: Solid brush doesn't seem to appearmemberdavemc19:27 22 Nov '03  
GeneralRe: Solid brush doesn't seem to appearmembercthomas17:33 23 Nov '03  
Generaldrawing in a Scrollable Form??memberazusakt23:14 24 Sep '03