示例#1
0
/*!
  \brief Paint the plot into a given rectangle.
  Paint the contents of a QwtPlot instance into a given rectangle.

  \param painter Painter
  \param plotRect Bounding rectangle
  \param pfilter Print filter
  \sa QwtPlotPrintFilter
*/
void QwtPlot::print(QPainter *painter, const QRect &plotRect,
        const QwtPlotPrintFilter &pfilter) const
{
    int axisId;

    if ( painter == 0 || !painter->isActive() ||
            !plotRect.isValid() || size().isNull() )
       return;

    painter->save();

    // All paint operations need to be scaled according to
    // the paint device metrics. 

    QwtPainter::setMetricsMap(this, painter->device());
    const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();

    // It is almost impossible to integrate into the Qt layout
    // framework, when using different fonts for printing
    // and screen. To avoid writing different and Qt unconform
    // layout engines we change the widget attributes, print and 
    // reset the widget attributes again. This way we produce a lot of
    // useless layout events ...

    pfilter.apply((QwtPlot *)this);

    int baseLineDists[QwtPlot::axisCnt];
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintCanvasBackground) )
    {
        // In case of no background we set the backbone of
        // the scale on the frame of the canvas.

        for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
        {
            QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
            if ( scaleWidget )
            {
                baseLineDists[axisId] = scaleWidget->baseLineDist();
                scaleWidget->setBaselineDist(0);
            }
        }
    }
    // Calculate the layout for the print.

    int layoutOptions = QwtPlotLayout::IgnoreScrollbars 
        | QwtPlotLayout::IgnoreFrames;
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintMargin) )
        layoutOptions |= QwtPlotLayout::IgnoreMargin;
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintLegend) )
        layoutOptions |= QwtPlotLayout::IgnoreLegend;

    ((QwtPlot *)this)->plotLayout()->activate(this, 
        QwtPainter::metricsMap().deviceToLayout(plotRect), 
        layoutOptions);

    if ((pfilter.options() & QwtPlotPrintFilter::PrintTitle)
        && (!titleLabel()->text().isEmpty()))
    {
        printTitle(painter, plotLayout()->titleRect());
    }

    if ( (pfilter.options() & QwtPlotPrintFilter::PrintLegend)
        && legend() && !legend()->isEmpty() )
    {
        printLegend(painter, plotLayout()->legendRect());
    }

    for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
    {
        QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
        if (scaleWidget)
        {
            int baseDist = scaleWidget->baseLineDist();

            int startDist, endDist;
            scaleWidget->getBorderDistHint(startDist, endDist);

            printScale(painter, axisId, startDist, endDist,
                baseDist, plotLayout()->scaleRect(axisId));
        }
    }

    const QRect canvasRect = metricsMap.layoutToDevice(plotLayout()->canvasRect());

    // When using QwtPainter all sizes where computed in pixel
    // coordinates and scaled by QwtPainter later. This limits
    // the precision to screen resolution. A much better solution
    // is to scale the maps and print in unlimited resolution.

    QwtArray<QwtScaleMap> map(axisCnt);
    for (axisId = 0; axisId < axisCnt; axisId++)
    {
        map[axisId].setTransformation(axisScaleEngine(axisId)->transformation());

        const QwtScaleDiv &scaleDiv = *axisScaleDiv(axisId);
        map[axisId].setScaleInterval(scaleDiv.lBound(), scaleDiv.hBound());

        double from, to;
        if ( axisEnabled(axisId) )
        {
            const int sDist = axisWidget(axisId)->startBorderDist();
            const int eDist = axisWidget(axisId)->endBorderDist();
            const QRect &scaleRect = plotLayout()->scaleRect(axisId);

            if ( axisId == xTop || axisId == xBottom )
            {
                from = metricsMap.layoutToDeviceX(scaleRect.left() + sDist);
                to = metricsMap.layoutToDeviceX(scaleRect.right() - eDist);
            }
            else
            {
                from = metricsMap.layoutToDeviceY(scaleRect.bottom() - sDist);
                to = metricsMap.layoutToDeviceY(scaleRect.top() + eDist);
            }
        }
        else
        {
            const int margin = plotLayout()->canvasMargin(axisId);

            const QRect &canvasRect = plotLayout()->canvasRect();
            if ( axisId == yLeft || axisId == yRight )
            {
                from = metricsMap.layoutToDeviceX(canvasRect.bottom() - margin);
                to = metricsMap.layoutToDeviceX(canvasRect.top() + margin);
            }
            else
            {
                from = metricsMap.layoutToDeviceY(canvasRect.left() + margin);
                to = metricsMap.layoutToDeviceY(canvasRect.right() - margin);
            }
        }
        map[axisId].setPaintXInterval(from, to);
    }


    // The canvas maps are already scaled. 
    QwtPainter::setMetricsMap(painter->device(), painter->device());

    printCanvas(painter, canvasRect, map, pfilter);

    QwtPainter::resetMetricsMap();

    ((QwtPlot *)this)->plotLayout()->invalidate();

    // reset all widgets with their original attributes.
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintCanvasBackground) )
    {
        // restore the previous base line dists

        for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
        {
            QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
            if ( scaleWidget  )
                scaleWidget->setBaselineDist(baseLineDists[axisId]);
        }
    }

    pfilter.reset((QwtPlot *)this);

    painter->restore();
}
/*!
  \brief Paint the plot into a given rectangle.
  Paint the contents of a QwtPlot instance into a given rectangle.

  \param painter Painter
  \param plotRect Bounding rectangle
  \param pfilter Print filter
  \sa QwtPlotPrintFilter
*/
void QwtPlot::print(QPainter *painter, const QRect &plotRect,
                    const QwtPlotPrintFilter &pfilter) const
{
    int axisId;

    if ( painter == 0 || !painter->isActive() ||
            !plotRect.isValid() || size().isNull() )
        return;

    painter->save();
#if 1
    /*
      PDF: In Qt4 ( <= 4.3.2 ) the scales are painted in gray instead of
      black. See http://trolltech.com/developer/task-tracker/index_html?id=184671&method=entry
      The dummy lines below work around the problem.
     */
    const QPen pen = painter->pen();
    painter->setPen(QPen(Qt::black, 1));
    painter->setPen(pen);
#endif

    // All paint operations need to be scaled according to
    // the paint device metrics.

    QwtPainter::setMetricsMap(this, painter->device());
    const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();

    // It is almost impossible to integrate into the Qt layout
    // framework, when using different fonts for printing
    // and screen. To avoid writing different and Qt unconform
    // layout engines we change the widget attributes, print and
    // reset the widget attributes again. This way we produce a lot of
    // useless layout events ...

    pfilter.apply((QwtPlot *)this);

    int baseLineDists[QwtPlot::axisCnt];
    if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales ) {
        for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) {
            QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
            if ( scaleWidget ) {
                baseLineDists[axisId] = scaleWidget->margin();
                scaleWidget->setMargin(0);
            }
        }
    }
    // Calculate the layout for the print.

    int layoutOptions = QwtPlotLayout::IgnoreScrollbars
                        | QwtPlotLayout::IgnoreFrames;
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintMargin) )
        layoutOptions |= QwtPlotLayout::IgnoreMargin;
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintLegend) )
        layoutOptions |= QwtPlotLayout::IgnoreLegend;

    ((QwtPlot *)this)->plotLayout()->activate(this,
            QwtPainter::metricsMap().deviceToLayout(plotRect),
            layoutOptions);

    if ((pfilter.options() & QwtPlotPrintFilter::PrintTitle)
            && (!titleLabel()->text().isEmpty())) {
        printTitle(painter, plotLayout()->titleRect());
    }

    if ( (pfilter.options() & QwtPlotPrintFilter::PrintLegend)
            && legend() && !legend()->isEmpty() ) {
        printLegend(painter, plotLayout()->legendRect());
    }

    for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) {
        QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
        if (scaleWidget) {
            int baseDist = scaleWidget->margin();

            int startDist, endDist;
            scaleWidget->getBorderDistHint(startDist, endDist);

            printScale(painter, axisId, startDist, endDist,
                       baseDist, plotLayout()->scaleRect(axisId));
        }
    }

    QRect canvasRect = plotLayout()->canvasRect();

    /*
       The border of the bounding rect needs to ba scaled to
       layout coordinates, so that it is aligned to the axes
     */
    QRect boundingRect( canvasRect.left() - 1, canvasRect.top() - 1,
                        canvasRect.width() + 2, canvasRect.height() + 2);
    boundingRect = metricsMap.layoutToDevice(boundingRect);
    boundingRect.setWidth(boundingRect.width() - 1);
    boundingRect.setHeight(boundingRect.height() - 1);

    canvasRect = metricsMap.layoutToDevice(canvasRect);

    // When using QwtPainter all sizes where computed in pixel
    // coordinates and scaled by QwtPainter later. This limits
    // the precision to screen resolution. A better solution
    // is to scale the maps and print in unlimited resolution.

    QwtScaleMap map[axisCnt];
    for (axisId = 0; axisId < axisCnt; axisId++) {
        map[axisId].setTransformation(axisScaleEngine(axisId)->transformation());

        const QwtScaleDiv &scaleDiv = *axisScaleDiv(axisId);
        map[axisId].setScaleInterval(scaleDiv.lBound(), scaleDiv.hBound());

        double from, to;
        if ( axisEnabled(axisId) ) {
            const int sDist = axisWidget(axisId)->startBorderDist();
            const int eDist = axisWidget(axisId)->endBorderDist();
            const QRect &scaleRect = plotLayout()->scaleRect(axisId);

            if ( axisId == xTop || axisId == xBottom ) {
                from = metricsMap.layoutToDeviceX(scaleRect.left() + sDist);
                to = metricsMap.layoutToDeviceX(scaleRect.right() + 1 - eDist);
            } else {
                from = metricsMap.layoutToDeviceY(scaleRect.bottom() + 1 - eDist );
                to = metricsMap.layoutToDeviceY(scaleRect.top() + sDist);
            }
        } else {
            int margin = plotLayout()->canvasMargin(axisId);
            if ( axisId == yLeft || axisId == yRight ) {
                margin = metricsMap.layoutToDeviceY(margin);
                from = canvasRect.bottom() - margin;
                to = canvasRect.top() + margin;
            } else {
                margin = metricsMap.layoutToDeviceX(margin);
                from = canvasRect.left() + margin;
                to = canvasRect.right() - margin;
            }
        }
        map[axisId].setPaintXInterval(from, to);
    }

    // The canvas maps are already scaled.
    QwtPainter::setMetricsMap(painter->device(), painter->device());
    printCanvas(painter, boundingRect, canvasRect, map, pfilter);
    QwtPainter::resetMetricsMap();

    ((QwtPlot *)this)->plotLayout()->invalidate();

    // reset all widgets with their original attributes.
    if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales ) {
        // restore the previous base line dists

        for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) {
            QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
            if ( scaleWidget  )
                scaleWidget->setMargin(baseLineDists[axisId]);
        }
    }

    pfilter.reset((QwtPlot *)this);

    painter->restore();
}
/*!
  \brief Paint the plot into a given rectangle.
  Paint the contents of a QwtPlot instance into a given rectangle.

  \param painter Painter
  \param plotRect Bounding rectangle
  \param pfilter Print filter
  \sa QwtPlotPrintFilter
*/
void QwtPlot::print(QPainter *painter, const QRect &plotRect,
        const QwtPlotPrintFilter &pfilter) const
{
    int axis;

    if ( painter == 0 || !painter->isActive() ||
            !plotRect.isValid() || size().isNull() )
       return;

    painter->save();

    // All paint operations need to be scaled according to
    // the paint device metrics. 

    QwtPainter::setMetricsMap(this, painter->device());

#if QT_VERSION < 300 
    if ( painter->device()->isExtDev() )
    {
        QPaintDeviceMetrics metrics(painter->device());
        if ( metrics.logicalDpiX() == 72 && metrics.logicalDpiY() == 72 )
        {
            // In Qt 2.x QPrinter returns hardcoded wrong metrics.
            // So scaling won´t work: we reset to screen resolution

            QwtPainter::setMetricsMap(this, this);
        }
    }
#endif

    const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();

    // It is almost impossible to integrate into the Qt layout
    // framework, when using different fonts for printing
    // and screen. To avoid writing different and Qt unconform
    // layout engines we change the widget attributes, print and 
    // reset the widget attributes again. This way we produce a lot of
    // useless layout events ...

    pfilter.apply((QwtPlot *)this);

    int baseLineDists[QwtPlot::axisCnt];
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintCanvasBackground) )
    {
        // In case of no background we set the backbone of
        // the scale on the frame of the canvas.

        for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
        {
            if ( d_scale[axis] )
            {
                baseLineDists[axis] = d_scale[axis]->baseLineDist();
                d_scale[axis]->setBaselineDist(0);
            }
        }
    }
    // Calculate the layout for the print.

    int layoutOptions = QwtPlotLayout::IgnoreScrollbars 
        | QwtPlotLayout::IgnoreFrames;
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintMargin) )
        layoutOptions |= QwtPlotLayout::IgnoreMargin;
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintLegend) )
        layoutOptions |= QwtPlotLayout::IgnoreLegend;

    d_layout->activate(this, QwtPainter::metricsMap().deviceToLayout(plotRect), 
        layoutOptions);

    if ((pfilter.options() & QwtPlotPrintFilter::PrintTitle)
        && (!d_lblTitle->text().isEmpty()))
    {
        printTitle(painter, d_layout->titleRect());
    }

    if ( (pfilter.options() & QwtPlotPrintFilter::PrintLegend)
        && !d_legend->isEmpty() )
    {
        printLegend(painter, d_layout->legendRect());
    }

    for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
    {
        if (d_scale[axis])
        {
            int baseDist = d_scale[axis]->baseLineDist();

            int startDist, endDist;
            d_scale[axis]->minBorderDist(startDist, endDist);

            printScale(painter, axis, startDist, endDist,
                baseDist, d_layout->scaleRect(axis));
        }
    }

    const QRect canvasRect = metricsMap.layoutToDevice(d_layout->canvasRect());

    // When using QwtPainter all sizes where computed in pixel
    // coordinates and scaled by QwtPainter later. This limits
    // the precision to screen resolution. A much better solution
    // is to scale the maps and print in unlimited resolution.

    QwtArray<QwtDiMap> map(axisCnt);
    for (axis = 0; axis < axisCnt; axis++)
    {
        const QwtScaleDiv &scaleDiv = d_as[axis].scaleDiv();
        map[axis].setDblRange(scaleDiv.lBound(),
            scaleDiv.hBound(), scaleDiv.logScale());

        double from, to;
        if ( axisEnabled(axis) )
        {
            const int sDist = d_scale[axis]->startBorderDist();
            const int eDist = d_scale[axis]->endBorderDist();
            const QRect &scaleRect = d_layout->scaleRect(axis);

            if ( axis == xTop || axis == xBottom )
            {
                from = metricsMap.layoutToDeviceX(scaleRect.left() + sDist);
                to = metricsMap.layoutToDeviceX(scaleRect.right() - eDist);
            }
            else
            {
                from = metricsMap.layoutToDeviceY(scaleRect.bottom() - sDist);
                to = metricsMap.layoutToDeviceY(scaleRect.top() + eDist);
            }
        }
        else
        {
            const int margin = plotLayout()->canvasMargin(axis);

            const QRect &canvasRect = plotLayout()->canvasRect();
            if ( axis == yLeft || axis == yRight )
            {
                from = metricsMap.layoutToDeviceX(canvasRect.bottom() - margin);
                to = metricsMap.layoutToDeviceX(canvasRect.top() + margin);
            }
            else
            {
                from = metricsMap.layoutToDeviceY(canvasRect.left() + margin);
                to = metricsMap.layoutToDeviceY(canvasRect.right() - margin);
            }
        }
        map[axis].setIntRange( qwtInt(from), qwtInt(to));
    }


    // The maps are already scaled. 
    QwtPainter::setMetricsMap(painter->device(), painter->device());

    printCanvas(painter, canvasRect, map, pfilter);

    QwtPainter::resetMetricsMap();

    d_layout->invalidate();

    // reset all widgets with their original attributes.
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintCanvasBackground) )
    {
        // restore the previous base line dists

        for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
        {
            if ( d_scale[axis] )
                d_scale[axis]->setBaselineDist(baseLineDists[axis]);
        }
    }

    pfilter.reset((QwtPlot *)this);

    painter->restore();
}