简体   繁体   English

打印文档添加空白页

[英]printdocument adds blank page

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我正在尝试使用 printdocument 从数据库打印数据,我把它打印到了它从指定范围打印数据的地方,但仍然有两件事出错

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 + " "; }
}

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.让我们看一些: 有currentY ,这很不错。 And there are itemperpage , totalnumber and amount , all of which are terrible!还有itemperpagetotalnumberamount ,这些都太可怕了! 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.默认的GraphicsUnitDisplay ,用于打印的大小为 1/100 英寸。 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() .您应该研究的另一件事是String.Format()string.PadLeft() They are so much nicer than the loop you have in the tostring() method!它们比您在tostring()方法中的循环要好得多!

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.另一个问题是您设置 DB 读取的方式:您需要在开始打印的位置而不是在PrintPage循环中设置阅读器。 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.注意:这实际上是两个循环:一个是可见的while (...reader.Read() ) ,另一个是隐含的外部循环:整个PrintPage事件本身就是循环体。

First let's look at the range() code.首先让我们看一下range()代码。 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.然后我设置DataReader以进行真正的阅读,这将在PrintPage事件中发生:我枚举字段,这样我就可以控制它们的顺序,并且不会引入我不需要的东西。

Note that I am using MySql but the classes are pretty much the same, just with a MySQl -prefix.请注意,我使用的是MySql但类几乎相同,只是带有MySQl前缀。 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!请注意, Reader是在range调用中创建的!

Finally the PrintPage event:最后是PrintPage事件:

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);
    }
}

Had this issue too.也有这个问题。 In my situation the reason was a line e.HasMorePages = true;在我的情况下,原因是一行e.HasMorePages = true; ( e is PrintPageEventArgs ) in event handler void PrintDoc_PrintPage(object sender, PrintPageEventArgs e) . ( e 是 PrintPageEventArgs )在事件处理程序void PrintDoc_PrintPage(object sender, PrintPageEventArgs e) Every time you declare e.HasMorePages = true;每次你声明e.HasMorePages = true; a new page is prepared for printing.准备打印新页。 So, my correct code was:所以,我的正确代码是:

private void PrintDoc_PrintPage(object sender, PrintPageEventArgs e)
        {
            if (currentPagePrinting <= maxPagePrinting)  {
                //...
                // do some drawing on e.Graphics as you like
                //...
                currentPagePrinting++;
                e.HasMorePages = (currentPagePrinting <= maxPagePrinting);
            } else
            {
                e.HasMorePages = false;
                // also set this value to 1 in PrintDoc_BeginPrint event handler (declare it)
                currentPagePrinting = 1;
            }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM