SkylineSoft

莽莽苍节兮 群山巍峨 日月光照兮 纷纭错落 丝竹共振兮 执节者歌 行云流水兮 用心无多 求大道以弹兵兮凌万物而超脱 觅知音因难得兮唯天地与作合
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

双缓冲技术(Double Buffering)(4、私有函数的实现)

Posted on 2011-05-14 14:39  Jiangwzh  阅读(901)  评论(1编辑  收藏  举报
以下是私有函数的实现: 

  void Plotter::updateRubberBandRegion()

{

    QRect rect = rubberBandRect.normalized();
    update(rect.left(), rect.top(), rect.width(), 1);
    update(rect.left(), rect.top(), 1, rect.height());
    update(rect.left(), rect.bottom(), rect.width(), 1);
    update(rect.right(), rect.top(), 1, rect.height());
}
函数updateRubberBand()在mousePressEvent(),mouseMoveEvent()和 mouseReleaseEvent()中被调用,用来删除或者从新绘制橡皮线。函数中调用了四次update(),用四个绘制事件完成由橡皮线组成的四 个小矩形的绘制。Qt也提供了一个类QRubberBand用来绘制橡皮线,但是控件自己提供的绘制函数会更好
void Plotter::refreshPixmap()
{
    pixmap = QPixmap(size());
    pixmap.fill(this, 0, 0);
    QPainter painter(&pixmap);
    painter.initFrom(this);
    drawGrid(&painter);
    drawCurves(&painter);
    update();
}
函数refreshPixmap()把plot绘制到图片上,并且更新控件。首先我们把图片的大小调整为和当前控件大小相同,用控件的背景颜色 填充整个图片。这个颜色是当前调色版的“dark”部分。如果背景用的刷子不是固体的(solid brush,刷子的样式,只有颜色,没有花纹的那种最简单的),QPixmap::fill()需要知道控件中刷子的偏移量,以便图片和控件保持一致。因 为我们保存的是整个控件,那么因此偏移位置为(0,0)。
在这个函数中,我们使用了一个QPainter绘制图片,QPainter::initFrom()设置绘制图片所需画笔,背景和字体,参数 this表示这些设置和Plotter控件的相应设置是一致的。然后我们调用drawGrid(),drawCurves()绘制网格和曲线。最 后,update()函数更新全部控件,在painteEvent()函数中把图片拷贝到控件上。
void Plotter::drawGrid(QPainter *painter)
{
   QRect rect(Margin, Margin,
               width() - 2 * Margin, height() - 2 * Margin);
    if (!rect.isValid())
        return;
    PlotSettings settings = zoomStack[curZoom];
    QPen quiteDark = palette().dark().color().light();
    QPen light = palette().light().color();
    for (int i = 0; i <= settings.numXTicks; ++i) {
        int x = rect.left() + (i * (rect.width() - 1)
                                 / settings.numXTicks);
        double label = settings.minX + (i * settings.spanX()
                                          / settings.numXTicks);
        painter->setPen(quiteDark);
        painter->drawLine(x, rect.top(), x, rect.bottom());
        painter->setPen(light);
        painter->drawLine(x, rect.bottom(), x, rect.bottom() + 5);
        painter->drawText(x - 50, rect.bottom() + 5, 100, 15,
                          Qt::AlignHCenter | Qt::AlignTop,
                          QString::number(label));
    }
    for (int j = 0; j <= settings.numYTicks; ++j) {
        int y = rect.bottom() - (j * (rect.height() - 1)
                                   / settings.numYTicks);
        double label = settings.minY + (j * settings.spanY()
                                          / settings.numYTicks);
        painter->setPen(quiteDark);
        painter->drawLine(rect.left(), y, rect.right(), y);
        painter->setPen(light);
        painter->drawLine(rect.left() - 5, y, rect.left(), y);
        painter->drawText(rect.left() - Margin, y - 10, Margin - 5, 20,
                          Qt::AlignRight | Qt::AlignVCenter,
                          QString::number(label));
    }
    painter->drawRect(rect.adjusted(0, 0, -1, -1));
}
函数drawGrid()在坐标轴和曲线的下面绘制网格。这个区域由一个矩形确定,如果控件太小,则不绘制。第一个循环绘制网格的垂直线,个数 为x坐标轴的刻度个数。第二个循环绘制网格的水平线,共y坐标轴的刻度个数。最后,沿边界绘制一个矩形。drawText()绘制两个坐标轴上刻度的个 数。
函数painter->drawText()语法如下:
painter->drawText(x, y, width, height, alignment, text);
其中(x,y,width,height)所确定的矩形确定文字的大小和位置alignment为文字的对其方式。
void Plotter::drawCurves(QPainter *painter)
{
    static const QColor colorForIds[6] = {
        Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta, Qt::yellow
    };
    PlotSettings settings = zoomStack[curZoom];
    QRect rect(Margin, Margin,
               width() - 2 * Margin, height() - 2 * Margin);
    if (!rect.isValid())
        return;
    painter->setClipRect(rect.adjusted(+1, +1, -1, -1));
    QMapIterator<int, QVector<QPointF> > i(curveMap);
    while (i.hasNext()) {
        i.next();
        int id = i.key();
        const QVector<QPointF> &data = i.value();
        QPolygonF polyline(data.count());
        for (int j = 0; j < data.count(); ++j) {
            double dx = data[j].x() - settings.minX;
            double dy = data[j].y() - settings.minY;
            double x = rect.left() + (dx * (rect.width() - 1)
                                         / settings.spanX());
            double y = rect.bottom() - (dy * (rect.height() - 1)
                                           / settings.spanY());
            polyline[j] = QPointF(x, y);
        }
        painter->setPen(colorForIds[uint(id) % 6]);
        painter->drawPolyline(polyline);
    }
}
函数drawCurves()在网格上绘制出曲线。调用了QPainter::setClipRect()函数设置绘制曲线的矩形区域(不包括四周的间隙和框架)。QPainter会忽略画到这个区域外的象素。
然后我们遍历所有的曲线,在每一条曲线,遍历它所有的QPointF点。函数key()得到曲线的id,value()函数得到曲线的 QVector<QPointF>类型的数据。内层循环把QPointF记录的plotter坐标转换为控件坐标,把它们保存在多段线变量 中。
转换坐标后,我们设置画笔的颜色(使用函数前面预定义的颜色),调用drawPolyline()绘制出所有的曲线的点。