首页 > 编程学习 > C++/Win32实现波浪球效果及详细源码

C++/Win32实现波浪球效果及详细源码

发布时间:2022/11/6 22:51:15

C++/Win32波浪球效果

  • 简介
  • 原理
  • 功能
  • 源码
  • 使用
  • 参考demo

简介

这是一个基于C++在win32上实现的波浪球效果。它使用GDI+进行图形绘制,支持指定签名、动态百分比显示以及特殊项目的PASS/FAIL显示。

对其封装成了一个类,并开放了相关参数给用户设置,可以灵活使用。

项目github地址在这里,如果对你有帮助帮忙点个star哟。

部分效果图小如下:
wave_ball_show

原理

  1. 利用GDI+在内存DC上创建 一个画布,并填充背景颜色。
  2. 使用Pen在画布上画一个外层圆。
  3. 依靠公式 “振幅高sin(x振幅宽 + 振幅偏移量)”画出波浪。
  4. 使用DrawString画上署名或百分比进度。
  5. 使用DrawImage将内存DC输出到Dialog。

这里利用双缓存原理消除闪屏问题。双缓冲实现过程如下:

  1. 在内存中创建与画布一致的缓冲区。
  2. 在缓冲区画图。
  3. 将缓冲区位图拷贝到当前画布上。
  4. 释放内存缓冲区。

功能

没有添加构造函数和析构函数,后面会再做一次优化。

  1. WaveBallInit 初始化波浪球。
  2. ThreadDynamicWave 动态更新波浪,一般在一个线程或定时器中实时更新。
  3. WaveBallUpdateProgress 更新百分比显示和进度条,进度条会根据百分比进行自适应。
  4. WaveBallSetConstantWave 设置恒定进度状态,比如设为30%,则波浪一直在该状态下波动。
  5. WaveBallSetTextColor 允许设置波浪球中的文本颜色。
  6. WaveBallSetColor 允许设置波浪球的背景颜色。
  7. WaveBallSetText 设置波浪球的文本。
  8. WaveBallSetResult 设置PASS / FAIL 状态,应用一些特殊需要,比如进度达到100%后的状态显示。
  9. WaveBallSetAmplitude设置波浪球的波浪参数,根据不同的尺寸大小调整波浪。

源码

GdiplusWaveBall.cpp

#include "GdiplusWaveBall.h"
#include <process.h>
#include <strsafe.h>

/*****************************************************************************
*
* GET VALUE POINT: CreateOriginalBmp
*
*****************************************************************************/
Bitmap* FlyWaveBall::CreateOriginalBmp()
{
	HDC			hdc;
	REAL		nWidth, nHeight;
	Graphics	*baseGraph;
	Bitmap		*bmp;
	Graphics	*pGraphics;
	Pen			*myPen;
	SolidBrush	*blackBrush;
	REAL		strSize;
	INT			iStrLength;

	nHeight = 2 * (threadWavesMove.radius + 1);
	nWidth = 2 * (threadWavesMove.radius + 1);
	Gdiplus::RectF gdiRc(threadWavesMove.originalX,
		threadWavesMove.originalY,
		nWidth,
		nHeight);

	hdc = GetDC(threadWavesMove.hWnd);
	baseGraph = new Gdiplus::Graphics(hdc);
	bmp = new Bitmap((int)nWidth, (int)nHeight);
	for (int i = 0; i < nWidth; i++)
	{
		for (int j = 0; j < nHeight; j++)
		{
			bmp->SetPixel(i, j, threadWavesMove.colorOriginal);
		}
	}
	pGraphics = Graphics::FromImage(bmp);

	pGraphics->SetSmoothingMode(SmoothingModeHighQuality);
	myPen = new Pen(threadWavesMove.colorWaveBall, 1);
	pGraphics->DrawEllipse(myPen, 0.0f, 0.0f, 2 * threadWavesMove.radius, 2 * threadWavesMove.radius);
	strSize = 2 * threadWavesMove.radius / 5;
	//WaveBallSetText(threadWavesMove.hWnd, threadWavesMove.colorWaveBall, AUTOGRAPH, lstrlen(AUTOGRAPH), (REAL)2 * threadWavesMove.radius / 5);
	Font myFont(TEXT("Arial"), strSize);
	iStrLength = lstrlen(AUTOGRAPH);
	blackBrush = new SolidBrush(threadWavesMove.colorWaveBall);
	pGraphics->DrawString(AUTOGRAPH, iStrLength, &myFont,
		PointF(threadWavesMove.radius - (strSize / 3)*iStrLength - 7,
			threadWavesMove.radius - 2 * strSize / 3),
		blackBrush);

	baseGraph->DrawImage(bmp, gdiRc, 0.0f, 0.0f, nWidth, nHeight, UnitPixel);

	delete(myPen);
	delete(blackBrush);
	delete(pGraphics);
	delete(baseGraph);
	DeleteDC(hdc);

	return bmp;
}
/*****************************************************************************
*
* GET VALUE POINT: WaveBallInit
*
* Function: Initialize wave ball
*
*****************************************************************************/
VOID FlyWaveBall::WaveBallInit(
	IN HWND hWnd,
	IN Gdiplus::Color &color,
	IN Gdiplus::Color &colorOriginal,
	IN REAL x,
	IN REAL y,
	IN REAL radius)
{
	memset(&threadWavesMove, 0, sizeof(ThreadParam));
	threadWavesMove.bConstantWave = FALSE;
	threadWavesMove.hWnd = hWnd;
	threadWavesMove.originalX = x;
	threadWavesMove.originalY = y;
	threadWavesMove.colorWaveBall = color;
	threadWavesMove.colorOriginal = colorOriginal;
	threadWavesMove.colorText = Color(255, 255, 235, 205);
	threadWavesMove.percentage = 0;
	threadWavesMove.radius = radius;

	amplitudeHigh = 1.0;
	amplitudeWidth = 0.08f;
	amplitudeOffset = 6.0;

	bResult = TRUE;
	lstrcpyn(strText, AUTOGRAPH, sizeof(strText) / sizeof(strText[0]));

	//bmpOriginal = CreateOriginalBmp();

}
/*****************************************************************************
*
* GET VALUE POINT: ThreadDynamicWave
*
* Function: Make the waves move
*
*****************************************************************************/
VOID FlyWaveBall::ThreadDynamicWave(int	offset)
{
	if (threadWavesMove.percentage <= 0)
	{
		WaveBallRedrawCircle();
		return;
	}
	else if (threadWavesMove.percentage >= 1)
	{
		ShowResult();
		return;
	}

	HDC			hdc;
	REAL		nWidth, nHeight;
	Graphics	*baseGraph;
	Bitmap		*bmp;
	Graphics	*pGraphics;
	Pen			*myPen;
	SolidBrush	*blackBrush;
	REAL		strSize;
	/***********************/
	float			sX, sY;			// start X/Y
	float			x, y;
	int				count;
	//int				offset;
	float			iCircularInterval = 3;
	PointF			points[MAX_POINT];
	Brush			*brush;
	Brush			*brushOriginal;
	float			centerX, centerY;
	TCHAR			strText[128];

	nHeight = 2 * (threadWavesMove.radius + 1);
	nWidth = 2 * (threadWavesMove.radius + 1);
	Gdiplus::RectF gdiRc(threadWavesMove.originalX,
		threadWavesMove.originalY,
		nWidth,
		nHeight);
	bmp = new Bitmap((int)nWidth, (int)nHeight);
	pGraphics = Graphics::FromImage(bmp);
	pGraphics->SetSmoothingMode(SmoothingModeHighQuality);
	hdc = GetDC(threadWavesMove.hWnd);
	baseGraph = new Gdiplus::Graphics(hdc);

	// 初始化画布
	for (int i = 0; i < nWidth; i++)
	{
		for (int j = 0; j < nHeight; j++)
		{
			bmp->SetPixel(i, j, threadWavesMove.colorOriginal);
		}
	}

	strSize = 2 * threadWavesMove.radius / 5;
	Font myFont(TEXT("Arial"), strSize);
	blackBrush = new SolidBrush(threadWavesMove.colorText);
	myPen = new Pen(threadWavesMove.colorWaveBall, 1);

	sX = 0.0f;
	centerX = threadWavesMove.radius;
	centerY = threadWavesMove.radius;
	brush = new SolidBrush(threadWavesMove.colorWaveBall);
	brushOriginal = new SolidBrush(threadWavesMove.colorOriginal);
	//offset = 0;

	sY = 2 * threadWavesMove.radius*(1 - threadWavesMove.percentage);
	count = 0;
	for (x = sX; x < (int)sX + MAX_POINT; x += 1.0f) 
	{
		//此处坐标(x,y)的取点,依靠公式 “振幅高*sin(x*振幅宽 + 振幅偏移量)”

		// The point of coordinates (x, y) here depends on the formula 
		// "amplitude height * sin (x * amplitude width+amplitude offset)"
		if (threadWavesMove.percentage < 0.1)
			y = threadWavesMove.percentage*(float)sin((sX + x) * 0.08 - offset*PI / 6);
		else if (threadWavesMove.percentage > 0.9)
			y = (float)(fabs(threadWavesMove.percentage - 1)*sin((sX + x) * 0.08 - offset*PI / 6));
		else
			y = amplitudeHigh*(float)sin((sX + x) * amplitudeWidth - offset*PI / amplitudeOffset);// 4,0.02,6
		

		//TIS_Trace(TEXT("x,y:%f,%f\n"), x, sY + y * 5);
		if (IsPointInCircle(x, sY + y * 5, centerX, centerY, threadWavesMove.radius - iCircularInterval))
		{
			points[count] = Gdiplus::PointF(x, (sY + y * 5));
			count++;
		}
		if (count >= MAX_POINT || x > (centerX + threadWavesMove.radius))
			break;
	}

	// 绘制圆形
	pGraphics->DrawEllipse(myPen, 0.0f, 0.0f, 2 * threadWavesMove.radius, 2 * threadWavesMove.radius);

	if (threadWavesMove.percentage > 0.95f)
	{
		pGraphics->FillEllipse(brush,
			iCircularInterval,//x
			iCircularInterval,//y
			2 * (threadWavesMove.radius - iCircularInterval),
			2 * (threadWavesMove.radius - iCircularInterval));

	}
	else if (count > 0)
	{
		double startAngle = (atan((points[count - 1].Y - centerY) / (points[count - 1].X - centerX)) * 180 / PI);
		double endAngle = 180 + (atan((points[1].Y - centerY) / (points[1].X - centerX)) * 180 / PI);
		//TIS_Trace(TEXT("Angle:%d,%d\n"), startAngle, endAngle);
		for (; startAngle<endAngle; startAngle += 1.0f)
		{

			if (startAngle > 0 && startAngle < 90) // 4 quadrant
			{
				points[count] = Gdiplus::PointF(centerX + threadWavesMove.radius * (float)cos(startAngle* PI / 180) - iCircularInterval,
					centerY + threadWavesMove.radius * (float)sin(startAngle* PI / 180) - iCircularInterval);
			}
			else if (startAngle > 90 && startAngle < 180)// 3 quadrant
			{
				points[count] = Gdiplus::PointF(centerX + threadWavesMove.radius * (float)cos(startAngle* PI / 180) + iCircularInterval,
					centerY + threadWavesMove.radius * (float)sin(startAngle* PI / 180) - iCircularInterval);
			}
			else if (startAngle>180 && startAngle < 270)// 2 quadrant
			{
				points[count] = Gdiplus::PointF(centerX + threadWavesMove.radius * (float)cos(startAngle* PI / 180) + iCircularInterval,
					centerY + threadWavesMove.radius * (float)sin(startAngle* PI / 180) + iCircularInterval);
			}
			else if (startAngle>270 || startAngle <0)// 1 quadrant
			{
				points[count] = Gdiplus::PointF(centerX + threadWavesMove.radius * (float)cos(startAngle* PI / 180) - iCircularInterval,
					centerY + threadWavesMove.radius * (float)sin(startAngle* PI / 180) + iCircularInterval);
			}
			else if (startAngle == 0)// 0
			{
				points[count] = Gdiplus::PointF(centerX + threadWavesMove.radius * (float)cos(startAngle* PI / 180) - iCircularInterval,
					centerY + threadWavesMove.radius * (float)sin(startAngle* PI / 180));
			}
			else if (startAngle == 90) // 90
			{
				points[count] = Gdiplus::PointF(centerX + threadWavesMove.radius * (float)cos(startAngle* PI / 180),
					centerY + threadWavesMove.radius * (float)sin(startAngle* PI / 180) - iCircularInterval);
			}
			else if (startAngle == 180) //180
			{
				points[count] = Gdiplus::PointF(centerX + threadWavesMove.radius * (float)cos(startAngle* PI / 180) + iCircularInterval,
					centerY + threadWavesMove.radius * (float)sin(startAngle* PI / 180));
			}
			else //270
			{
				points[count] = Gdiplus::PointF(centerX + threadWavesMove.radius * (float)cos(startAngle* PI / 180) - iCircularInterval,
					centerY + threadWavesMove.radius * (float)sin(startAngle* PI / 180));
			}
			count++;
		}

		// Draw wave ball
		pGraphics->FillClosedCurve(brush, points, count);
	}

	// Set text.
	if (!threadWavesMove.bConstantWave)
		swprintf_s(strText, TEXT("%.1f%%"), threadWavesMove.percentage * 100);
	else
		lstrcpy(strText, AUTOGRAPH);
	// Draw String
	pGraphics->DrawString(strText, lstrlen(strText), &myFont,
		PointF(threadWavesMove.radius - (strSize / 3)*lstrlen(strText) - 7,
			threadWavesMove.radius - 2 * strSize / 3),
		blackBrush);
	// Draw memory DC to Dialog
	baseGraph->DrawImage(bmp, gdiRc, 0.0f, 0.0f, nWidth, nHeight, UnitPixel);


	delete(brushOriginal);
	delete(brush);
	delete(myPen);
	delete(blackBrush);
	delete(pGraphics);
	delete(baseGraph);
	delete(bmp);
	DeleteDC(hdc);

}
/*****************************************************************************
*
* GET VALUE POINT: IsPointInCircle
*
*****************************************************************************/
BOOL FlyWaveBall::IsPointInCircle(double x, double y, double CenterX, double CenterY, double radius)
{
	//到圆心的距离 是否大于半径。半径是R  
	//如O(x,y)点圆心,任意一点P(x1,y1) (x-x1)*(x-x1)+(y-y1)*(y-y1)>R*R 那么在圆外 反之在圆内
	double r = radius;
	double x1 = x;
	double y1 = y;



	if (!((CenterX - x1)*(CenterX - x1) + (CenterY - y1)*(CenterY - y1) > r*r))
	{
		return true;        //当前点在圆内
	}
	else
	{
		return false;       //当前点在圆外
	}
}
/*****************************************************************************
*
* GET VALUE POINT: WaveBallRedrawCircle
*
* Function: Erase fill.Redraw waveball
*
*****************************************************************************/
BOOL FlyWaveBall::WaveBallRedrawCircle()
{
	HDC			hdc;
	REAL		nWidth, nHeight;
	Graphics	*baseGraph;
	Bitmap		*bmp;
	Graphics	*pGraphics;
	Pen			*myPen;
	SolidBrush	*blackBrush;
	REAL		strSize;
	INT			iStrLength;

	nHeight = 2 * (threadWavesMove.radius + 1);
	nWidth = 2 * (threadWavesMove.radius + 1);
	Gdiplus::RectF gdiRc(threadWavesMove.originalX,
		threadWavesMove.originalY,
		nWidth,
		nHeight);

	hdc = GetDC(threadWavesMove.hWnd);
	baseGraph = new Gdiplus::Graphics(hdc);
	bmp = new Bitmap((int)nWidth, (int)nHeight);
	for (int i = 0; i < nWidth; i++)
	{
		for (int j = 0; j < nHeight; j++)
		{
			bmp->SetPixel(i, j, threadWavesMove.colorOriginal);
		}
	}
	pGraphics = Graphics::FromImage(bmp);

	pGraphics->SetSmoothingMode(SmoothingModeHighQuality);
	myPen = new Pen(threadWavesMove.colorWaveBall, 1);
	pGraphics->DrawEllipse(myPen, 0.0f, 0.0f, 2 * threadWavesMove.radius, 2 * threadWavesMove.radius);
	strSize = 2 * threadWavesMove.radius / 5;
	//WaveBallSetText(threadWavesMove.hWnd, threadWavesMove.colorWaveBall, AUTOGRAPH, lstrlen(AUTOGRAPH), (REAL)2 * threadWavesMove.radius / 5);
	Font myFont(TEXT("Arial"), strSize);
	iStrLength = lstrlen(strText);
	blackBrush = new SolidBrush(threadWavesMove.colorWaveBall);
	pGraphics->DrawString(strText, iStrLength, &myFont,
		PointF(threadWavesMove.radius - (strSize / 3)*iStrLength - 7,
			threadWavesMove.radius - 2 * strSize / 3),
		blackBrush);

	baseGraph->DrawImage(bmp, gdiRc, 0.0f, 0.0f, nWidth, nHeight, UnitPixel);

	delete(myPen);
	delete(blackBrush);
	delete(pGraphics);
	delete(bmp);
	delete(baseGraph);
	DeleteDC(hdc);

	return TRUE;
}
/*****************************************************************************
*
* GET VALUE POINT: WaveBallSetText
*
* Function: Set wave ball text
*
*****************************************************************************/
VOID FlyWaveBall::WaveBallUpdateProgress(IN REAL	percentage)
{
	if (percentage>1)
		threadWavesMove.percentage = 1;
	else if (percentage<0)
		threadWavesMove.percentage = 0;
	else
		threadWavesMove.percentage = percentage;
}
/*****************************************************************************
*
* GET VALUE POINT: WaveBallSetSpeed
*
* Function: Set wave ball speed. Milliseconds.
*
*****************************************************************************/
VOID FlyWaveBall::WaveBallSetConstantWave(IN REAL percentage)
{
	threadWavesMove.bConstantWave = TRUE;
	threadWavesMove.percentage = percentage;
}
/*****************************************************************************
*
* GET VALUE POINT: WaveBallSetTextColor
*
* Function: Set wave ball text color.
*
*****************************************************************************/
VOID FlyWaveBall::WaveBallSetTextColor(IN Color	&color)
{
	threadWavesMove.colorText = color;
}
/*****************************************************************************
*
* GET VALUE POINT: CreateOriginalBmp
*
*****************************************************************************/
VOID FlyWaveBall::ShowResult()
{
	HDC			hdc;
	REAL		nWidth, nHeight;
	Graphics	*baseGraph;
	Bitmap		*bmp;
	Graphics	*pGraphics;
	Pen			*myPen;
	int			iOffset = 8;

	nHeight = 2 * (threadWavesMove.radius + 1);
	nWidth = 2 * (threadWavesMove.radius + 1);
	Gdiplus::RectF gdiRc(threadWavesMove.originalX,
		threadWavesMove.originalY,
		nWidth,
		nHeight);

	hdc = GetDC(threadWavesMove.hWnd);
	baseGraph = new Gdiplus::Graphics(hdc);
	bmp = new Bitmap((int)nWidth, (int)nHeight);
	for (int i = 0; i < nWidth; i++)
	{
		for (int j = 0; j < nHeight; j++)
		{
			bmp->SetPixel(i, j, threadWavesMove.colorOriginal);
		}
	}
	pGraphics = Graphics::FromImage(bmp);

	pGraphics->SetSmoothingMode(SmoothingModeHighQuality);
	

	if (bResult)
	{// PASS
		myPen = new Pen(Color(255, 0, 255, 0), 2* (float)iOffset);
		pGraphics->DrawLine(myPen, 
			Point(iOffset, (int)nHeight/2 + iOffset),
			Point((int)nWidth/2, (int)nHeight - iOffset)
		);
		pGraphics->DrawLine(myPen,
			Point((int)nWidth - iOffset,5 * iOffset),
			Point((int)nWidth / 2 -(iOffset+1), (int)nHeight -(iOffset+1))
		);
	}
	else
	{// FAIL
		myPen = new Pen(Color(255, 255, 0, 0), 2 * (float)iOffset);
		pGraphics->DrawLine(myPen,
			Point(0, 0),
			Point((int)nWidth, (int)nHeight)
		);
		pGraphics->DrawLine(myPen,
			Point((int)nWidth, 0),
			Point(0, (int)nHeight)
		);
	}

	baseGraph->DrawImage(bmp, gdiRc, 0.0f, 0.0f, nWidth, nHeight, UnitPixel);

	delete(myPen);
	delete(pGraphics);
	delete(bmp);
	delete(baseGraph);
	DeleteDC(hdc);

}
/*****************************************************************************
*
* ENTRY POINT: WaveBallSetText
*
*****************************************************************************/
VOID FlyWaveBall::WaveBallSetText(TCHAR * string)
{
	lstrcpyn(strText, string, sizeof(strText) / sizeof(strText[0]));
}
/*****************************************************************************
*
* ENTRY POINT: WaveBallSetText
*
*****************************************************************************/
VOID FlyWaveBall::WaveBallSetResult(BOOL result)
{
	bResult = result;
}
/*****************************************************************************
*
* ENTRY POINT: WaveBallSetColor
*
*****************************************************************************/
VOID FlyWaveBall::WaveBallSetColor(IN Color	&color)
{
	threadWavesMove.colorWaveBall = color;
}

/*****************************************************************************
*
* ENTRY POINT: WaveBallSetText
*
*****************************************************************************/
VOID FlyWaveBall::WaveBallSetAmplitude(float High, float Width, float Offset)
{
	if (High > 0)
		amplitudeHigh = High;
	if (Width > 0)
		amplitudeWidth = Width;

	amplitudeOffset = Offset;
}

GdiplusWaveBall.h

#ifndef _FLY_GDIPLUS_WAVE_BALL_H_
#define _FLY_GDIPLUS_WAVE_BALL_H_

#include <windows.h>
// GDI+
#include <gdiplus.h> 
#pragma comment (lib, "GdiPlus.lib")
using namespace Gdiplus;



class FlyWaveBall
{
public:
	//FlyWaveBall();
	//~FlyWaveBall();
	VOID WaveBallInit(
		IN HWND hWnd,
		IN Gdiplus::Color &color,
		IN Gdiplus::Color &colorOriginal,
		IN REAL x,
		IN REAL y,
		IN REAL radius);
	VOID ThreadDynamicWave(int offset);
	VOID WaveBallUpdateProgress(IN REAL	percentage);
	VOID WaveBallSetConstantWave(IN REAL percentage);
	VOID WaveBallSetTextColor(IN Color	&color);
	VOID WaveBallSetColor(IN Color	&color);
	VOID WaveBallSetText(TCHAR * string);
	VOID WaveBallSetResult(BOOL result);
	VOID WaveBallSetAmplitude(float High, float Width, float amplitudeOffset);
private:
#define PI			3.141592654
#define MAX_POINT	1024
#define AUTOGRAPH	TEXT("FLY.")
	typedef struct ThreadParameters
	{
		HWND	hWnd;
		REAL	originalX;
		REAL	originalY;
		REAL	radius;
		REAL	percentage;
		Color	colorWaveBall;
		Color	colorOriginal;
		Color	colorText;
		BOOL	bConstantWave;
	}ThreadParam;

	Bitmap* CreateOriginalBmp();
	BOOL WaveBallRedrawCircle();
	VOID ShowResult();
	BOOL IsPointInCircle(
		double x, 
		double y, 
		double CenterX, 
		double CenterY, 
		double radius);

	ThreadParam threadWavesMove;
	BOOL	bResult;
	TCHAR	strText[16];

	float amplitudeHigh;

	float amplitudeWidth;

	float amplitudeOffset;
};

#endif

使用

一般步骤:

  1. 创建FlyWaveBall类。
  2. 使用该类中的WaveBallInit 初始化波浪球。
  3. 根据需要使用该类的WaveBallSetAmplitude设置波浪球的波浪参数。
  4. 创建一个定时器或线程使用该类的ThreadDynamicWave 动态更新波浪。
  5. 其他根据需要进行设置。

只需要包含了头文件GdiplusWaveBall.h和添加gdi+库即可使用该类;详情可以参考Demo。

// GDI+
#include <gdiplus.h> 
#pragma comment (lib, "GdiPlus.lib")
using namespace Gdiplus;

// Wave ball
#include "./WaveBallApi/GdiplusWaveBall.h"

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{ 

	//Initialize GDI+.
	Gdiplus::GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

	// other code

	//Unload GDI+
	Gdiplus::GdiplusShutdown(gdiplusToken);

	return 0; 
} 

波浪球的速度和进度可以在线程或者定时器中更新。

// 在定时器中更新波浪,定时的长短决定了波浪球的波浪速度,建议使用线程效果比较好。
static VOID CALLBACK CallBackTimer(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
	static int iWaveBallOffset = 0;
	switch (idEvent)
	{
	case TIMER_ID_WAVEBALL:
		mWaveBall.ThreadDynamicWave(iWaveBallOffset);
		if (++iWaveBallOffset > 12)
			iWaveBallOffset = 0;
		break;
	default:
		break;
	}
}

参考demo

#include <windows.h> 
#include <commctrl.h>
#pragma comment (lib,"comctl32.lib")

// GDI+
#include <gdiplus.h> 
#pragma comment (lib, "GdiPlus.lib")
using namespace Gdiplus;

// Wave ball
#include "./WaveBallApi/GdiplusWaveBall.h"

#define COLOR_RGB_DLG_BG	RGB(115, 141, 141)
// Wave ball color
#define COLOR_GDI_WAVEBALL	Color(255, 249, 205, 173)
#define COLOR_GDI_DLG_BG	Color(255, 115, 141, 141)

#define TIMER_ID_WAVEBALL	1
#define TIMER_TIME_SEC		1000
#define TIMER_TIME_300MS	300

static FlyWaveBall mWaveBall;


INT_PTR CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); 
static VOID CALLBACK CallBackTimer(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime);

/*****************************************************************************
*
* ENTRY POINT: WinMain
*
*****************************************************************************/
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{ 

	//Initialize GDI+.
	Gdiplus::GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

	InitCommonControls();
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)MyDlgProc); 

	//Unload GDI+
	Gdiplus::GdiplusShutdown(gdiplusToken);

	return 0; 
} 




/*****************************************************************************
*
* ENTRY POINT: MyDlgProc
*
*****************************************************************************/
INT_PTR CALLBACK MyDlgProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) 
{ 
	static HBRUSH	hBsh;

	switch (msg) { 
    case WM_INITDIALOG:
        SetWindowText(hWnd, MODELNAME);
		// Set dialog background
		hBsh = CreateSolidBrush(COLOR_RGB_DLG_BG);

		// wave ball
		mWaveBall.WaveBallInit(hWnd, COLOR_GDI_WAVEBALL, COLOR_GDI_DLG_BG, 70, 38, 160);
		mWaveBall.WaveBallSetText(L"FLY.");
		mWaveBall.WaveBallSetConstantWave(0.3f);
		mWaveBall.WaveBallSetAmplitude(4.0, 0.02f, 6.0);

		SetTimer(hWnd, TIMER_ID_WAVEBALL, TIMER_TIME_300MS, (TIMERPROC)CallBackTimer);

		

        break;
	case WM_COMMAND: 
		switch (LOWORD(wp)) { 
		case IDOK: 
			
			break;
		case IDCANCEL: 
			EndDialog(hWnd, 0); 
			return TRUE; 
		} 
	case WM_CTLCOLORDLG:
		// Returns a brush to create a dialog background color  
		return (INT_PTR)hBsh;
		break;
	} 
	return FALSE; 
} 

/******************************************************************************
*
* ENTRY POINT: CallBackTimer
*
* Function: Timer call back
*
******************************************************************************/
static VOID CALLBACK CallBackTimer(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
	static int iWaveBallOffset = 0;
	switch (idEvent)
	{
	case TIMER_ID_WAVEBALL:
		mWaveBall.ThreadDynamicWave(iWaveBallOffset);
		if (++iWaveBallOffset > 12)
			iWaveBallOffset = 0;
		break;
	default:
		break;
	}
}

项目github地址在这里,如果对你有帮助帮忙点个star哟。

Copyright © 2010-2022 dgrt.cn 版权所有 |关于我们| 联系方式