Datagridview问题与打印备用行

时间:2017-05-12 12:22:37

标签: c# datagridview

大家好,我试图以这种方式从datagridview打印数据,交替的行应该左右打印。我能够打印,但他们没有排队。这是我试图打印的代码。

您可以在此处找到完整的代码

https://drive.google.com/open?id=0ByVjmdncQgagRjZvME9STWJoVHc

using (Font font = new Font("Consolas", 13f))
{
    float x = 0;
    float y = 0;
    for (int row = linesPrinted; row < DGV.Rows.Count; row++)
    {
       for (int col = 0; col < DGV.ColumnCount; col++)
       {
          x = 0;
          string text = DGV[col, row].FormattedValue.ToString();
          if (row % 2 == 0)
          {
              x += 10;
              y += 5;
              e.Graphics.DrawString(text, font, Brushes.Black, new PointF(x, y));
          }
          else
          {
               x += 45;
               y += 5;
               e.Graphics.DrawString(text, font, Brushes.Black, new PointF(x, y));
          }
      }
}

我得到的输出如下

If you see the right hand side data it在country1之后打印,我需要的是它应该与顶部对齐

1 个答案:

答案 0 :(得分:2)

由于您似乎在尝试在同一行上打印两个不同的行,因此您将必须跟踪列1的“Y”值开始的位置,这将有助于排列第2列。另一个问题是当有多个页面要打印时,当前代码只打印一页。

当循环DataGridView打印行时,我们到达页面末尾,我们需要再次调用PrintPage方法。在当前形式中,PrintPage方法将从DataGridView的第一行(0)开始打印,并且它将为每个新页面执行此操作。随之而来的是无限循环,因为每个新页面都会从第一行开始。全局int变量dgvRowIndex应该修复此问题,以便每次打印下一页时我们都不会从头开始。

我很难打印多个页面,但@LarsTech解决方案在Print multiple datagridview pages

处理得很好

为了提供帮助,下面是一种简单打印数据网格视图的一行的方法。该方法需要rowIndex来确定DataGridView中要使用的行,printX值以指示起始左侧打印值,printY值来指示垂直位置要开始打印此行,lineIncrement用作文本的“前导”值,最后用PrintPageEventArgs变量e来绘制文本。

private void printRow(int rowIndex, float printX, float printY, float lineIncrement, PrintPageEventArgs e) {
  for (int col = 0; col < dataGridView1.ColumnCount; col++) {
    string text = dataGridView1[col, rowIndex].FormattedValue.ToString();
    e.Graphics.DrawString(text, font, Brushes.Black, new PointF(printX, printY));
    printY += lineIncrement;
  }
}

既然我们有一个方法可以将DatagridView中的单行打印到打印文档中的一列中,那么将列打印为行并将行排成一行应该会更容易。首先如前所述,我们需要一个全局变量来跟踪DataGridView行索引,同时循环遍历它。每次调用dgvRowIndex方法时都会使用此全局变量PrintPage。我还将字体变量添加为全局变量。

// global variables 
int dgvRowIndex = 0;
Font font = new Font("Consolas", 13f);

以下是打印每页的PrintPage方法。大多数变量的名称都是不言自明的。 pageHeight用于确定何时需要新页面。两列LeftColXRightColX是每列的两个水平(X)起点。 curY跟踪打印页面上的垂直(Y)位置,用于将其值与pageHeight进行比较,并在需要时启动新页面。 lineIncrement用作每个新行的“前导”值。 spaceBefore用于在两个打印行之间添加额外的垂直空间。最后,如前所述,我们需要在打印新的“第1列”时跟踪垂直“Y”值。 column2YValue用于此目的,并在打印第二列时作为起始“Y”值发送到PrintRow方法。

当while循环开始循环遍历DataGridView的行时,会检查此行是否在第1列或第2列。如果dgvRowIndex在第1列,那么我们需要保存此起始“Y”column2YValue以在打印第二列时使用。如果dgvRowIndex位于第2列,那么我们只需再次调用printRow方法,但这次我们会从上一列column2YValue中传递起始“Y”值。添加了额外的垂直空间,dgvRowIndex递增以转到下一行,然后检查是否需要添加另一个页面。这里进行简单检查以查看当前“Y”值curY是否超过保证金,如果是,则我们需要指示需要新页面然后返回。 return只是简单地启动PrintPage方法,这应该按预期工作,因为我们现在有一个全局变量dgvRowIndex,以避免从DataGridView的开头开始。希望这会有所帮助。

private void printDocument1_PrintPage(object sender, PrintPageEventArgs e) {
  float pageHeight = e.MarginBounds.Height;
  float leftColX = 10;
  float rightColX = 145;
  float curY = 10;
  float lineIncrement = 16;
  float spaceBefore = 24;
  float column2YValue = curY;
  while (dgvRowIndex < dataGridView1.Rows.Count) {
    if (dgvRowIndex % 2 == 0) {
      column2YValue = curY;
      printRow(dgvRowIndex, leftColX, curY, lineIncrement, e);
    } else {
      printRow(dgvRowIndex, rightColX, column2YValue, lineIncrement, e);
      curY += spaceBefore;
    }
    dgvRowIndex++;
    if (curY > pageHeight) {
      e.HasMorePages = true;
      return;
    }
    curY += spaceBefore;
  }
}

编辑以处理多个列和多行。

正如我评论的那样,为了打印多列,代码需要跟踪页面上的打印“X”值。我们的想法是在相同(打印)行(y值)上保持打印,直到“X”值超过右边距。

另一个更改解决了从哪里开始下一个打印组/网格行的问题。当代码调用printRow时,在调用之前不知道网格行可能有多少列。如果网格有三列,四列或十列,则代码将打印该行数。如果每个网格行中有10列...网格中的每一行将有10个“打印”行。由于printRow将循环遍历要打印的列,因此它用于返回此“下一个”“Y”打印行值。

跟踪下面的代码,遍历网格行,首先打印当前行,然后根据网格中的列数设置下一个“打印”行nextRowYStart

下一个if语句会检查页面右侧是否有足够的空间来打印另一列。如果页面上有足够的空间用于其他列,则curX只会移动到下一列。如果空间不足,则“X”值curX将重置为最左侧(起始)列,curY将设置为nextRowYstart以向下移动到下一个打印行,并添加了一些垂直空间。然后进行检查以查看新的打印行“Y”值curY是否超过下边距。如果是,那么我们开始一个新的页面。否则,只需打印网格的下一行。

代码假定您要打印所有列,但是如果您只想打印前X列,则会添加stopColumn变量,以便您可以决定要打印的第一列中有多少列。我猜这可能是你在找什么。希望它有所帮助。

private void printDocument1_PrintPage(object sender, PrintPageEventArgs e) {
  //int stopColumn = 3;
  int stopColumn = dataGridView1.Columns.Count;
  float pageHeight = e.MarginBounds.Height;
  float pageWidth = e.MarginBounds.Width;
  float startX = 50;
  float startY = 50;
  float columnWidth = 150;
  float curX = startX;
  float curY = startY;
  float lineIncrement = 16;
  float spaceBefore = 24;
  float nextRowYStart = curY;
  while (dgvRowIndex < dataGridView1.Rows.Count) {
    nextRowYStart = printRow(dgvRowIndex, curX, curY, lineIncrement, stopColumn, e);
    if (curX + columnWidth > pageWidth) {
      // start a new PRINT group/row
      curX = startX;    
      curY = nextRowYStart;
      curY += spaceBefore;
      if (curY > pageHeight + spaceBefore) {
        dgvRowIndex++;
        e.HasMorePages = true;
        return;
      }
    } else {
      curX += columnWidth;
    }
    dgvRowIndex++;
  }
}

更新了printRow方法

private float printRow(int rowIndex, float printX, float printY, float lineIncrement, int stopCol, PrintPageEventArgs e) {
  for (int col = 0; col < dataGridView1.ColumnCount; col++) {
    if (col < stopCol) {
      string text = dataGridView1[col, rowIndex].FormattedValue.ToString();
      e.Graphics.DrawString(text, font, Brushes.Black, new PointF(printX, printY));
      printY += lineIncrement;
    }
    else {
      break;
    }
  }
  return printY;
}