[Webinar] Streamline your web hosting managementRegister Today

x
?
Solved

c# - make rectangle around control get transparent

Posted on 2010-03-27
19
Medium Priority
?
2,533 Views
Last Modified: 2013-12-17
I have a Circle class that draws a circle in a blank rectangle, which is put in a picturebox, then I use the rectangle to move the drawing in the picturebox.
The problem is I can't get the rectangle transparent, I just get it opaque.

Please take a look at my Circle class attached code:
protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            if (this.Width != this.Height)
                this.Width = this.Height;
            pen.Color = BorderColor;
            pen.Width = BorderWidth;
            Create(e.Graphics, new RectangleF(0, 0, this.Width - 3, this.Height - 3), pen, Color.FromArgb(0, FillColor.R, FillColor.G, FillColor.B));           
        }

        private void Create(Graphics gfx, RectangleF bounds, Pen drawPen, Color fillColor)
        {
            int strokeOffset = Convert.ToInt32(Math.Ceiling(drawPen.Width));
            bounds = RectangleF.Inflate(bounds, -strokeOffset, -strokeOffset);
            if (bounds.Width < 1)
                bounds.Width = 1;
            if (bounds.Height < 1)
                bounds.Height = 1;
            drawPen.EndCap = drawPen.StartCap = LineCap.Round;

            GraphicsPath gfxPath = new GraphicsPath();
            gfxPath.AddArc(bounds, 0, 360);
            gfxPath.CloseAllFigures();
            gfx.SmoothingMode = SmoothingMode.AntiAlias;
            gfx.FillPath(new SolidBrush(Color.FromArgb(0, FillColor.R, FillColor.G, FillColor.B)), gfxPath);
            gfx.DrawPath(drawPen, gfxPath);
        }

Open in new window

0
Comment
Question by:dnwx
  • 8
  • 6
  • 4
  • +1
19 Comments
 
LVL 6

Expert Comment

by:spule
ID: 28850346
If you want to make a control transparent, you need to choose a color that is not used in the control (I guess you can use Color.Cyan or Color.Magenta). Then you fill your rectangle with this color and you set your control's TransparencyKey to the same color.
0
 
LVL 16

Expert Comment

by:CuteBug
ID: 28866064
I would suggest you keep your bounding rectangle and the circle in two separate GraphicsPath and call FillPath method for only the Graphics Path containing the circle.

Have a look at the attached code.
        private void Create(Graphics gfx, RectangleF bounds, Pen drawPen, Color fillColor)
        {
            int strokeOffset = Convert.ToInt32(Math.Ceiling(drawPen.Width));
            bounds = RectangleF.Inflate(bounds, -strokeOffset, -strokeOffset);
            if (bounds.Width < 1)
                bounds.Width = 1;
            if (bounds.Height < 1)
                bounds.Height = 1;
            drawPen.EndCap = drawPen.StartCap = LineCap.Round;

            GraphicsPath gfxPath = new GraphicsPath();
            gfxPath.AddArc(bounds, 0, 360);
            gfxPath.CloseAllFigures();
            gfx.SmoothingMode = SmoothingMode.AntiAlias;
            gfx.FillPath(new SolidBrush(Color.FromArgb(0, FillColor.R, FillColor.G, FillColor.B)), gfxPath);
            gfx.DrawPath(drawPen, gfxPath);

            // Draw the rectangle
            gfx.DrawRectangle(drawPen, bounds);
        }

Open in new window

0
 
LVL 1

Author Comment

by:dnwx
ID: 28899885

here you are 2 screenshot.

Please note that what I want to do is to hide that white rectangle. In other words, I want the circles to get interlaced.

First one is my old code.
Second one is using CuteBug's code.

any clues?

spule: I can't find TransparencyKey propertie in other control than Form.
picturebox1.jpg
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
LVL 1

Author Comment

by:dnwx
ID: 28899966
second printscreen:


picturebox2.jpg
0
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 1600 total points
ID: 28903375
0
 
LVL 1

Author Comment

by:dnwx
ID: 28909993
Wow Idle_Mind...
thank you!
Your code is incredibly better than the one which this irresponsible fired guy left behind.

I still got 3 questions for you
1) is it possible for correcting my code or at least keep my structure, at least for today? (purpose is below).
2) What changes do I have to do to fill the ellipses with a different color in both your codes?
2) How to set it antialias in both your approachs? I know about smoothingmode, but I'm not sure how to use in your codes.

