Click here to Skip to main content
Click here to Skip to main content

Combining GDI and GDI+ to Draw Rubber Band Rectangles

, 9 Sep 2003
Rate this:
Please Sign up or sign in to vote.
Demonstrates drawng rubber band rectangles using GDI in a .NET GDI app

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

Share

About the Author

cthomas
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 Pinmembermanoj kumar choubey26-Feb-12 22:56 
QuestionHow to avoid/reduce flickering PinmemberTheMperor24-Feb-12 10:50 
QuestionHow do I draw a general polygon with xor? Pinmemberphojholt2-Jan-11 0:12 
GeneralVery good Pinmemberbluealert4556-Jul-09 16:24 
GeneralProblem removing the frame PinmemberbuyValu23-Aug-08 7:13 
QuestionHow to Select Multiple Controls at Runtime PinmemberMember #386972714-Mar-07 22:40 
GeneralAlternative approach Pinmemberzanderxo26-Dec-06 19:43 
NewsControlPaint.DrawReversibleFrame() Pinmembers-arhipenko25-Sep-06 23:27 
GeneralBug when using code in a scrollable panel PinmemberFrédéric BEAULIEU12-May-06 4:52 
QuestionNeed to draw a rubberband rectangle and capture coordinates Pinmembersowjanya_d7-Dec-05 20:19 
GeneralDifferent way PinmemberTellyB25-Sep-05 18:01 
GeneralRe: Different way Pinmembergabegabe12-Apr-07 21:12 
GeneralRe: Different way - no, not really. Pinmemberhugh12323-Jul-07 13:28 
GeneralDrwaing on top of web browser control PinmemberBalaji Vishnumolakala25-Aug-05 12:37 
GeneralRe: Drwaing on top of web browser control Pinmembercthomas26-Aug-05 14:56 
Generalchange background of Rubber Band Rectangle Pinsussis_vlb507-Jun-05 9:35 
GeneralRe: change background of Rubber Band Rectangle Pinmembercthomas7-Jun-05 17:35 
GeneralRe: change background of Rubber Band Rectangle Pinmemberis_vlb507-Jun-05 22:22 
GeneralRe: change background of Rubber Band Rectangle Pinmembercthomas8-Jun-05 18:40 
QuestionWhere did those constants come from? PinmemberDavid Piepgrass28-Apr-05 8:12 
AnswerRe: Where did those constants come from? PinmemberDavid Piepgrass28-Apr-05 8:21 
GeneralRe: Where did those constants come from? PinmemberDavid Piepgrass28-Apr-05 8:34 
GeneralRe: Where did those constants come from? Pinmembercthomas26-Aug-05 14:51 
GeneralBetter get a license for this... PinmemberMike Stevenson19-Apr-04 14:18 
GeneralSolid brush doesn't seem to appear Pinsussdavemc22-Nov-03 16:19 
GeneralRe: Solid brush doesn't seem to appear Pinmembercthomas22-Nov-03 18:40 
GeneralRe: Solid brush doesn't seem to appear Pinmemberdavemc22-Nov-03 19:27 
GeneralRe: Solid brush doesn't seem to appear Pinmembercthomas23-Nov-03 17:33 
Questiondrawing in a Scrollable Form?? Pinmemberazusakt24-Sep-03 23:14 
AnswerRe: drawing in a Scrollable Form?? Pinmembercthomas25-Sep-03 18:21 
AnswerRe: drawing in a Scrollable Form?? Pinmembercthomas27-Sep-03 9:00 
GeneralRe: drawing in a Scrollable Form?? Pinmemberazusakt29-Sep-03 0:48 
GeneralRe: drawing in a Scrollable Form?? Pinmembercthomas29-Sep-03 20:14 
GeneralSimpler way PinmemberMichael Potter10-Sep-03 11:43 
GeneralRe: Simpler way Pinmemberyvdh12-Sep-03 14:11 
GeneralRe: Simpler way Pinmemberbsmucker26-Dec-03 11:41 
GeneralRe: Simpler way PinmemberMichael Potter26-Dec-03 12:03 
GeneralRe: Simpler way Pinmembercirocco22-Apr-04 23:54 
GeneralGood Stuff! PinmemberStoo 7010-Sep-03 7:20 
GeneralRe: Good Stuff! PinmemberArun Bhalla16-Sep-03 14:11 
GeneralRe: Good Stuff! Pinmembercthomas16-Sep-03 18:55 
GeneralRe: Good Stuff! PinmemberArun Bhalla16-Sep-03 19:04 
GeneralRe: Good Stuff! Pinmembercthomas16-Sep-03 20:39 
GeneralRe: Good Stuff! PinmemberArun Bhalla16-Sep-03 21:01 
GeneralRe: Good Stuff! Pinmembercthomas17-Sep-03 17:54 
GeneralRe: Good Stuff! PinmemberArun Bhalla18-Sep-03 12:17 
GeneralRe: Good Stuff! Pinmembercthomas18-Sep-03 19:18 
QuestionWhy not using more advanced techniques? Pinmembertstih10-Sep-03 5:00 
AnswerRe: Why not using more advanced techniques? Pinmembercthomas10-Sep-03 17:06 
GeneralRe: Why not using more advanced techniques? PinmemberBlake Coverett10-Sep-03 18:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411023.1 | Last Updated 10 Sep 2003
Article Copyright 2003 by cthomas
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid