简体   繁体   English

如何调整e.Graphics将在其中绘制的区域(视口)?

[英]How can I adjust the area into which e.Graphics will be drawing (viewport)?

I am using PrintDocument.Print() to start a print process, in which I print a data grid (C1FlexGrid) and some header and footer information. 我正在使用PrintDocument.Print()启动打印过程,在其中打印数据网格(C1FlexGrid)以及一些页眉和页脚信息。 It's a somewhat complicated printing process. 这是一个有点复杂的打印过程。 I'm using standard PrintDocument methods but because of what I want to have hit the page, I'm in control of everything that is happening. 我正在使用标准的PrintDocument方法,但是由于要在页面上显示内容,因此我可以控制所有发生的事情。

The problem I am having is that I want to shrink the area into which the grid control will be drawn. 我遇到的问题是我想缩小将绘制网格控件的区域。 When I draw my headers and footers, I am calculating the space that they will consume, and what should remain for the grid to occupy. 当我绘制页眉和页脚时,我正在计算它们将消耗的空间,以及网格要占用的空间。 The grid control has its own PrintDocumentGridRenderer class that provides the PrintPage() method that I call to get it to render the grid on the PrintDocument's Graphics object. 网格控件具有自己的PrintDocumentGridRenderer类,该类提供PrintPage()方法,我调用该方法来获取它以在PrintDocument的Graphics对象上呈现网格。

I cannot figure out how I can restrict the area into which the grid can fit, but do it after I've already drawn the header/footer and know what that remaining space is. 我无法弄清楚如何限制网格可以容纳的区域,但是绘制了页眉/页脚并知道剩余空间后再进行操作。

Here's some code, heavily stripped to what I think is the essence: 这是一些代码,我认为这是本质:

private void PrintDocument_PrintPage(Object sender, PrintPageEventArgs e)
{
    //I tried putting a non-drawing version of DrawHeadersAndFooters() here to get the calculated space and then reset the Margin...but it's always one call behind the Graphics object, meaning that it has no effect on the first page.  In fact, because Setup() gets called with two different margins at that point, the pages end up very badly drawn.

    _gridRenderer.Setup(e);  //this is the PrintDocumentGridRender object and Setup() figures out page layout (breaks and such)

    DrawHeadersAndFooters(e.Graphics, e.MarginBounds);
    Int32 newX = _printProperties.GridBounds.X - e.MarginBounds.X;
    Int32 newY = _printProperties.GridBounds.Y - e.MarginBounds.Y;
    e.Graphics.TranslateTransform(newX, newY);
    _gridRenderer.PrintPage(e, _currentPage - 1);  //grid control's print method
    e.HasMorePages = _currentPage < _printProperties.Document.PrinterSettings.ToPage;
    _currentPage++;
}