Unfortunatelly I'm not sure I'll be able to change the whole code until tomorrow and also fix the other bunch of bugs...
even because originally I'm no c# nor .net developer... "became" c# dev since 4 days ago, when I forcedly inherited this project (because the the other guy spent all project money and got it kind 4 months late without producing 70% of the software). In few words: I'm screwd up.
But I'll sure use your code as soon as possible to turn this software into something really nice, beautiful and usable.

thank you a lot... I'll give you the points for sure.
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 28911872
In my example, the middle of the ellipses are transparent because they are actually being "removed" from the control.  This is done by setting the REGION property of the control to the GraphicsPath containing just the portions of the control I want to keep visible.   The parts of the control that are not in the GraphicsPath are CLIPPED and not drawn at all.  It's as if the control doesn't exist outside the GraphicsPath.  In fact, when you click somewhere not on the ellipse (or the handles) the mouse is actually clicking on whatever is underneath or behind the control.

As far as color goes, are you wanting to changing the color of the ellipse itself?...or fill the interior of the ellipse?

Not sure about aliasing the controls edges itself...
0
 
LVL 1

Author Comment

by:dnwx
ID: 28912752
I want to fill the ellipse inside with other color different than the border color.

Understood the region an clipping thing, thanks again!
0
 
LVL 16

Expert Comment

by:CuteBug
ID: 28941543
Hi dwnx,
      with my code provided, I am getting a rectangle with transparent fill and only the ellipse is filled.

      I have attached the screenshot and the code which I used.
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        if (this.Width != this.Height)
            this.Width = this.Height;
        Pen pen = new Pen(Brushes.Black, 2F);
        Create(e.Graphics, new RectangleF(100, 100, 100, 100), pen, Color.Blue);
        Create(e.Graphics, new RectangleF(150, 150, 100, 100), pen, Color.Red);
    }

    private void Create(Graphics gfx, RectangleF bounds, Pen drawPen, Color fillColor)
    {
        int strokeOffset = Convert.ToInt32(Math.Ceiling(drawPen.Width));
        bounds = RectangleF.Inflate(bounds, -strokeOffset, -strokeOffset);
        if (bounds.Width < 1)
            bounds.Width = 1;
        if (bounds.Height < 1)
            bounds.Height = 1;
        drawPen.EndCap = drawPen.StartCap = LineCap.Round;

        GraphicsPath gfxPath = new GraphicsPath();
        gfxPath.AddArc(bounds, 0, 360);
        gfxPath.CloseAllFigures();
        gfx.SmoothingMode = SmoothingMode.AntiAlias;
        gfx.FillPath(new SolidBrush(fillColor), gfxPath);
        gfx.DrawPath(drawPen, gfxPath);

        // Draw the rectangle
        gfx.DrawRectangle(drawPen, bounds.Left, bounds.Top, bounds.Width, bounds.Height);
    }
}

Open in new window

Circle-Rect.JPG
0
 
LVL 1

Author Comment

by:dnwx
ID: 28948203
CuteBug:

I can't figure out how to use your code inside my Circle class, I mean, how to do make it work without writing hardcoded code in the picturebox Paint method.

Is there a way that I can put this code dinamically in the picturebox Paint method everytime I click the CreateCircle button?

Just to make it clear: I need to move and resize those circles (it already works this way with my old code)..

Puting your code hardcoded in the picturebox's paint method works perfectly as your printscreen shows.
0
 
LVL 16

Expert Comment

by:CuteBug
ID: 28952548
There is a way to solve your problem.

First, in your Circle class, maintain the location and size of the Circle. do have a method in your Circle class (say Render) which will take Graphics as an input.
In your Form (or your main class) which contains the picturebox, maintain a List of your Circle class.
In the Paint method of the PictureBox, you will get the Graphics class, e.Graphics . Now iterate through each Circle in the List and call the Render method of that object while passing e.Graphics as the argument.

Now whenever you move or resize any of your Circle, all you need to do it update that Circle's values in the List and call the Invalidate() method of the PictureBox which will redraw all the Circles.

In order to avoid flickering, make your Form and Picturebox double buffered.
Check these links for double buffering
http://www.bobpowell.net/doublebuffer.htm
http://www.codeproject.com/KB/graphics/DoubleBuffering.aspx
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 28984375
So you have two basic options:
(1) Each circle is its own control.  This requires the control to be clipped, though, by setting the Region() property if you want to be able to overlap the things since the underlying basis for controls is a rectangle.  The advantage here is that you can get mouse events for each control neatly encapsulated in the controls themselves.
(2) Everything is drawn directly into the PictureBox.  Since you are only drawing the circles you don't need to worry about the overlapping issue as they will do this by default.  The disadvantage is that you must manually perform all of your hit-testing to determine if the mouse is over a circle.  The code for allowing selection and manipulation of the circles becomes a lot messier.
0
 
