简介
这是一个基于C++在win32上实现的波浪球效果。它使用GDI+进行图形绘制,支持指定签名、动态百分比显示以及特殊项目的PASS/FAIL显示。
对其封装成了一个类,并开放了相关参数给用户设置,可以灵活使用。
项目github地址在这里,如果对你有帮助帮忙点个star哟。
部分效果图小如下:
原理
- 利用GDI+在内存DC上创建 一个画布,并填充背景颜色。
- 使用Pen在画布上画一个外层圆。
- 依靠公式 “振幅高sin(x振幅宽 + 振幅偏移量)”画出波浪。
- 使用DrawString画上署名或百分比进度。
- 使用DrawImage将内存DC输出到Dialog。
这里利用双缓存原理消除闪屏问题。双缓冲实现过程如下:
- 在内存中创建与画布一致的缓冲区。
- 在缓冲区画图。
- 将缓冲区位图拷贝到当前画布上。
- 释放内存缓冲区。
功能
没有添加构造函数和析构函数,后面会再做一次优化。
- WaveBallInit 初始化波浪球。
- ThreadDynamicWave 动态更新波浪,一般在一个线程或定时器中实时更新。
- WaveBallUpdateProgress 更新百分比显示和进度条,进度条会根据百分比进行自适应。
- WaveBallSetConstantWave 设置恒定进度状态,比如设为30%,则波浪一直在该状态下波动。
- WaveBallSetTextColor 允许设置波浪球中的文本颜色。
- WaveBallSetColor 允许设置波浪球的背景颜色。
- WaveBallSetText 设置波浪球的文本。
- WaveBallSetResult 设置PASS / FAIL 状态,应用一些特殊需要,比如进度达到100%后的状态显示。
- 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
使用
一般步骤:
- 创建FlyWaveBall类。
- 使用该类中的WaveBallInit 初始化波浪球。
- 根据需要使用该类的WaveBallSetAmplitude设置波浪球的波浪参数。
- 创建一个定时器或线程使用该类的ThreadDynamicWave 动态更新波浪。
- 其他根据需要进行设置。
只需要包含了头文件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哟。