Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
338 views
in Technique[技术] by (71.8m points)

c# - Winforms - how to print the whole of a form, including unseen parts?

I have a windows forms project written in C#. The main form has a TabControl on it and there is a requirement for one of the users to be able to print one of the TabPages. The form is very long and I use a vertical scroll bar. The whole of the form needs to be able to be printed.

I have tried using the DrawToBitmap method to convert to a bitmap first, but this will only include the portion of the form that the user can see. Some other solutions I have tried involve screen capturing, which has the same issue.

How can I print out, or get an image, of the whole of the tab page, including the parts the user only sees when they scroll down?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is rather simple for any control including TabControls and TabPages but not Forms.

All you need to do is enlarge the relevant controls enough to show all their content. (They don't have to be actually visible on screen.)

Here is an example:

tabControl1.Height = 10080;
tabPage2.Height = 10050;
dataGridView1.Height = 10000;

dataGridView1.Rows.Add(3000);
for (int i = 0; i < dataGridView1.Rows.Count; i++)  dataGridView1[0, i].Value = i;

using (Bitmap bmp = new Bitmap(tabControl1.Width , tabControl1.Height ))
{
    tabControl1.DrawToBitmap(bmp, tabControl1.ClientRectangle);
    bmp.Save("D:\xxxx.png", ImageFormat.Png);
}

This saves the full content of the DataGridView, the TabPage and the TabControl..

Note: that this will not work with forms, which can't much exceed the screen dimensions..

Update: Here is code that saves a form with vertical scrolling by patching several bitmaps together. It can, of course be expanded to include horizontal scrolling as well. I have coded a similar solution for larger Panels here.

static void saveLargeForm(Form form, string fileName)
{
    // yes it may take a while
    form.Cursor = Cursors.WaitCursor;

    // allocate target bitmap and a buffer bitmap
    Bitmap target = new Bitmap(form.DisplayRectangle.Width, form.DisplayRectangle.Height);
    Bitmap buffer = new Bitmap(form.Width, form.Height);
    // the vertical pointer
    int y = 0;
    var vsc = form.VerticalScroll;
    vsc.Value = 0;
    form.AutoScrollPosition = new Point(0, 0);
    // the scroll amount
    int l = vsc.LargeChange;

    Rectangle srcRect = ClientBounds(form);
    Rectangle destRect = Rectangle.Empty;
    bool done = false;

    // we'll draw onto the large bitmap with G
    using (Graphics G = Graphics.FromImage(target))
    {
        while (!done)
        {
            destRect = new Rectangle(0, y, srcRect.Width, srcRect.Height);
            form.DrawToBitmap(buffer, new Rectangle(0, 0, form.Width, form.Height));
            G.DrawImage(buffer, destRect, srcRect, GraphicsUnit.Pixel);   
            int v = vsc.Value;
            vsc.Value = vsc.Value + l;
            form.AutoScrollPosition = new Point(form.AutoScrollPosition.X, vsc.Value + l);
            int delta = vsc.Value - v;
            done = delta < l;
            y += delta;
        }
        destRect = new Rectangle(0, y, srcRect.Width, srcRect.Height);
        form.DrawToBitmap(buffer, new Rectangle(0, 0, form.Width, form.Height));
        G.DrawImage(buffer, destRect, srcRect, GraphicsUnit.Pixel);
    }
    // write result to disc and clean up
    target.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
    target.Dispose();   
    buffer.Dispose();      
    GC.Collect();          // not sure why, but it helped
    form.Cursor = Cursors.Default;    
}

It makes use of a helper function to determine the the net size of the virtual client rectangle, ie excluding borders, title and scrollbar:

static Rectangle ClientBounds(Form f)
{
    Rectangle rc = f.ClientRectangle;
    Rectangle rb = f.Bounds;
    int sw = SystemInformation.VerticalScrollBarWidth;
    var vsc = f.VerticalScroll;
    int bw = (rb.Width - rc.Width - (vsc.Visible ? sw : 0) ) / 2;
    int th = (rb.Height - rc.Height) - bw * 2;
    return new Rectangle(bw, th + bw, rc.Width, rc.Height );
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...