private void DrawHeadersAndFooters(Graphics graphics, Rectangle marginBounds)
{
    Rectangle textRect = new Rectangle();
    Int32 height = 0;
    //loop lines in header paragraph to get total height required
    //there are actually three, across the page, but just one example for bevity...
    if (!String.IsNullOrEmpty(_printProperties.HeaderLeft))
    {
        Int32 h = 0;
        foreach (String s in _printProperties.HeaderLeft.Split(new String[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
            h += (Int32)graphics.MeasureString(s, _printProperties.HeaderLeftFont, width, stringFormat).Height;
        height = (h > height) ? h : height;
    } //repeat for other two, keeping the greatest of 3 heights in the end
    textRect.X = marginBounds.X;
    textRect.Y = (Int32)_printProperties.Document.DefaultPageSettings.PrintableArea.Y;  //a global storage for printing information I need to keep in memory
    textRect.Width = width;
    textRect.Height = height;

    stringFormat.Alignment = StringAlignment.Near;
    graphics.DrawString(_printProperties.HeaderLeft, _printProperties.HeaderLeftFont, new SolidBrush(_printProperties.HeaderLeftForeColor), textRect, stringFormat);

    _printProperties.GridBounds = new Rectangle(marginBounds.X, textRect.Y, marginBounds.Width, marginBounds.Bottom - textRect.Y);  //here I think I have the space into which the grid _should_ be made to fit
}

You can see that in PrintDocument_PrintPage() I am applying a transform to the Graphics object, which scoots the grid down into place, and under the headers. 您可以看到在PrintDocument_PrintPage()我正在对Graphics对象应用转换,该转换将网格向下滑动到适当位置,并且位于标题下方。

Screenshot: 截图:

在此处输入图片说明

So, the question: 因此,问题是:

I would like to shrink the area bottom-up to get the bottom of that grid to be just above the footers. 我想自下而上缩小区域,以使该网格的底部位于页脚上方。 You can see by looking at the bottom-right corner that the rendered grid image is overlapping the footers that I've already drawn. 通过查看右下角,可以看到渲染的网格图像与我已经绘制的页脚重叠。 And that's the help I need. 这就是我需要的帮助。 How can I shrink the Graphics drawing space without doing something like ScaleTransform() , which doesn't seem the right idea at all. 我如何不做ScaleTransform()类的事情而缩小Graphics绘图空间,这似乎根本不是个正确的主意。

The answer proved to be a complete reorganization of the logic. 答案被证明是对逻辑的完全重组。 Instead of trying to figure it all out and render it at the same time, I refactored the calculation code into a separate method that I can call ahead of the call to PrintDocument.Print() . 我没有尝试全部弄清楚并同时渲染它,而是将计算代码重构为一个单独的方法,可以在调用PrintDocument.Print()之前调用PrintDocument.Print()

It all came down to this little gem that I was previously unaware of: 一切都归结为我以前没有意识到的这个小宝石:

Graphics graphics = _printProperties.Document.PrinterSettings.CreateMeasurementGraphics();

That gave me a fresh Graphics object for the print document that I could use to do all the calculations ahead of printing. 这为打印文档提供了一个新的Graphics对象,可用于在打印之前进行所有计算。 Once I had that, it was a simple matter of storing it and then using the results in the actual header and footer rendering. 一旦有了这些,就可以简单地存储它,然后在实际的页眉和页脚渲染中使用结果。

It also afforded me the information I needed in order to adjust the Margins of the PrintDocument.DefaultPageSettings prior to the grid's Print() call. 它还为我提供了在网格的Print()调用之前调整PrintDocument.DefaultPageSettingsMargins所需的信息。

Some code for reference: 一些代码供参考:

//The margins I intend to adjust
System.Drawing.Printing.Margins margins = _printProperties.Document.DefaultPageSettings.Margins;

//Get paper width/height respecting orientation
Int32 paperWidth = 
    _printProperties.Document.DefaultPageSettings.Landscape ? 
    _printProperties.Document.DefaultPageSettings.PaperSize.Height : 
    _printProperties.Document.DefaultPageSettings.PaperSize.Width;
Int32 paperHeight = 
    _printProperties.Document.DefaultPageSettings.Landscape ? 
    _printProperties.Document.DefaultPageSettings.PaperSize.Width : 
    _printProperties.Document.DefaultPageSettings.PaperSize.Height;

//Calculate printable bounds using user-defined margins and paper size
Rectangle marginBounds = new Rectangle(_printProperties.MarginLeft, _printProperties.MarginTop,
    paperWidth - (_printProperties.MarginLeft + _printProperties.MarginRight),
    paperHeight - (_printProperties.MarginTop + _printProperties.MarginBottom));

//Calculate Rectangles for every header/footer element
CalculatePrintRegions(marginBounds);

//If certain elements exist, use the calculated sizes to adjust the margins
Boolean hasHeader =
    !String.IsNullOrEmpty(_printProperties.HeaderLeft) ||
    !String.IsNullOrEmpty(_printProperties.HeaderCenter) ||
    !String.IsNullOrEmpty(_printProperties.HeaderRight);
Boolean hasHeader2 = 
    !String.IsNullOrEmpty(_printProperties.Header2Range) || 
    !String.IsNullOrEmpty(_printProperties.Header2Date);
Boolean hasFooter =
    !String.IsNullOrEmpty(_printProperties.FooterLeft) ||
    !String.IsNullOrEmpty(_printProperties.FooterCenter) ||
    !String.IsNullOrEmpty(_printProperties.FooterRight);
if (hasHeader)
{
    Int32 topAdd = Math.Max(Math.Max(_printProperties.HeaderLeftRect.Height, _printProperties.HeaderCenterRect.Height), _printProperties.HeaderRightRect.Height);
    if (hasHeader2)
        topAdd += Math.Max(_printProperties.Header2RangeRect.Height, _printProperties.Header2DateRect.Height);
    margins.Top = _printProperties.HeaderLeftRect.Top + topAdd + 10;
}
if (hasFooter)
    margins.Bottom = paperHeight - (_printProperties.FooterLeftRect.Top - 10);

//This used to be the starting point, everything above was added in answer to the problem
_printProperties.IsPrinting = true;  //used by drawing code to control drawing of certain elements (such as not showing selection/highlight)
_printProperties.IsPreview = Preview;
_printProperties.IsDryRun = true;  //to get page count into _gridRenderer before displaying prompt
_printProperties.Document.Print();

Note that since I am drawing all header/footer text manually, margins have no impact on it, so adjusting them only influences the grid rendering. 请注意,由于我是手动绘制所有页眉/页脚文本,因此页边距对此没有任何影响,因此调整它们只会影响网格渲染。

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

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