tags:

views:

221

answers:

1

I have two controls which are both contained within a user control.

  • Panel location: 49, 400
  • Panel size: 787, 70
  • Picturebox location: 25, 0
  • Picturebox Size: 737, 700

Picturebox is seen underneath panel.

I could use some advice on the best way to determine the area of the PictureBox image covered by the panel, so I can copy the image onto the panel correctly in DrawImage call.

My answer is: I will copy screen from this area: 24,400 top left, it will be 714 wide, 70 high But how do I automate to work with any combination of panel and picture box for a re-usable control?

Background if you need more info: The PictureBox contains an image of a map. The panel contains tools for manipulating the map, panel is positioned on top of PictureBox. Panel needs to be semi-transparent so the map image is still seen through it.

Because of the way that winforms paints transparency, (calling up through the control tree to have the parent paint its self) - when I paint my panel it takes on the color of the background of the usercontrol, not the image of the map below it.

My thoughts for this are: if I can copy the image of the map that is below the panel to the background of the panel and then paint my semi-transparent background I will be able to simulate the effect that designers have requested.

Original code from the panel is where I grab the image from the picture box.

            Dim x As Integer = GetXOffset()
            Dim y As Integer = GetYOffset()

            Dim sizeOfImage As Size = New Size(ClientRectangle.Width _
                                  , ClientRectangle.Height)
            bmpScreenshot = New Bitmap(sizeOfImage.Width, sizeOfImage.Height, _
                     PixelFormat.Format32bppArgb)

            gfxScreenshot = Graphics.FromImage(bmpScreenshot)
            Dim destrect As New Rectangle(ClientRectangle.X, ClientRectangle.Y, _
                        ClientRectangle.Width, ClientRectangle.Height)


            gfxScreenshot.DrawImage(mPictureBox1.Image, destrect, New Rectangle(x, y, _
               sizeOfImage.Width, sizeOfImage.Height), GraphicsUnit.Pixel)

I copy this image to the background in the OnPaint event.

If bmpScreenshot Is Nothing Then
            PushScreen()
        End If
        If Not bmpScreenshot Is Nothing Then
            pevent.Graphics.DrawImage(bmpScreenshot, GetPaintOffset())
        End If

And finally, after adding the change from the accepted answer, here is the modified code where the image is grabbed.

 Dim sizeOfImage As Size = New Size(ClientRectangle.Width _
                                  , ClientRectangle.Height)
            bmpScreenshot = New Bitmap(sizeOfImage.Width, sizeOfImage.Height, PixelFormat.Format32bppArgb)

            gfxScreenshot = Graphics.FromImage(bmpScreenshot)

            Dim rect As Rectangle = Rectangle.Intersect(mPictureBox1.Bounds, Bounds)
            Dim destrect As Rectangle = New Rectangle(rect.Left - Left, _
             rect.Top - Top, rect.Width, rect.Height)
            Dim imgrect As Rectangle = _
              New Rectangle(rect.Left - mPictureBox1.Bounds.Left, _
              rect.Top - mPictureBox1.Bounds.Top, rect.Width, rect.Height)

            gfxScreenshot.DrawImage(mPictureBox1.Image, destrect, _
               imgrect, GraphicsUnit.Pixel)
+3  A: 

You can use the Rectangle.Intersect method (together with a tiny bit of calculation) to get the result you want. C# sample:

Rectangle rect = Rectangle.Intersect(_pictureBox.Bounds, _panel.Bounds);
rect = new Rectangle(rect.Top - _panel.Top, rect.Left - _panel.Left, rect.Width, rect.Height);
e.Graphics.FillRectangle(Brushes.Red, rect);

Update

I played around with this a bit more and came up with the following solution, that I find a bit simpler and also a bit more robust (this time VB.NET code):

Private Sub DrawPanelBackground(ByVal pictureBox As PictureBox, ByVal panel As Panel)
    If pictureBox.Image Is Nothing Then
        Exit Sub
    End If

    Dim rect As Rectangle = New Rectangle(pictureBox.Left - panel.Left, pictureBox.Top - panel.Top, pictureBox.Image.Width, pictureBox.Image.Height)
    Using g As Graphics = Panel.CreateGraphics()
        g.DrawImage(pictureBox.Image, rect)
    End Using
End Sub
Fredrik Mörk
The Control.Bounds method will give exactly what is needed if the Panel and PictureBox share a parent (presumably the user control).
Hamish Smith
Thanks, I'll give these a try in different control location and let you know!
BPerreault
the edit shows code which I 'think' would assume panel is always inside of picturebox. What if panel top left were outside of picturebox rectangle?
BPerreault
@BPerreault: With the second version I tried having the panel "sticking out" over the edge of the picture box in various directions, and it worked well in all cases.
Fredrik Mörk
Oh, I wonder what I did wrong then...... In any case, thanks for this, as long as the panel is entirely within the bounds of the picturebox, I have no more issues to fix.
BPerreault