Creating a transparent portion of a control to see controls underneath it

。_饼干妹妹 提交于 2019-12-01 06:37:16

问题


I've modified the SuperContextMenuStrip found at CodeProject to meet some of my projects needs. I'm using it as a tooltip for map markers on a GMap.NET Map Control. Here is a sample of what it looks like:

What I would like to do is pretty this up a little by making it look more like a bubble. Similar to an old Google Maps stytle tooltip:

I've spent some time searching on control transparency and I know this isn't an easy thing. This SO question in particular illustrates that.

I have considered overriding the OnPaint method of the SuperContextMenuStrip to draw a background of the GMap.NET control that is underneath the SuperContextMenuStrip, but even that would fail in cases where the marker is hanging off the GMap.NET control:

What is the correct way to create the type of transparency I am looking for?


回答1:


In Windows Forms, you achieve transparency (or draw irregularly shaped windows) by defining a region. To quote MSDN

The window region is a collection of pixels within the window where the operating system permits drawing.

In your case, you should have a bitmap that you will use as a mask. The bitmap should have at least two distinct colors. One of these colors should represent the part of the control that you want to be transparent.

You would then create a region like this:

// this code assumes that the pixel 0, 0 (the pixel at the top, left corner) 
// of the bitmap passed contains the color you  wish to make transparent.

       private static Region CreateRegion(Bitmap maskImage) {
           Color mask = maskImage.GetPixel(0, 0);
           GraphicsPath grapicsPath = new GraphicsPath(); 
           for (int x = 0; x < maskImage.Width; x++) {
               for (int y = 0; y < maskImage.Height; y++) {
                   if (!maskImage.GetPixel(x, y).Equals(mask)) {
                           grapicsPath.AddRectangle(new Rectangle(x, y, 1, 1));
                       }
                   }
           }

           return new Region(grapicsPath);
       }

You would then set the control’s Region to the Region returned by the CreateRegion method.

this.Region = CreateRegion(YourMaskBitmap);

to remove the transparency:

this.Region = new Region();

As you can probably tell from the code above, creating regions is expensive resource-wise. I'd advice saving regions in variables should you need to use them multiple times. If you use cached regions this way, you'd soon experience another problem. The assignment would work the first time but you would get an ObjectDisposedException on subsequent calls.

A little investigation with refrector would reveal the following code within the set accessor of the Region Property:

         this.Properties.SetObject(PropRegion, value);
            if (region != null)
            {
                region.Dispose();
            }

The Region object is disposed after use! Luckily, the Region is clonable and all you need to do to preserve your Region object is to assign a clone:

private Region _myRegion = null;
private void SomeMethod() {
    _myRegion = CreateRegion(YourMaskBitmap);            
}

private void SomeOtherMethod() {
    this.Region = _myRegion.Clone();
}


来源:https://stackoverflow.com/questions/12581578/creating-a-transparent-portion-of-a-control-to-see-controls-underneath-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!