双缓冲技术(Double Buffering)(1、简介和源代码部分)
#ifndef PLOTTER_H
#define PLOTTER_H
#include <QMap>//包含的Qt的头文件
#include <QPixmap>
#include <QVector>
#include <QWidget>
class QToolButton; //两个前向声明
class PlotSettings;
class Plotter : public QWidget
{
Q_OBJECT
public:
Plotter(QWidget *parent = );
void setPlotSettings(const PlotSettings &settings);
void setCurveData(int id, const QVector<QPointF> &data);
void clearCurve(int id);
QSize minimumSizeHint() const; //重写QWidget::minimumSizeHint()
QSize sizeHint() const; //重写QWidget::sizeHint()
public slots:
void zoomIn(); //放大曲线
void zoomOut(); //缩小显示曲线
protected: //重写的事件处理函数
void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
void wheelEvent(QWheelEvent *event);
private:
void updateRubberBandRegion();
void refreshPixmap();
void drawGrid(QPainter *painter);
void drawCurves(QPainter *painter);
enum { Margin = };
QToolButton *zoomInButton;
QToolButton *zoomOutButton;
QMap<int, QVector<QPointF> > curveMap; //曲线数据
QVector<PlotSettings> zoomStack; //PlotSettings堆栈区域
int curZoom;
bool rubberBandIsShown;
QRect rubberBandRect;
QPixmap pixmap; //显示在屏幕的控件的一个拷贝,任何绘制总是先在pixmap进行,然//后拷贝到控件上
};
//PlotSettings确定x,y轴的范围,和刻度的个数
class PlotSettings
{
public:
PlotSettings(); void scroll(int dx, int dy);
void adjust();
double spanX() const { return maxX - minX; }
double spanY() const { return maxY - minY; } double minX;
double maxX;
int numXTicks;
double minY;
double maxY;
int numYTicks; private:
static void adjustAxis(double &min, double &max, int &numTicks);
};
#endif
#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 = ;
zoomInButton->hide();
zoomOutButton->hide();
refreshPixmap();
} void Plotter::zoomOut()
{
if (curZoom > ) {
--curZoom;
zoomOutButton->setEnabled(curZoom > );
zoomInButton->setEnabled(true);
zoomInButton->show();
refreshPixmap();
}
} void Plotter::zoomIn()
{
if (curZoom < zoomStack.count() - ) {
++curZoom;
zoomInButton->setEnabled(curZoom < zoomStack.count() - );
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( * Margin, * Margin);
} QSize Plotter::sizeHint() const
{
return QSize( * Margin, * Margin);
} void Plotter::paintEvent(QPaintEvent * /* event */)
{
QStylePainter painter(this);
painter.drawPixmap(, , pixmap);
if (rubberBandIsShown) {
painter.setPen(palette().light().color());
painter.drawRect(rubberBandRect.normalized()
.adjusted(, , -, -));
}
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() + );
zoomInButton->move(x, );
zoomOutButton->move(x + zoomInButton->width() + , );
refreshPixmap();
}
void Plotter::resizeEvent(QResizeEvent * /* event */)
{
int x = width() - (zoomInButton->width()
+ zoomOutButton->width() + );
zoomInButton->move(x, );
zoomOutButton->move(x + zoomInButton->width() + , );
refreshPixmap();
}
void Plotter::resizeEvent(QResizeEvent * /* event */)
{
int x = width() - (zoomInButton->width()
+ zoomOutButton->width() + );
zoomInButton->move(x, );
zoomOutButton->move(x + zoomInButton->width() + , );
refreshPixmap();
} void Plotter::mousePressEvent(QMouseEvent *event)
{
QRect rect(Margin, Margin,
width() - * Margin, height() - * 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() < || rect.height() < )
return;
rect.translate(-Margin, -Margin);
PlotSettings prevSettings = zoomStack[curZoom];
PlotSettings settings;
double dx = prevSettings.spanX() / (width() - * Margin);
double dy = prevSettings.spanY() / (height() - * 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 + );
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(-, );
refreshPixmap();
break;
case Qt::Key_Right:
zoomStack[curZoom].scroll(+, );
refreshPixmap();
break;
case Qt::Key_Down:
zoomStack[curZoom].scroll(, -);
refreshPixmap();
break;
case Qt::Key_Up:
zoomStack[curZoom].scroll(, +);
refreshPixmap();
break;
default:
QWidget::keyPressEvent(event);
}
} void Plotter::wheelEvent(QWheelEvent *event)
{
int numDegrees = event->delta() / ;
int numTicks = numDegrees / ;
if (event->orientation() == Qt::Horizontal) {
zoomStack[curZoom].scroll(numTicks, );
} else {
zoomStack[curZoom].scroll(, numTicks);
}
refreshPixmap();
}
void Plotter::updateRubberBandRegion()
{
QRect rect = rubberBandRect.normalized();
update(rect.left(), rect.top(), rect.width(), );
update(rect.left(), rect.top(), , rect.height());
update(rect.left(), rect.bottom(), rect.width(), );
update(rect.right(), rect.top(), , rect.height());
}
void Plotter::refreshPixmap()
{
pixmap = QPixmap(size());
pixmap.fill(this, , );
QPainter painter(&pixmap);
painter.initFrom(this);
drawGrid(&painter);
drawCurves(&painter);
update();
} void Plotter::drawGrid(QPainter *painter)
{
QRect rect(Margin, Margin,
width() - * Margin, height() - * Margin);
if (!rect.isValid())
return;
PlotSettings settings = zoomStack[curZoom];
QPen quiteDark = palette().dark().color().light();
QPen light = palette().light().color();
for (int i = ; i <= settings.numXTicks; ++i) {
int x = rect.left() + (i * (rect.width() - )
/ 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() + );
painter->drawText(x - , rect.bottom() + , , ,
Qt::AlignHCenter | Qt::AlignTop,
QString::number(label));
}
for (int j = ; j <= settings.numYTicks; ++j) {
int y = rect.bottom() - (j * (rect.height() - )
/ 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() - , y, rect.left(), y);
painter->drawText(rect.left() - Margin, y - , Margin - , ,
Qt::AlignRight | Qt::AlignVCenter,
QString::number(label));
}
painter->drawRect(rect.adjusted(, , -, -));
} void Plotter::drawCurves(QPainter *painter)
{
static const QColor colorForIds[] = {
Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta, Qt::yellow
};
PlotSettings settings = zoomStack[curZoom];
QRect rect(Margin, Margin,
width() - * Margin, height() - * Margin);
if (!rect.isValid())
return;
painter->setClipRect(rect.adjusted(+, +, -, -));
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 = ; 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() - )
/ settings.spanX());
double y = rect.bottom() - (dy * (rect.height() - )
/ settings.spanY());
polyline[j] = QPointF(x, y);
}
painter->setPen(colorForIds[uint(id) % ]);
painter->drawPolyline(polyline);
}
} ////////////////////////////////////////////////////////////
PlotSettings::PlotSettings()
{
minX = 0.0;
maxX = 10.0;
numXTicks = ;
minY = 0.0;
maxY = 10.0;
numYTicks = ;
} 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)
{
const int MinTicks = ;
double grossStep = (max - min) / MinTicks;
double step = pow(10.0, floor(log10(grossStep)));
if ( * step < grossStep) {
step *= ;
} else if ( * step < grossStep) {
step *= ;
}
numTicks = int(ceil(max / step) - floor(min / step));
if (numTicks < MinTicks)
numTicks = MinTicks;
min = floor(min / step) * step;
max = ceil(max / step) * step;
}
参考:http://www.cnblogs.com/SkylineSoft/articles/2046262.html
双缓冲技术(Double Buffering)(1、简介和源代码部分)的更多相关文章
- OpenGL中实现双缓冲技术
在OpenGL中实现双缓冲技术的一种简单方法: 1.在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | G ...
- 《MFC游戏开发》笔记六 图像双缓冲技术:实现一个流畅的动画
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9334121 作者:七十一雾央 新浪微博:http:/ ...
- Win32 GDI 非矩形区域剪裁,双缓冲技术
传统的Win32通过GDI提供图形显示的功能,包括了基本的绘图功能,如画线.方块.椭圆等等,高级功能包括了多边形和Bezier的绘制.这样app就不用关心那些图形学的细节了,有点类似于UNIX上的X- ...
- avalon与双缓冲技术
avalon与双缓冲技术 avalon1.5一个重要技术升级是引进异步渲染.异步渲染在游戏界有一个更专业的名字,叫双缓冲.游戏界要刷新界面与我们刷新浏览器视图,面临的问题是一致的.视图是由许多存在套嵌 ...
- C#中利用双缓冲技术解决绘图闪屏问题。
这段时间在做一个小型游戏,在界面显示的时候用到了一些图形.一开始涉及到的图形全都用控件的背景图片代替了.这样游戏运行的时候存在的一个很大的问题是游戏运行很慢.小组成员费尽周折,即将放弃,每一个成员都愁 ...
- c++双缓冲技术,以避免闪烁绘图
当数据量非常大时,画图可能须要几秒钟甚至更长的时间,并且有时还会出现闪烁现象,为了解决这些问题.可採用双缓冲技术来画图. 双缓冲即在内存中创建一个与屏幕画图区域一致的对象,先将图形绘制到内存中的这个对 ...
- java的双缓冲技术
Java的强大特性让其在游戏编程和多媒体动画处理方面也毫不逊色.在Java游戏编程和动画编程中最常见的就是对于屏幕闪烁的处理.本文从J2SE的一个再现了屏幕闪烁的Java Appilication简单 ...
- C# GDI+双缓冲技术
我想有很多搞图形方面的朋友都会用到双缓冲技术的时候,而且有的时候她的确是个头疼的问题.最近我也要用双缓冲技术,程序怎么调试都不合适,当要对图形进行移动时,总是会出现闪烁抖动.在网上找了些资料,说得都不 ...
- Java中用双缓冲技术消除闪烁
在Java编写具有连贯变化的窗口程序时,通常的办法是在子类中覆盖父类的paint(Graphics)方法,在方法中使用GUI函数实现窗口重绘的过程.连贯变换的窗口会不断地调用update(Graphi ...
随机推荐
- Unity Panel open & close
Making a Popup and Closable Panel in Unity 5 script: public GameObject thePanel; public open() { the ...
- NDK-r7以上版本部署方法
一.关于NDK: NDK全称:Native Development Kit. 1.NDK是一系列工具的集合. NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和jav ...
- Android 自定义View修炼-Android开发之自定义View开发及实例详解
在开发Android应用的过程中,难免需要自定义View,其实自定义View不难,只要了解原理,实现起来就没有那么难. 其主要原理就是继承View,重写构造方法.onDraw,(onMeasure)等 ...
- CSS排版页面
创建CSS文件如下: @charset "utf-8"; /* CSS Document */ *{ margin:0px; padding:0px; border:0px; } ...
- 深入了解shell
接触linux很久了,但一直没有总线,老是尝鲜,什么都想学,但好多没多没有记住,特的总结了一些基本的东西,查了很多资料,不完善的方面我会慢慢的更新…… 操作系统与外部最主要的接口就叫做shell. ...
- Windows服务安装方法
操作系统:Win8.1 安装方法:在命令行窗口中输入:InstallUtil service.exe 出错原因:需要以管理员身份启动命令行.
- HDU1557权利选举
/* 思路:遍历所有2^n个集合,对于每个集合求票和,如果满足票为优胜团体,而再对集合每个成员比较,是否满足变成非优胜团体,是的话,对于该成员对应结果+1. 重点:利用二进制思想,所有团体均对应0~2 ...
- 网络基础---OSI 模型与TCP/IP
一.网络的演进: 1.简单的联接:1960's ------------ 1970's Host Network 六十至七十年代,网络的概念主要是主机架构的低速串行联接,提供应用程序执行.远程打 ...
- 将requirejs进行到底(2)
前一篇:JS模块化工具requirejs教程(一):初识requirejs 我们以非常简单的方式引入了requirejs,这一篇将讲述一下requirejs中的一些基本知识,包括API使用方式等. 基 ...
- 日期-用Datapicker实现前一天后一天
运用了JQuery UI Datepicker 插件和一些常用日期的方法.其中Datepicker的API具体可参考[http://api.jqueryui.com/datepicker/#optio ...