Click here to Skip to main content
11,640,599 members (59,526 online)
Click here to Skip to main content

Combining GDI and GDI+ to Draw Rubber Band Rectangles

, 9 Sep 2003 183.7K 2.5K 65
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

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
manoj kumar choubey26-Feb-12 21:56
membermanoj kumar choubey26-Feb-12 21:56 
QuestionHow to avoid/reduce flickering Pin
TheMperor24-Feb-12 9:50
memberTheMperor24-Feb-12 9:50 
QuestionHow do I draw a general polygon with xor? Pin
phojholt1-Jan-11 23:12
memberphojholt1-Jan-11 23:12 
GeneralVery good Pin
bluealert4556-Jul-09 15:24
memberbluealert4556-Jul-09 15:24 
GeneralProblem removing the frame Pin
buyValu23-Aug-08 6:13
memberbuyValu23-Aug-08 6:13 
QuestionHow to Select Multiple Controls at Runtime Pin
Member #386972714-Mar-07 21:40
memberMember #386972714-Mar-07 21:40 
GeneralAlternative approach Pin
zanderxo26-Dec-06 18:43
memberzanderxo26-Dec-06 18:43 
NewsControlPaint.DrawReversibleFrame() Pin
s-arhipenko25-Sep-06 22:27
members-arhipenko25-Sep-06 22:27 
GeneralBug when using code in a scrollable panel Pin
Frédéric BEAULIEU12-May-06 3:52
memberFrédéric BEAULIEU12-May-06 3:52 
QuestionNeed to draw a rubberband rectangle and capture coordinates Pin
sowjanya_d7-Dec-05 19:19
membersowjanya_d7-Dec-05 19:19 
GeneralDifferent way Pin
TellyB25-Sep-05 17:01
memberTellyB25-Sep-05 17:01 
GeneralRe: Different way Pin
gabegabe12-Apr-07 20:12
membergabegabe12-Apr-07 20:12 
GeneralRe: Different way - no, not really. Pin
hugh12323-Jul-07 12:28
memberhugh12323-Jul-07 12:28 
GeneralDrwaing on top of web browser control Pin
Balaji Vishnumolakala25-Aug-05 11:37
memberBalaji Vishnumolakala25-Aug-05 11:37 
GeneralRe: Drwaing on top of web browser control Pin
cthomas26-Aug-05 13:56
membercthomas26-Aug-05 13:56 
Generalchange background of Rubber Band Rectangle Pin
is_vlb507-Jun-05 8:35
sussis_vlb507-Jun-05 8:35 
GeneralRe: change background of Rubber Band Rectangle Pin
cthomas7-Jun-05 16:35
membercthomas7-Jun-05 16:35 
GeneralRe: change background of Rubber Band Rectangle Pin
is_vlb507-Jun-05 21:22
memberis_vlb507-Jun-05 21:22 
GeneralRe: change background of Rubber Band Rectangle Pin
cthomas8-Jun-05 17:40
membercthomas8-Jun-05 17:40 
QuestionWhere did those constants come from? Pin
David Piepgrass28-Apr-05 7:12
memberDavid Piepgrass28-Apr-05 7:12 
AnswerRe: Where did those constants come from? Pin
David Piepgrass28-Apr-05 7:21
memberDavid Piepgrass28-Apr-05 7:21 
GeneralRe: Where did those constants come from? Pin
David Piepgrass28-Apr-05 7:34
memberDavid Piepgrass28-Apr-05 7:34 
GeneralRe: Where did those constants come from? Pin
cthomas26-Aug-05 13:51
membercthomas26-Aug-05 13:51 
GeneralBetter get a license for this... Pin
Mike Stevenson19-Apr-04 13:18
memberMike Stevenson19-Apr-04 13:18 
GeneralSolid brush doesn't seem to appear Pin
davemc22-Nov-03 15:19
sussdavemc22-Nov-03 15:19 
GeneralRe: Solid brush doesn't seem to appear Pin
cthomas22-Nov-03 17:40
membercthomas22-Nov-03 17:40 
GeneralRe: Solid brush doesn't seem to appear Pin
davemc22-Nov-03 18:27
memberdavemc22-Nov-03 18:27 
GeneralRe: Solid brush doesn't seem to appear Pin
cthomas23-Nov-03 16:33
membercthomas23-Nov-03 16:33 
Questiondrawing in a Scrollable Form?? Pin
azusakt24-Sep-03 22:14
memberazusakt24-Sep-03 22:14 
AnswerRe: drawing in a Scrollable Form?? Pin
cthomas25-Sep-03 17:21
membercthomas25-Sep-03 17:21 
AnswerRe: drawing in a Scrollable Form?? Pin
cthomas27-Sep-03 8:00
membercthomas27-Sep-03 8:00 
GeneralRe: drawing in a Scrollable Form?? Pin
azusakt28-Sep-03 23:48
memberazusakt28-Sep-03 23:48 
GeneralRe: drawing in a Scrollable Form?? Pin
cthomas29-Sep-03 19:14
membercthomas29-Sep-03 19:14 
GeneralSimpler way Pin
Michael Potter10-Sep-03 10:43
memberMichael Potter10-Sep-03 10:43 
GeneralRe: Simpler way Pin
yvdh12-Sep-03 13:11
memberyvdh12-Sep-03 13:11 
GeneralRe: Simpler way Pin
bsmucker26-Dec-03 10:41
memberbsmucker26-Dec-03 10:41 
GeneralRe: Simpler way Pin
Michael Potter26-Dec-03 11:03
memberMichael Potter26-Dec-03 11:03 
GeneralRe: Simpler way Pin
cirocco22-Apr-04 22:54
membercirocco22-Apr-04 22:54 
GeneralGood Stuff! Pin
Stoo 7010-Sep-03 6:20
memberStoo 7010-Sep-03 6:20 
GeneralRe: Good Stuff! Pin
Arun Bhalla16-Sep-03 13:11
memberArun Bhalla16-Sep-03 13:11 
GeneralRe: Good Stuff! Pin
cthomas16-Sep-03 17:55
membercthomas16-Sep-03 17:55 
GeneralRe: Good Stuff! Pin
Arun Bhalla16-Sep-03 18:04
memberArun Bhalla16-Sep-03 18:04 
GeneralRe: Good Stuff! Pin
cthomas16-Sep-03 19:39
membercthomas16-Sep-03 19:39 
GeneralRe: Good Stuff! Pin
Arun Bhalla16-Sep-03 20:01
memberArun Bhalla16-Sep-03 20:01 
GeneralRe: Good Stuff! Pin
cthomas17-Sep-03 16:54
membercthomas17-Sep-03 16:54 
GeneralRe: Good Stuff! Pin
Arun Bhalla18-Sep-03 11:17
memberArun Bhalla18-Sep-03 11:17 
GeneralRe: Good Stuff! Pin
cthomas18-Sep-03 18:18
membercthomas18-Sep-03 18:18 
QuestionWhy not using more advanced techniques? Pin
tstih10-Sep-03 4:00
membertstih10-Sep-03 4:00 
AnswerRe: Why not using more advanced techniques? Pin
cthomas10-Sep-03 16:06
membercthomas10-Sep-03 16:06 
GeneralRe: Why not using more advanced techniques? Pin
Blake Coverett10-Sep-03 17:43
memberBlake Coverett10-Sep-03 17: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
Web04 | 2.8.150731.1 | Last Updated 10 Sep 2003
Article Copyright 2003 by cthomas
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid