一、前言

几年前就一直考虑过写这个控件了,在9年前用C#的时候,就看到过别人用C#写了个水波效果的控件,挺好玩的,当时看了下代码用的二维数组来存储变换的图像像素数据,自从学了Qt以后,有过几次想要用Qt写一个版本,当时功力尚浅,尝试过了没写成功,我记得还有个用汇编写的dll提供调用,那个效率贼高,用CPU绘制的话效率相对来说低很多。前阵子一个好友-离心泵(QQ:33522)恰巧写了个,我在他的基础上改进了一些功能,增加了一些接口设置,比如提供参数可以控制水波的消失速度,扩散的速度,水波的面积大小以及水波的深度等。

二、实现的功能

  • 1:可设置显示的图像
  • 2:可设置衰减系数,控制消失速度,值越小水波消失越快
  • 3:可设置折射系数,控制扩散速度,值越大水波扩散越快
  • 4:可设置石头大小,控制水波面积,值越大水波面积越大
  • 5:可设置石头重量,控制水波深度,值越大水波深度越浪
  • 6:目前采用的是cpu运算和绘制,图片越小越流畅

三、效果图

四、头文件代码

#ifndef WAVEWATER_H
#define WAVEWATER_H /**
* 水波效果控件 作者:离心泵(QQ:33522) 整理:feiyangqingyun(QQ:517216493) 2019-10-03
* 1:可设置显示的图像
* 2:可设置衰减系数,控制消失速度,值越小水波消失越快
* 3:可设置折射系数,控制扩散速度,值越大水波扩散越快
* 4:可设置石头大小,控制水波面积,值越大水波面积越大
* 5:可设置石头重量,控制水波深度,值越大水波深度越浪
* 6:目前采用的是cpu运算和绘制,图片越小越流畅
*/ #include <QWidget>
#include <QMap> #ifdef quc
#if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
#include <QtDesigner/QDesignerExportWidget>
#else
#include <QtUiPlugin/QDesignerExportWidget>
#endif class QDESIGNER_WIDGET_EXPORT WaveWater : public QWidget
#else
class WaveWater : public QWidget
#endif {
Q_OBJECT
Q_PROPERTY(int damping READ getDamping WRITE setDamping)
Q_PROPERTY(int refractive READ getRefractive WRITE setRefractive)
Q_PROPERTY(int stoneSize READ getStoneSize WRITE setStoneSize)
Q_PROPERTY(int stoneWeight READ getStoneWeight WRITE setStoneWeight)
Q_PROPERTY(QPixmap image READ getImage WRITE setImage) public:
explicit WaveWater(QWidget *parent = 0);
~WaveWater(); protected:
void mousePressEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);
void mouseReleaseEvent(QMouseEvent *);
void paintEvent(QPaintEvent *); private:
int damping; //波能衰减系数
int refractive; //波能折射系数
int stoneSize; //石头大小
int stoneWeight; //石头重量
QPixmap image; //渲染图片 QImage imageRender; //渲染像素图片
QImage imageOrigin; //渲染源
QPixmap pixmap; //渲染图片 int imageWidth; //图片宽度
int imageHeight; //图片高度
int **waveBuffer1; //波能缓冲区1
int **waveBuffer2; //波能缓冲区2 bool isStoped; //水波是否结束波动
bool isPressed; //鼠标是否按下
QPoint lastPoint; //鼠标按下出的坐标
QTimer *timer; //定时器绘制 private slots:
//执行计算位图进行绘制
void drawImage();
//水波步进扩散
void waveSpread();
//渲染水波位图
void waveRender();
//扔石子
void dropStone(int x, int y, int stoneSize, int stoneWeight); public:
int getDamping() const;
int getRefractive() const;
int getStoneSize() const;
int getStoneWeight() const;
QPixmap getImage() const; QSize sizeHint() const;
QSize minimumSizeHint() const; public Q_SLOTS:
//设置衰减率系数
void setDamping(int damping);
//设置折射率系数
void setRefractive(int refractive);
//设置石头大小
void setStoneSize(int stoneSize);
//设置石头重量
void setStoneWeight(int stoneWeight);
//设置背景图片
void setImage(const QPixmap &pixmap);
}; #endif // WAVEWATER_H

五、核心代码

void WaveWater::paintEvent(QPaintEvent *)
{
if(image.isNull()) {
return;
} QPainter painter(this);
painter.setRenderHints(QPainter::SmoothPixmapTransform); //如果停止阶段则绘制原图,否则绘制渲染图
if (isStoped) {
painter.drawPixmap(0, 0, image);
} else {
painter.drawPixmap(0, 0, pixmap);
}
} void WaveWater::drawImage()
{
if(isStoped) {
timer->stop();
} else {
this->waveRender();
this->update();
}
} void WaveWater::waveSpread()
{
quint32 counter = 0;
// 波能渐变
for(int h = 1; h < imageHeight - 1; h++) {
for(int w = 1; w < imageWidth - 1; w++) {
//波能扩散
waveBuffer2[w][h] = ((waveBuffer1[w - 1][h] + waveBuffer1[w + 1][h] + waveBuffer1[w][h - 1] + waveBuffer1[w][ h + 1]) >> 1) - waveBuffer2[w][h];
//波能衰减
waveBuffer2[w][h] -= (waveBuffer2[w][h] >> damping);
//判断波动释放结束
if(waveBuffer1[w][h] - waveBuffer2[w][h]) {
counter++;
}
}
} //交换缓冲区
int **temp = waveBuffer1;
waveBuffer1 = waveBuffer2;
waveBuffer2 = temp; //设置释放完成
isStoped = counter ? false : true;
} void WaveWater::waveRender()
{
//先改变波纹振幅
waveSpread();
if(isStoped) {
return;
} int offsetX = 0;
int offsetY = 0; //扫描位图
for(int y = 1; y < imageHeight - 1; y++) {
for(int x = 1; x < imageWidth - 1; x++) {
//根据波幅计算位图数据偏移值,渲染点(x,y)对应原始图片(offsetX,offsetY)
offsetX = x + ((waveBuffer1[x - 1][y] - waveBuffer1[x + 1][y]) >> refractive);
offsetY = y + ((waveBuffer1[x][y - 1] - waveBuffer1[x][y + 1]) >> refractive);
//复制象素
if(0 <= offsetX && offsetX < imageWidth - 1 && 0 <= offsetY && offsetY < imageHeight - 1) {
QRgb color = imageOrigin.pixel(offsetX, offsetY);
imageRender.setPixel(x, y, color);
}
}
} pixmap.convertFromImage(imageRender);
} void WaveWater::dropStone(int x, int y, int stoneSize, int stoneWeight)
{
isStoped = false;
int posX = 0;
int posY = 0; for(int h = -stoneSize; h < stoneSize; h++) {
for(int w = -stoneSize; w < stoneSize; w++) {
posX = x + w;
posY = y + h; //控制范围,不能超出图片
if(posX < 0 || posX >= imageWidth || posY < 0 || posY >= imageHeight) {
continue;
} //点(w,h)在一个圆形区域内,初始化波能缓冲区1
if(h * h + w * w <= stoneSize * stoneSize) {
waveBuffer1[posX][posY] = -stoneWeight;
}
}
}
}

六、控件介绍

  1. 超过160个精美控件,涵盖了各种仪表盘、进度条、进度球、指南针、曲线图、标尺、温度计、导航条、导航栏,flatui、高亮按钮、滑动选择器、农历等。远超qwt集成的控件数量。
  2. 每个类都可以独立成一个单独的控件,零耦合,每个控件一个头文件和一个实现文件,不依赖其他文件,方便单个控件以源码形式集成到项目中,较少代码量。qwt的控件类环环相扣,高度耦合,想要使用其中一个控件,必须包含所有的代码。
  3. 全部纯Qt编写,QWidget+QPainter绘制,支持Qt4.6到Qt5.13的任何Qt版本,支持mingw、msvc、gcc等编译器,支持任意操作系统比如windows+linux+mac+嵌入式linux等,不乱码,可直接集成到Qt Creator中,和自带的控件一样使用,大部分效果只要设置几个属性即可,极为方便。
  4. 每个控件都有一个对应的单独的包含该控件源码的DEMO,方便参考使用。同时还提供一个所有控件使用的集成的DEMO。
  5. 每个控件的源代码都有详细中文注释,都按照统一设计规范编写,方便学习自定义控件的编写。
  6. 每个控件默认配色和demo对应的配色都非常精美。
  7. 超过130个可见控件,6个不可见控件。
  8. 部分控件提供多种样式风格选择,多种指示器样式选择。
  9. 所有控件自适应窗体拉伸变化。
  10. 集成自定义控件属性设计器,支持拖曳设计,所见即所得,支持导入导出xml格式。
  11. 自带activex控件demo,所有控件可以直接运行在ie浏览器中。
  12. 集成fontawesome图形字体+阿里巴巴iconfont收藏的几百个图形字体,享受图形字体带来的乐趣。
  13. 所有控件最后生成一个动态库文件(dll或者so等),可以直接集成到qtcreator中拖曳设计使用。
  14. 目前已经有qml版本,后期会考虑出pyqt版本,如果用户需求量很大的话。
  15. 自定义控件插件开放动态库使用(永久免费),无任何后门和限制,请放心使用。
  16. 目前已提供32个版本的dll,其中qt_5_7_0_mingw530_32这个版本会一直保证最新的完整的。
  17. 不定期增加控件和完善控件,不定期更新SDK,欢迎各位提出建议,谢谢!
  18. Qt入门书籍推荐霍亚飞的《Qt Creator快速入门》《Qt5编程入门》,Qt进阶书籍推荐官方的《C++ GUI Qt4编程》。
  19. 强烈推荐程序员自我修养和规划系列书《大话程序员》《程序员的成长课》《解忧程序员》,受益匪浅,受益终生!
  20. SDK地址:https://gitee.com/feiyangqingyun/QUCSDK https://github.com/feiyangqingyun/qucsdk

Qt编写自定义控件63-水波效果的更多相关文章

  1. Qt编写自定义控件二动画按钮

    现在的web发展越来越快,很多流行的布局样式,都是从web开始的,写惯了Qt widgets 项目,很多时候想改进一下现有的人机交互,尤其是在现有的按钮上加一些动画的效果,例如鼠标移上去变大,移开还原 ...

  2. Qt编写自定义控件56-波浪曲线

    一.前言 波浪曲线控件,其实是之前一个水波进度条控件的一个核心,其实就是利用正弦曲线来生成对应的坐标进行绘制,把这个功能单独提取出来,是为了更详细的研究各种正弦余弦等拓展效果,当时写这个效果的时候,参 ...

  3. Qt编写自定义控件插件开放动态库dll使用(永久免费)

    这套控件陆陆续续完善了四年多,目前共133个控件,除了十几个控件参考网友开源的代码写的,其余全部原创,在发布之初就有打算将动态库开放出来永久免费使用,在控件比较完善的今天抽了半天时间编译了多个qt版本 ...

  4. Qt编写自定义控件11-设备防区按钮控件

    前言 在很多项目应用中,需要根据数据动态生成对象显示在地图上,比如地图标注,同时还需要可拖动对象到指定位置显示,能有多种状态指示,安防领域一般用来表示防区或者设备,可以直接显示防区号,有多种状态颜色指 ...

  5. Qt编写自定义控件10-云台仪表盘

    前言 做过安防视频监控的同学都清楚,在视频监控系统软件上都可以看到一个云台控制区域,可以对球机进行下下左右等八个方位的运动控制,还可以进行复位,一般都是美工作图好,然后贴图的形式加入到软件中,好处是程 ...

  6. Qt编写自定义控件9-导航按钮控件

    前言 导航按钮控件,主要用于各种漂亮精美的导航条,我们经常在web中看到导航条都非常精美,都是html+css+js实现的,还自带动画过度效果,Qt提供的qss其实也是无敌的,支持基本上所有的CSS2 ...

  7. Qt编写自定义控件8-动画按钮组控件

    前言 动画按钮组控件可以用来当做各种漂亮的导航条用,既可以设置成顶部底部+左侧右侧,还自带精美的滑动效果,还可以设置悬停滑动等各种颜色,原创作者雨田哥(QQ:3246214072),驰骋Qt控件界多年 ...

  8. Qt编写自定义控件7-自定义可拖动多边形

    前言 自定义可拖动多边形控件,原创作者是赵彦博(QQ:408815041 zyb920@hotmail.com),创作之初主要是为了能够在视频区域内用户自定义可拖动的多个区域,即可用来作为警戒区域,也 ...

  9. Qt编写自定义控件6-指南针仪表盘

    前言 指南针仪表盘,主要用来指示东南西北四个方位,双向对称两个指针旋转,其实就是360度打转,功能属于简单型,可能指针的绘制稍微难一点,需要计算多个点构成多边形,本系列控件文章将会连续发100+篇,一 ...

随机推荐

  1. DT7.0/6.0最简单实现主动推送方法

    最近研究destoon内核开发,开发了一个大型的信息站点:http://www.xuetong365.com/  但是新站如何提高收录和排名呢?网上有很多主动提交的方法,今天我分享一个自己原创的超级简 ...

  2. POJ3709 K-Anonymous Sequence

    题意 Language:Default K-Anonymous Sequence Time Limit: 4000MS Memory Limit: 65536K Total Submissions: ...

  3. map json 字符串 对象之间的相互转化

    1.对象与字符串之间的互转 将对象转换成为字符串 String str = JSON.toJSONString(infoDo); 字符串转换成为对象 InfoDo infoDo = JSON.pars ...

  4. 002——转载Excel2010分成两个或者多个独立窗口

    在借鉴了很多个baidu方法之后,使用修改注册表之后我的Excel终于可以独立窗口出来了.转自:www.xuexila.com/excel/2010/2051008.html方法如下: 本操作需要修改 ...

  5. mongodb 集群配置文件

    本文档是在mongodb为3.4下编写的,仅作为参考,详细内容请参考:https://docs.mongodb.com/manual/reference/configuration-options/# ...

  6. 问题--Notepad++保存文件遇到Failed to save file

    一.问题如下 使用Notepad编码,保存时遇到问题:Failed to save file. Not enough space on disk to save file? 如下图所示: 二.解决方法 ...

  7. 【一起来烧脑】一步学会Vue.js系统

    Vuejs是一个构建数据驱动的web界面的库,通过api实现响应的数据绑定和组合的视图组件,Vue.js的核心是一个响应的数据绑定系统,它让数据与DOM保持同步非常简单,一旦创建了绑定,DOM 将与数 ...

  8. secureCRT连接服务器和文件传输( 一步搞定)

    1.在百度云盘存有此工具,获取到后解压执行即可,如下2 连接目标服务器 192.xxx.xx.xx 2.secureCRT连接服务器和文件传输 ,现象如下 登录后切换到root用户即可有权限操作    ...

  9. Tkinter 之TopLevel顶级窗口

    一.参数说明 width  设置宽度 height  设置高度 background(bg) 设置背景颜色默认值由系统指定为了防止更新,可以将颜色值设置为空字符串 borderwidth(bd) 设置 ...

  10. winform如何不卡界面

    快速阅读 如何在winform程序中,让界面不再卡死. 关于委托和AsyncCallback的使用. 界面卡死的原因是因为耗时任务的计算占用了主线程,导致主界面没有办法进行其它操作,比如拖动.造成界面 ...