Re: Saving a panel to a Graphics (Printing) by she_prog
she_prog
Sun Jun 10 16:48:27 CDT 2007
You're great, Ben, thank you very much! I did play with flags and all,
but here I'm displaying the code that's working for me for every case
- it might help someone sometime in the future :)
[DllImport("user32.dll")]
public static extern int SendMessage(
IntPtr hWnd, // handle to destination window
int Msg, // message
int wParam, // first message parameter
int lParam // second message parameter
);
const int WM_PRINT =3D 0x317;
[Flags]
enum DrawingOptions
{
PRF_CHECKVISIBLE =3D 0x01,
PRF_NONCLIENT =3D 0x02,
PRF_CLIENT =3D 0x04,
PRF_ERASEBKGND =3D 0x08,
PRF_CHILDREN =3D 0x10,
PRF_OWNED =3D 0x20
}
private void command_Click(object sender, EventArgs e)
{
// get filename
c_panel.AutoScrollPosition =3D new Point(0, 0);
Bitmap l_bmpPanel =3D new
Bitmap(c_panel.DisplayRectangle.Width,
c_panel.DisplayRectangle.Height);
Graphics l_grpSrc =3D Graphics.FromImage(l_bmpPanel);
c_panel.ForcePaint(new PaintEventArgs(l_grpSrc,
c_panel.DisplayRectangle));
SendMessage(c_panel.Handle, WM_PRINT,
(int)l_grpSrc.GetHdc(), (int)(DrawingOptions.PRF_OWNED |
DrawingOptions.PRF_CHILDREN | DrawingOptions.PRF_CLIENT |
DrawingOptions.PRF_NONCLIENT));
l_grpSrc.ReleaseHdc();
l_bmpPanel.Save(filename);
}
I had to set AutoScrollPosition to (0,0), but I don't think it's
against the user-friendliness of the application.
ForcePaint is simple:
public void ForcePaint(PaintEventArgs pe)
{
OnPaint(pe);
}
It's only needed because I have some custom painting in this OnPaint
and that was only drawn in the visible area of the panel, I don't
really know why. All children have custom painting as well, and those
drawings are done both on visible and invisible area. Although I don't
think it's elegant programming, I couldn't think of any other
solution.
So thank you again for the help, Ben!
Regards, Chris
Ben Voigt [C++ MVP] =EDrta:
> Did you Dispose the Graphics object before trying to use the Bitmap?
>
> "she_prog" <puffy_chris@yahoo.com> wrote in message
> news:1181425407.830351.320850@k79g2000hse.googlegroups.com...
> Great, now I can see stepping through OnPaint when debugging. Still,
> the resulted Bitmap is all blank :(
> Right after SendMessage I'm calling l_bmp.Save(filename); so there's
> no code overdrawing the result of SendMessage. The same OnPaint draws
> the panel and its children just fine onto the screen.
> Right now I'm just testing without scrollbars, so that shouldn't cause
> the problem. I might try to do a small sample application to try to
> narrow down the cause.
>
> Thank you very much for the help! If you could think of anything that
> could cause the problem, please let me know!
> Regards,
> Chris
>
> Ben Voigt [C++ MVP] =EDrta:
> > You should also use the CLIENT and CHILDREN flags (OR-ed together), to =
get
> > the content of the window and all contained windows.
> >
> >
> > "she_prog" <puffy_chris@yahoo.com> wrote in message
> > news:1181418208.451963.154800@c77g2000hse.googlegroups.com...
> > Thank you very much, Ben!
> > I tried your solution, but it didn't work for me. Maybe the problem is
> > that I'm trying to save a class of my own, derived from Panel and
> > OnPaint method is overriden in this new class. When trying to debug,
> > OnPaint is not called as a result of SendMessage. Here's my code:
> >
> > [DllImport("user32.dll")]
> > public static extern int SendMessage(
> > IntPtr hWnd, // handle to destination window
> > int Msg, // message
> > int wParam, // first message parameter
> > int lParam // second message parameter
> > );
> >
> > const int WM_PRINT =3D 0x317;
> >
> > [Flags]
> > enum DrawingOptions
> > {
> > PRF_CHECKVISIBLE =3D 0x01,
> > PRF_NONCLIENT =3D 0x02,
> > PRF_CLIENT =3D 0x04,
> > PRF_ERASEBKGND =3D 0x08,
> > PRF_CHILDREN =3D 0x10,
> > PRF_OWNED =3D 0x20
> > }
> >
> > ...
> > Bitmap l_bmp =3D new Bitmap(c_panel.Width, c_panel.Height);
> > Graphics l_grp =3D Graphics.FromImage(l_bmp);
> > IntPtr hdc =3D l_grp.GetHdc();
> > SendMessage(c_panel.Handle, WM_PRINT, (int)hdc,
> > (int)DrawingOptions.PRF_OWNED);
> >
> > Could you please advice further?
> > Regards,
> > Chris
> >
> > Ben Voigt [C++ MVP] =EDrta:
> > > "she_prog" <puffy_chris@yahoo.com> wrote in message
> > > news:1181411906.558071.296830@m36g2000hse.googlegroups.com...
> > > > Dear All,
> > > >
> > > > I need to save the content of a panel to a bitmap. The panel can ha=
ve
> > > > many child controls which also need to be saved. The problem would =
be
> > > > solved if I could have the panel saved to a Graphics object, which =
is
> > > > the same as if I'd need to print it. It'd be easy using
> > > > Control.DrawToBitmap, but I also need the invisible part of the pan=
el
> > > > (which is hidden because of scrolling) and DrawToBitmap just takes a
> > > > screenshot.
> > > >
> > > > I've been reading about this. Many samples uses BitBlt, but that al=
so
> > > > skips the invisible part. I've also seen some posts stating that th=
is
> > > > is not a simple thing and I'd need to programatically scroll to all
> > > > needed position and combine the screenshots taken from all the scro=
ll-
> > > > positions. These posts were from 2003 or 2004.
> > > >
> > > > So my question: Is there any new solutions provided by VS2005? Or d=
o I
> > > No, there aren't. However, Windows has always had a solution for thi=
s:
> > > WM_PRINT.
> > >
> > > Try creating a bitmap of the appropriate size, getting a Graphics for
> > > it,
> > > get the HDC, and SendMessage WM_PRINT to the window and each of its
> > > children. That will usually get you the results you are looking for.
> > >
> > > > have to do this multiple scrolling (which produces flickering)?
> > > >
> > > > Thank you for any help!
> > > >
> > > > Chris
> > > >