1. 程式人生 > >5-4 雙緩衝技術(Double Buffering)(1、簡介和原始碼部分)

5-4 雙緩衝技術(Double Buffering)(1、簡介和原始碼部分)

#include <QtGui>
#include 
<cmath>

#include 
"plotter.h"

Plotter::Plotter(QWidget 
*parent)
    : QWidget(parent)
{
    setBackgroundRole(QPalette::Dark);
    setAutoFillBackground(
true);
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    setFocusPolicy(Qt::StrongFocus);
    rubberBandIsShown 
=false;

    zoomInButton 
=new QToolButton(this);
    zoomInButton
->setIcon(QIcon(":/images/zoomin.png"));
    zoomInButton
->adjustSize();
    connect(zoomInButton, SIGNAL(clicked()), 
this, SLOT(zoomIn()));

    zoomOutButton 
=new QToolButton(this);
    zoomOutButton
->setIcon(QIcon(":/images/zoomout.png
"));
    zoomOutButton
->adjustSize();
    connect(zoomOutButton, SIGNAL(clicked()), 
this, SLOT(zoomOut()));

    setPlotSettings(PlotSettings());
}

void Plotter::setPlotSettings(const PlotSettings &settings)
{
    zoomStack.clear();
    zoomStack.append(settings);
    curZoom 
=0;
    zoomInButton
->hide();
    zoomOutButton
->hide();
    refreshPixmap();
}

void Plotter::zoomOut()
{
    
if (curZoom >0) {
        
--curZoom;
        zoomOutButton
->setEnabled(curZoom >0);
        zoomInButton
->setEnabled(true);
        zoomInButton
->show();
        refreshPixmap();
    }
}

void Plotter::zoomIn()
{
    
if (curZoom < zoomStack.count() -1) {
        
++curZoom;
        zoomInButton
->setEnabled(curZoom < zoomStack.count() -1);
        zoomOutButton
->setEnabled(true);
        zoomOutButton
->show();
        refreshPixmap();
    }
}

void Plotter::setCurveData(int id, const QVector<QPointF>&data)
{
    curveMap[id] 
= data;
    refreshPixmap();
}

void Plotter::clearCurve(int id)
{
    curveMap.remove(id);
    refreshPixmap();
}

QSize Plotter::minimumSizeHint() 
const
{
    
return QSize(6* Margin, 4* Margin);
}

QSize Plotter::sizeHint() 
const
{
    
return QSize(12* Margin, 8* Margin);
}

void Plotter::paintEvent(QPaintEvent */* event */)
{
    QStylePainter painter(
this);
    painter.drawPixmap(
00, pixmap);
    
if (rubberBandIsShown) {
        painter.setPen(palette().light().color());
        painter.drawRect(rubberBandRect.normalized()
                                       .adjusted(
00-1-1));
    }
    
if (hasFocus()) {
        QStyleOptionFocusRect option;
        option.initFrom(
this);
        option.backgroundColor 
= palette().dark().color();
        painter.drawPrimitive(QStyle::PE_FrameFocusRect, option);
    }
}

void Plotter::resizeEvent(QResizeEvent */* event */)
{
    
int x = width() - (zoomInButton->width()
                       
+ zoomOutButton->width() +10);
    zoomInButton
->move(x, 5);
    zoomOutButton
->move(x + zoomInButton->width() +55);
    refreshPixmap();
}
void Plotter::resizeEvent(QResizeEvent */* event */)
{
    
int x = width() - (zoomInButton->width()
                       
+ zoomOutButton->width() +10);
    zoomInButton
->move(x, 5);
    zoomOutButton
->move(x + zoomInButton->width() +55);
    refreshPixmap();
}
void Plotter::resizeEvent(QResizeEvent */* event */)
{
    
int x = width() - (zoomInButton->width()
                       
+ zoomOutButton->width() +10);
    zoomInButton
->move(x, 5);
    zoomOutButton
->move(x + zoomInButton->width() +55);
    refreshPixmap();
}

void Plotter::mousePressEvent(QMouseEvent *event)
{
    QRect rect(Margin, Margin,
               width() 
-2* Margin, height() -2* Margin);
    
if (event->button() == Qt::LeftButton) {
        
if (rect.contains(event->pos())) {
            rubberBandIsShown 
=true;
            rubberBandRect.setTopLeft(
event->pos());
            rubberBandRect.setBottomRight(
event->pos());
            updateRubberBandRegion();
            setCursor(Qt::CrossCursor);
        }
    }
}
void Plotter::mouseMoveEvent(QMouseEvent *event)
{
    
if (rubberBandIsShown) {
        updateRubberBandRegion();
        rubberBandRect.setBottomRight(
event->pos());
        updateRubberBandRegion();
    }
}
void Plotter::mouseReleaseEvent(QMouseEvent *event)
{
    
if ((event->button() == Qt::LeftButton) && rubberBandIsShown) {
        rubberBandIsShown 
=false;
        updateRubberBandRegion();
        unsetCursor();
        QRect rect 
= rubberBandRect.normalized();
        
if (rect.width() <4|| rect.height() <4)
            
return;
        rect.translate(
-Margin, -Margin);
        PlotSettings prevSettings 
= zoomStack[curZoom];
        PlotSettings settings;
        
double dx = prevSettings.spanX() / (width() -2* Margin);
        
double dy = prevSettings.spanY() / (height() -2* Margin);
        settings.minX 
= prevSettings.minX + dx * rect.left();
        settings.maxX 
= prevSettings.minX + dx * rect.right();
        settings.minY 
= prevSettings.maxY - dy * rect.bottom();
        settings.maxY 
= prevSettings.maxY - dy * rect.top();
        settings.adjust();
        zoomStack.resize(curZoom 
+1);
        zoomStack.append(settings);
        zoomIn();
    }
}

void Plotter::keyPressEvent(QKeyEvent *event)
{
    
switch (event->key()) {
    
case Qt::Key_Plus:
        zoomIn();
        
break;
    
case Qt::Key_Minus:
        zoomOut();
        
break;
    
case Qt::Key_Left:
        zoomStack[curZoom].scroll(
-10);
        refreshPixmap();
        
break;
    
case Qt::Key_Right:
        zoomStack[curZoom].scroll(
+10);
        refreshPixmap();
        
break;
    
case Qt::Key_Down:
        zoomStack[curZoom].scroll(
0-1);
        refreshPixmap();
        
break;
    
case Qt::Key_Up:
        zoomStack[curZoom].scroll(
0+1);
        refreshPixmap();
        
break;
    
default:
        QWidget::keyPressEvent(
event);
    }
}

void Plotter::wheelEvent(QWheelEvent *event)
{
    
int numDegrees =event->delta() /8;
    
int numTicks = numDegrees /15;
    
if (event->orientation() == Qt::Horizontal) {
        zoomStack[curZoom].scroll(numTicks, 
0);
    } 
else {
        zoomStack[curZoom].scroll(
0, numTicks);
    }
    refreshPixmap();
}
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());
}
void Plotter::refreshPixmap()
{
    pixmap 
= QPixmap(size());
    pixmap.fill(
this00);
    QPainter painter(
&pixmap);
    painter.initFrom(
this);
    drawGrid(
&painter);
    drawCurves(
&painter);
    update();
}

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() +510015,
                          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 -520,
                          Qt::AlignRight 
| Qt::AlignVCenter,
                          QString::number(label));
    }
    painter
->drawRect(rect.adjusted(00-1-1));
}

void Plotter::drawCurves(QPainter *painter)
{
    
staticconst 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);
    }
}

////////////////////////////////////////////////////////////
PlotSettings::PlotSettings()
{
    minX 
=0.0;
    maxX 
=10.0;
    numXTicks 
=5;
    minY 
=0.0;
    maxY 
=10.0;
    numYTicks 
=5;
}

void PlotSettings::scroll(int dx, int dy)
{
    
double stepX = spanX() / numXTicks;
    minX 
+= dx * stepX;
    maxX 
+= dx * stepX;
    
double stepY = spanY() / numYTicks;
    minY 
+= dy * stepY;
    maxY 
+= dy * stepY;
}

void PlotSettings::adjust()
{
    adjustAxis(minX, maxX, numXTicks);
    adjustAxis(minY, maxY, numYTicks);
}

void PlotSettings::adjustAxis(double&min, double&max,
                              
int&numTicks)
{
    
constint MinTicks =4;
    
double grossStep = (max - min) / MinTicks;
    
double step = pow(10.0, floor(log10(grossStep)));
    
if (5* step < grossStep) {
        step 
*=5;
    } 
elseif (2* step < grossStep) {
        step 
*=2;
    }
    numTicks 
=int(ceil(max / step) - floor(min / step));
    
if (numTicks < MinTicks)
        numTicks 
= MinTicks;
    min 
= floor(min / step) * step;
    max 
= ceil(max / step) * step;
}