LVL 16

Assisted Solution

by:CuteBug
CuteBug earned 400 total points
ID: 28994408
Hi Idle_Mind,
      I have a solution for (2)

      Three event must be considered for the handling selection and manipulation of the circle objects
      1. MouseDownEvent
      2. MouseMoveEvent
      3. MouseUpEvent

      The Circle objects will be maintained in a List<Circle>, say, DrawnCircles.

      We must also maintain the reference to the Circle being currently manipulated, say, CurrentCircle.

      The Circle class must also have the following:
      1. An enum called ManipulationMode having three values { RESIZING, MOVING, NONE }
      2. A private variable called m_ManipulationMode of type ManipulationMode.
      3. A method called IsManipulated(Point pt) - This will determine whether the given point lies within one of the handles of the Circle (if yes then set m_ManipulationMode as RESIZING) or within the Circle (If yes then set m_ManipulationMode as MOVING). This method will return true if the value of m_ManipulationMode is RESIZING/MOVING else it will return false.
      4. A member variable called m_PrevPoint of type Point. Set m_PrevPoint = pt (in the IsManipulated method)
      5. A method called HandleManipulation(Point pt) - which will do the resizing/moving based on the new Point being provided.
      6. A method called StopManipulation() which will set the m_ManipulatedMode to NONE.

      Now in the main Form, handle the MouseDown, MouseMove and MouseUp events of the PictureBox.

      In the MouseDown eventHandler, iterate through each Circle in the DrawnCircles list and call the IsManipulated method of each Circle. If any Circle's method returns true then set CurrentCircle equal to that Circle.

      In the MouseMove eventHandler, check if the mouse is down and CurrentCircle is not null, then call the HandleManipulation method of that Circle, passing the point obtained.

      In the MouseMove eventHandler, check if the CurrentCircle is not null, then call the StopManipulation method of that Circle.

      This should do it.
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 28994782
That'll work...

In fact, in the SAME PAQ I referenced earlier that demonstrates method #1, I also posted a simple version of method #2:
http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_25089847.html#26428585
0
 
LVL 16

Expert Comment

by:CuteBug
ID: 28995684
Oh.. ok!

Well, previously I did not go through the link you provided, Idle_Mind.

Anyways I hope dnwx would now have got a good idea for the solution to his problem.

cheers
CuteBug
0
 
LVL 1

Author Comment

by:dnwx
ID: 29002728
CuteBug and Idle_Mind,

I'm still reading and "digesting" all information.

Just would like you to know you really helped me a lot.

I'll give you my feedback as soon as possible (i'm at worktime now).

Thank you!!!
0
 
LVL 1

Author Comment

by:dnwx
ID: 29165536
dudes,

sorry for the delay.

I've done the Region thing, because using one of the other ideas would require to change a lot of code, spread all over the software, it would be almost the same as doing it from zero mark.

Unfortunatelly, even the simpler region code get's a lot ugly because of aliasing. And I couldn't find a way to smooth it.
Any Ideas on how to smooth the clipped border, or should I just give up and start it using your ideas/code?


Here you are a printscreen showing the aliasing thing.
sample.png
0
 
LVL 16

Expert Comment

by:CuteBug
ID: 29212329
In the OnPaint() method, try setting the InterpolationMode and SmoothingMode properties of e.Graphics.

Set e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic
and e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
0
 
LVL 1

Author Closing Comment

by:dnwx
ID: 31709707
Thank you CuteBug and Idle_Mind. You helped me a lot. I would give you 500 points if I could, but I had to share between you both. I'm sticking with Idle_Mind's code, so I gave him more points.
0

Featured Post

Learn to develop an Android App

Want to increase your earning potential in 2018? Pad your resume with app building experience. Learn how with this hands-on course.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
Hello there! As a developer I have modified and refactored the unit tests which was written by fellow developers in the past. On the course, I have gone through various misconceptions and technical challenges when it comes to implementation. I would…
Enter Foreign and Special Characters Enter characters you can't find on a keyboard using its ASCII code ... and learn how to make a handy reference for yourself using Excel ~ Use these codes in any Windows application! ... whether it is a Micr…
SQL Database Recovery Software repairs the MDF & NDF Files, corrupted due to hardware related issues or software related errors. Provides preview of recovered database objects and allows saving in either MSSQL, CSV, HTML or XLS format. Ensures recov…
Suggested Courses

640 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question