printdocument adds blank page

maam27

I'm trying to print data from a database using printdocument and i got it to where it prints the data from the specified range but there are still 2 things that go wrong

the things that still don't work like intended are

  • on printing if a page is almost fully used it adds a blank page with only a header printed on it
  • and if a page is full the next page starts with the first item of the range again (FIXED by using multiple lists because i couldnt figure out how to make a list with sublists)

this is the code i have to call the printdocument

private void button3_Click(object sender, EventArgs e)//print
{
    range();
    try
    {
        if (artikel == true)
        {
            itemperpage = totalnumber = 0;
            printPreviewDialog1.Document = printDocument1;
            print = true;
            printDocument1.Print();
            // this.Close();
        }
    }
    catch (Exception q) { MessageBox.Show("" + q); }
}

this is the code of the printdocument

private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
    if (artikel == true)
    {
        Font messageFont = new Font("Arial", 14, System.Drawing.GraphicsUnit.Point);

        float currentY = 10;// declare  one variable for height measurement 
        e.Graphics.DrawString("                                                                                                                  I N K O O P A R T I K E L E N ", DefaultFont, Brushes.Black, 10, currentY);//this will print one heading/title in every page of the document 
        currentY += 15;

        SqlCommand artprint = new SqlCommand("select * from ART WHERE ART BETWEEN @range AND @range2 ORDER BY ART ASC", Connectie.connMEVO_ART);
        if (comboBox1.SelectedIndex <= comboBox2.SelectedIndex)
        {
            artprint.Parameters.Add("@range", SqlDbType.VarChar).Value = comboBox1.SelectedItem;
            artprint.Parameters.Add("@range2", SqlDbType.VarChar).Value = comboBox2.SelectedItem;
        }
        else if (comboBox2.SelectedIndex <= comboBox1.SelectedIndex)
        {
            artprint.Parameters.Add("@range", SqlDbType.VarChar).Value = comboBox2.SelectedItem;
            artprint.Parameters.Add("@range2", SqlDbType.VarChar).Value = comboBox1.SelectedItem;
        }
        drART = artprint.ExecuteReader();
        try
        {
            while (totalnumber <= amount - 1 && drART.Read())
            {// check the number of items 
                tostring();//SQL data to string
                row = row + Environment.NewLine + "ART            LEV         LTD       MVRD   SGR        INK        CRNI    " + " VALUTA    KOR ";
                row = row + Environment.NewLine + aa + "  " + a + "  " + b + "  " + c + "  " + d + "  " + m + "  " + f + "   " + g + "          " + h;
                row = row + Environment.NewLine + "EH2     EH1      EF            OMS     ";
                row = row + Environment.NewLine + j + "         " + k + "         " + l + "  " + i;
                row = row + Environment.NewLine;
                e.Graphics.DrawString(row, DefaultFont, Brushes.Black, 50, currentY);//print each item
                Debug.WriteLine("" + row);
                row = "";
                currentY += 80; // set a gap between every item
                totalnumber += 1; //increment count by 1
                if (itemperpage <= 12) 
                {
                    itemperpage += 1; // increment itemperpage by 1
                    e.HasMorePages = false; // set the HasMorePages property to false , so that no other page will not be added 
                }
                else // if the number of item(per page) is more than 12 then add one page 
                {
                    itemperpage = 0; //initiate itemperpage to 0 .  
                    e.HasMorePages = true; //e.HasMorePages raised the PrintPage event once per page .           
                    return;//It will call PrintPage event again   
                }
            }
        }
        catch (Exception ef)
        {
            MessageBox.Show("" + ef);
        }
        artprint.Dispose();
    }
}

private void tostring()
{
    aa = drART["ART"].ToString();
    for (int ss = aa.Length; ss < 8; ss++) { aa = aa + " "; }
    a = drART["LEV"].ToString();
    for (int ss = a.Length; ss < 10; ss++) { a = a + " "; }
    b = drART["LTD"].ToString();
    for (int ss = b.Length; ss < 10; ss++) { b = b + " "; }
    c = drART["MVRD"].ToString();
    for (int ss = c.Length; ss < 10; ss++) { c = c + " "; }
    d = drART["SGR"].ToString();
    for (int ss = d.Length; ss < 10; ss++) { d = d + " "; }
    m = drART["INK"].ToString();
    for (int ss = m.Length; ss < 10; ss++) { m = m + " "; }
    f = drART["CRNI"].ToString();
    for (int ss = f.Length; ss < 10; ss++) { f = f + " "; }
    g = drART["VALUTA"].ToString();
    for (int ss = g.Length; ss < 3; ss++) { g = g + " "; }
    h = drART["KOR"].ToString();
    for (int ss = h.Length; ss < 10; ss++) { h = h + " "; }
    i = drART["OMS"].ToString();
    j = drART["EH2"].ToString();
    for (int ss = j.Length; ss < 3; ss++) { j = j + " "; }
    k = drART["EH1"].ToString();
    for (int ss = k.Length; ss < 3; ss++) { k = k + " "; }
    l = drART["EF"].ToString();
    for (int ss = l.Length; ss < 10; ss++) { l = l + " "; }
}
TaW

