views:

706

answers:

8

I am trying to create an image of a Panel and save it to a folder. The problem is the panel has scrollbars and the image generated is only for the visible portion of the Panel.

The code I use is something like Panel.DrawToImage. Could there be any help out here to save the entire Panel as a picture and not just the visible portion?

A: 

Hmmm... It sounds like (as you did not say so in the original question) but would you have a picturebox acting as a container inside the panel's container i.e. nested containers?

Have you not considered doing this:

// Assume pic is the type of PictureBox and the image property is assigned
PictureBox pic;

// And that the picturebox is embedded in the Panel variable p.
p.Controls.Add(pic);

// ...

// So why not do this?
pic.Image.Save(...); 

The Save method of the Image class has 5 overloads so choose one at your convenience.

Hope this helps, Best regards, Tom.

tommieb75
I think he wants to "screenshot" a container control on his form.
hometoast
@hometoast: Oh...Now I understand...ummm...how about Alt+PrtScrn, and paste it into mspaint? Or some other Screen grabber tool? In short the answer is no as the screen capture what's there regardless of whether the image is clipped or not!
tommieb75
+1  A: 

Consider temporarily increasing the panel's size, calling p.Layout(), then p.DrawToImage()

hometoast
The Control is bigger than the display size of the screen anyways. So the scrollbars are just impossible to get rid of!!
Shri
+1  A: 

Perhaps you could clone the control to another (hidden) form at the desired size (such that the scroll bars aren't displayed) and call your DrawToImage() function that way?

Erik Forbes
+1  A: 

I think the WM_PRINT message is going to be helpful. Here's a sample that almost works. (It still prints the scrollbars themselves, and the background is lost on the "out of scroll" portions.) Perhaps you can play with this and get it working, or someone with more WinForms experience can take this to the next level?

Declare the following in your class:

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

private const int WM_PRINT = 791;

/// <summary>
/// The WM_PRINT drawing options
/// </summary>
[Flags]
private enum DrawingOptions
{
    /// <summary>
    /// Draws the window only if it is visible.
    /// </summary>
    PRF_CHECKVISIBLE = 1,

    /// <summary>
    /// Draws the nonclient area of the window.
    /// </summary>
    PRF_NONCLIENT = 2,
    /// <summary>

    /// Draws the client area of the window.
    /// </summary>
    PRF_CLIENT = 4,

    /// <summary>
    /// Erases the background before drawing the window.
    /// </summary>
    PRF_ERASEBKGND = 8,

    /// <summary>
    /// Draws all visible children windows.
    /// </summary>
    PRF_CHILDREN = 16,

    /// <summary>
    /// Draws all owned windows.
    /// </summary>
    PRF_OWNED = 32
}

Then, to paint the control to a bitmap:

using (Bitmap screenshot = new Bitmap(this.panel1.DisplayRectangle.Width, this.panel1.DisplayRectangle.Height))
using (Graphics g = Graphics.FromImage(screenshot))
{
    try
    {
        SendMessage(this.panel1.Handle, WM_PRINT, g.GetHdc().ToInt32(), (int)(DrawingOptions.PRF_CHILDREN | DrawingOptions.PRF_CLIENT | DrawingOptions.PRF_NONCLIENT | DrawingOptions.PRF_OWNED));
    }
    finally
    {
        g.ReleaseHdc();
    }
    screenshot.Save("temp.bmp");
}

EDIT: Here's an alternate paint strategy that might get you what you're looking for. I'm making some assumptions, but perhaps it will work. It paints a dummy background on the Bitmap first, and also removes the scrollbars:

using (Bitmap screenshot = new Bitmap(this.panel1.DisplayRectangle.Width, this.panel1.DisplayRectangle.Height))
using (Graphics g = Graphics.FromImage(screenshot))
{
    g.FillRectangle(SystemBrushes.Control, 0, 0, screenshot.Width, screenshot.Height);
    try
    {
        SendMessage(this.panel1.Handle, WM_PRINT, g.GetHdc().ToInt32(), (int)(DrawingOptions.PRF_CHILDREN | DrawingOptions.PRF_CLIENT | DrawingOptions.PRF_OWNED));
    }
    finally
    {
        g.ReleaseHdc();
    }
    screenshot.Save("temp.bmp");
}
Dave
A: 

I'd create a bitmap with the correct size (and clear it with the right color or paint the panels' background image to it) and then loop over all child controls and .DrawToImage each one of them to the correct place.

danbystrom
+1  A: 

No happy answers here, DrawToBitmap can only draw what would be visible to the user. Tricks like changing the Location and Size of the panel beforehand usually quickly run out of gas due to the restriction on the control size imposed by the parent. The form itself can never get larger than the screen, now you'll also depend on the resolution of the video adapter on the target machine.

One ugly hack is to run DrawToBitmap multiple times, changing the Panel's AutoScrollPosition property between each call. You'd have to stitch the resulting images together. Paying special attention to the last one of course since it won't be as large as the other ones.

Once you start considering code like this, you really ought to think about PrintDocument or a report generator instead. One benefit to that is that the printout will look a heckofalot cleaner. Printed screen-shots are invariably ugly due to the huge difference in video and printer resolution.

Hans Passant
Thanks!! That seems the only way at the moment!! A bit of work though!! Thanks again!!
Shri
Hey guys Just an update on this....A work around was to create the same control in memory as well and define custom height and width and then call the DrawToBitmap function!!Was a sweet success!! Hope this helps others!!
Shri
+1 for PrintDocument
hometoast
A: 

you need to make your panel AutoZize=True and AutoScroll=False, than put it into another container and make the container AutoScroll=true.

Bolu
A: 

Hi Shri,

Can you please share the code for this issue which you asked.

I am stucked in the same situation

The code I use is something like Panel.DrawToImage. Could there be any help out here to save the entire Panel as a picture and not just the visible portion?

Please help me urgent

Regards VRaj

VRaj