views:

956

answers:

2

I have been asked to write a GUI that will allow objects to be stacked inside a container. The user will be viewing the boxes from a top down view point. They also would like to be able to see what is stacked inside. My first thought to solve this was transparency. I have read some of the posts on transparency, however I didn't find any that solved the issues of both images being transparent so you was able to see both if they are stacked.

How can I get the control to be transparent with other controls on top. If this isn't really possible; What is a better aproach to this problem?

I am using a custom control (public partial class MyControl : Control) to solve the issue. I finally have the image on the control transparent. Anything that is drawn on the parent form shows thru the image (I'm using the onPaint for the parent to paint an elipse and a square), however other controls placed over it is no longer transparent.

The code I'm using to accomplish this is below:

public Image Image 
  {
     get { return m_Image; }
     set { m_Image = value; }
  }
private void GridControl_Paint(object sender, PaintEventArgs e)
  {
     if (Image != null)
     {

        Graphics g = e.Graphics;
        Bitmap bitMap = new Bitmap(Image);

        //This is not working... the color array always comes back empty
        //This is how I would rather making things transparent...
        Color[] colorArray = bitMap.Palette.Entries;

        if (colorArray.Length > 0)
        {

           ColorMap[] colorMap = new ColorMap[colorArray.Length];

           for (int index = 0; index < colorArray.Length; index++)
           {
              colorMap[index] = new ColorMap();
              colorMap[index].OldColor = colorArray[index];
              colorMap[index].NewColor = Color.Transparent;
           }

        }

        //Ok fine so the above is not working... let me force it.
        //Get each pixel in the image and change the color.
        else
        {
           for (int x = 0; x < bitMap.Width; x++)
           {
              for (int y = 0; y < bitMap.Height; y++)
              {
                 Color pixelColor = bitMap.GetPixel(x, y);
                 Color newColor = Color.FromArgb(100, pixelColor);

                 bitMap.SetPixel(x, y, newColor);
              }
           }
        }

        bitMap.MakeTransparent();

        g.DrawImage(bitMap, this.ClientRectangle);
     }

  }
+1  A: 

Are you locked into using WinForms? If you need to do much moderately tricky graphics stuff (such as you describe) and can't redesign your app to get around it, you could make the leap into WPF.

It's been a while since I've played in GDI+ graphics, so here's an idea (but no code ;) ):

Do your stacked controls actually need to work? If not, you can copy their appearance to bitmaps, hide them, then use the bitmaps in your own paint routine. When a control needs to work you can unhide it.

By the way, using bitmap.GetPixel or SetPixel is very slow. Here's some old code I had lying around that manipulated 32bit bitmaps (where blue, green, red and alpha are bytes):

BitmapData bmpData = bitmap.LockBits(pixelRect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

unsafe
{
    byte* bytes = (byte*)bmpData.Scan0;
    for (int row = 0; row < pixelRect.Height; row++)
    {
     for (int col = 0; col < pixelRect.Width * 4; ) // * 4: 4 bytes per pixel 
     {
      bytes[row * bmpData.Stride + col++] = blue;
      bytes[row * bmpData.Stride + col++] = green;
      bytes[row * bmpData.Stride + col++] = red;
      bytes[row * bmpData.Stride + col++] = alpha;
     }
    }
}

// Unlock the bits.
bitmap.UnlockBits(bmpData);
AndrewS
I would love to move from WinForms to WPF... however it is not an option for this project:-( The stacked controls do need to work. The user will need to be able to select one (top control left click, others by right click select from the list) and change the properites or move them around. Multiple controls need to also be selected to be moved.Thank you for the code! I might end up using it, right now I'm just trying to prove that this is possible in WinForms.
Billy
A: 

I have not been able to find a good solution to this problem. The only way I have found to do this is thru creating a custom control and using a lot of custom code (that I still don't have working fully). I am going to close this thread with the answer being:

It is too complicated to answer in this forum.

Billy