You wrote that you have used sources from the web and I guess it shows. We all do that but it is really important to be rather suspicious about their quality. And of course combining two sources most likely will not work at all..

I'll first go over a couple of issues with your code and then show you an example of how to print items from a DB on several pages..

Please do yourself a favor and chose the names of your variables with care! Yes, that takes a little longer but it will pay, believe me. (And if you can't come up with anything convincing, step back! This is usually an indication that you don't understand the problem well enough..)

Let's look at some: There is currentY, which is pretty good. And there are itemperpage, totalnumber and amount, all of which are terrible! They either are totally unclear or even misleading!

Let's set up a few ones with better names:

// layout variables
int itemsPerPage = 40;  // how many items fit on one page
int itemHeight = 25;    // height of one item in the chosen unit

// print job variables
int totalNumber = -1;   // total number of records/items coming from the dbms
int itemsToPrint = 75;  // total number of items we want to print

// print progress variables
int itemsPrinted = 0;   // number of items printed so far
int pagesPrinted = 0;   // number of pages printed

Another issue is the unit you chose, or to be precise the lack of choosing one. The default GraphicsUnit is Display which for printing amounts to 1/100 inch. If you like that I suggest to write it in code to document it. This unit will be used during the whole layout process so it should be visible in the code! I personally prefer Millimeters. There are several other units..pick yours but document it!

One more thing you should look into are String.Format() and string.PadLeft(). They are so much nicer than the loop you have in the tostring() method!

Now let's look at your specific problems:

The one with an empty page at the end of the job will go away once we use enough variables with names one can actually understand without learning them..

The other problem is the way you set up the DB-reading: You need to set up the reader where you start the printing and not in the PrintPage loop. Note: These actually are two loops: one is visible as the while (...reader.Read() ) and the other, outer loop is implict: The whole PrintPage event itself is the loop body.

First let's look at the range() code. I have turned it into a function that returns the maximum number of records. I fetch the count in a first step. Then I set up the DataReader for the real reading, which will happen in the PrintPage event: I enumerate the fields so I have control over their order and don't pull in stuff I don't need.

Note that I am using MySql but the classes are pretty much the same, just with a MySQl-prefix. I don't include the connect code here. And of course I read from a database of my own..

MySqlConnection DBC = new MySqlConnection("");
MySqlCommand CMD = null;
MySqlDataReader DR = null;

int range ()
{
    CMD = new MySqlCommand("select count(0) from test.artists ", DBC);
    var count = CMD.ExecuteScalar();
    int counter = Convert.ToInt32(count);
    CMD = new MySqlCommand("select artist_ID, artist, genres from test.artists ", DBC);
    DR = CMD.ExecuteReader();
    return (int)counter;
}

Now let's look at the print command, using the variables from above:

private void cb_print_Click(object sender, EventArgs e)
{
    totalNumber = range();
    try
    {
        if (DBC.State == ConnectionState.Open)
        {
            pagesPrinted = 0;
            printPreviewDlg.Document = printDocument1;
            printPreviewDlg.ShowDialog();
        }
    } catch (Exception q) { MessageBox.Show("" + q); }
    DR.Dispose();
}

Note that the Reader is created in the range call!

Finally the PrintPage event:

private void printDocument1_PrintPage(object sender, 
                            System.Drawing.Printing.PrintPageEventArgs e)
{
    // my page unit
    e.Graphics.PageUnit = GraphicsUnit.Millimeter;

    // starting a new page
    int itemsOnPage = 0;
    pagesPrinted++;

    float currentY = 12;
    e.Graphics.DrawString(String.Format(
               "HEADER -  printing {0} items of {1}    - Page {2}",
               itemsToPrint, totalNumber, pagesPrinted), 
               Font, Brushes.Black, 1, currentY);  

    currentY += 30;  // header height

    try
    {
        // page is not full and we want to print more items
        while (itemsOnPage < itemsPerPage && itemsPrinted < itemsToPrint - 1
               && DR.Read())
        {
            string row = String.Format("{0,5:000} Artist: {1,20}  ({2})   ",
                                         DR[0], DR[1], DR[2]);

            e.Graphics.DrawString(row, DefaultFont, Brushes.Black, 50, currentY);  
            // Console.WriteLine("" + row);

            currentY += itemHeight; 
            itemsPrinted++; 
            itemsOnPage++;

            // we want to print more items but now the page is full
            if ( itemsPrinted < itemsToPrint && itemsOnPage >= itemsPerPage)
            {
                itemsOnPage = 0;        
                e.HasMorePages = true;         
                return;                 
            }
            else 
            {
                // this will only be used after all data are printed
                e.HasMorePages = false; 
            }
        }
    } catch (Exception ef)
    {
        MessageBox.Show("" + ef);
    }
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related