65.9K
CodeProject 正在变化。 阅读更多。
Home

一个曼德勃罗特集探器/缩放器,带有朱利亚集漫游

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (5投票s)

2010年5月10日

CPOL

2分钟阅读

viewsIcon

25860

downloadIcon

341

一个曼德勃罗特集探器/缩放器,带有朱利亚集漫游

引言

这个简单的应用程序和文章演示了 Windows 消息处理和在 Win32 设备上下文中进行绘制。设备上下文是一个结构体,它定义了一组图形对象及其相关属性,以及影响输出的图形模式。

图形对象包括用于绘制线条的画笔、用于绘画和填充的刷子、用于复制或滚动屏幕部分的位图、用于定义可用颜色集的调色板、用于剪切和其他操作的区域。

我们将首先声明我们的变量。

//*********************************************************************
//* Defines                                                           *
//*********************************************************************

#define  pi 3.1415926
#define  WIDTH 400
#define  HEIGHT 400
#define  WEXT 380
#define  HEXT 210
#define  MAGNITUDE_CUTOFF 100
#define  NUMCOLOURS 256
#define  ID_TIMER 1
#define  DIVFACTOR 1

#define  XMin   -1.4
#define  XMax    1.4
#define  YMin   -1.4
#define  YMax    1.4
#define  Iter   32
#define  Scal   32767
#define  ResX 150
#define  ResY 150

// **************************************************************************
// **                      Global Variables                                **
// **************************************************************************

bool xorDone=false;
char title[]="MandelZoom / Julia Walkabout      by Topcoder",buffer[80],String[40];
int max_iterations,mousex,mousey,xorEx=0,xorEy=0,MouseX,MouseY;
double xmin = -2.10, xmax = 0.75, ymin = -1.5 , ymax = 1.5;
double  width_fact, height_fact;
double midx,midy,dx,dy;
double dxx,dyy,px,py,zsx,zsy,zex,zey;
int xp,yp,random=0;
float jdx=0,jdy=0,r=0,theta=0,jx=0,jy=0,tempx,tempy;
rektangel rekt;
POINT start,end;
HDC hdc;
HWND Button[2],Edit,StatusBar;

HDC          hdcMem;
HBITMAP      hbmMem;
HANDLE       hOld;
RECT rect;
HBRUSH hbrush = CreateSolidBrush(RGB(0,0,128));

然后我们使用 RegisterClassEx() 注册我们的窗口。

int WINAPI WinMain (HINSTANCE hinst, HINSTANCE hprevinst, LPSTR lpCmdLine,int cmdShow)
{
	if (hprevinst == NULL)
	{
		WNDCLASSEX wclass;
		wclass.cbSize = sizeof(WNDCLASSEX);
		wclass.hInstance = hinst;
		wclass.lpfnWndProc = (WNDPROC)WndProc;
		wclass.style = CS_HREDRAW | CS_VREDRAW;
		wclass.hIcon = LoadIcon(hinst, IDC_ARROW);
		wclass.hIconSm = NULL;
		wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
		wclass.lpszMenuName = NULL;
		wclass.cbClsExtra = 0;
		wclass.cbWndExtra = 0;
		wclass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
		wclass.lpszClassName = "BASIC2";

		if(!RegisterClassEx(&wclass))   return 0;

然后我们使用 CreateWindowEx()ShowWindow() 创建实际的窗口并显示它。

HWND hwnd = CreateWindowEx(
	WS_EX_WINDOWEDGE,   // extended window style
	"BASIC2",           // registered class name
	title,              // window name
	WS_OVERLAPPEDWINDOW,// window style
	CW_USEDEFAULT,      // horizontal position of window
	CW_USEDEFAULT,      // vertical position of window
	WIDTH+WEXT,		    // window width
	HEIGHT+32,	        // window height
	NULL,				// handle to parent or owner window
	NULL,				// menu handle or child identifier
	hinst,				// handle to application instance
	NULL);				// window-creation data

	ShowWindow(hwnd, cmdShow);
	UpdateWindow(hwnd); 

现在,我们使用以下代码启动 Win32 消息循环。Windows 应用程序处理来自操作系统的消息,并且大多数 Win32 应用程序必须能够转换和分派窗口消息。

现在我们可以使用 TranslateMessage()DispatchMessage() 发送和接收窗口消息。

while (GetMessage(&msg, NULL, 0, 0))
{
	TranslateMessage (&msg) ;
	DispatchMessage(&msg);	// send the message to the window proc
}

return msg.wParam;

}//  End int WINAPI WinMain ( 

WM_CREATE 消息

当应用程序正在创建和实例化时,会调用 WM_CREATE 消息。在此代码部分,使用 CreateWindow() 函数创建控件,例如按钮、列表框和组合框。

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	 	switch(msg)
	 	{

case WM_CREATE:
	Button[0] = CreateWindow (
		"button",
		"reset",
		WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
		WIDTH+5,		//Button position x
		 HEIGHT-48,  	//Button position y
		 WIDTH/2, 	//Button Dimension x
		 30,  		//Button Dimension y
		 hwnd,
		 (HMENU) 5 ,
		 ((LPCREATESTRUCT) lparam)->hInstance,
		NULL);

	Button[1] = CreateWindow (
		"button",
		"Exit",
		WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
		WIDTH+(WIDTH/2)+5,	//Button position x
		 HEIGHT-48,  	//Button position y
		 (WIDTH/2)-48, 	//Button Dimension x
		 30,  		//Button Dimension y
		 hwnd,
		 (HMENU) 6,
		 ((LPCREATESTRUCT) lparam)->hInstance,
		NULL);

	   SetTimer(hwnd,ID_TIMER,1,NULL);
break;

WM_PAINT 消息

如果应用程序的某个区域需要更新,则会调用 WM_PAINT 消息
我们将把我们的绘制和更新函数放在这个代码部分。

case WM_PAINT:
	Paint(hwnd);
	initWalk();
	putCursor();
	walkabout();
break;

WM_LBUTTONDOWN 消息

当按下左键时,会调用 WM_LBUTTONDOWN 消息。当用户按下左鼠标按钮时,我们的应用程序将鼠标的当前 x 和 y 坐标存储在变量 start.xstart.y 中。当用户拖动鼠标时,会绘制一个矩形,它定义了要缩放的曼德勃罗特集区域的大小。

case WM_LBUTTONDOWN:
{
	if (mouse_x>=0 && mouse_x<=WIDTH && mouse_y>=0 && mouse_y<=HEIGHT)
	{
		rekt.visa = true;
		rekt.sx = (float)mouse_x;
		rekt.sy = (float)mouse_y;
		rekt.ex = (float)mouse_x;
		rekt.ey = (float)mouse_y;

		xorEx=(int)rekt.sx+100;
		xorEy=(int)rekt.sy+100;
		end.x=0;
		end.y=0;
		start.x=mouse_x;
		start.y=mouse_y;
		MoveToEx (hdc, start.x, start.y, NULL) ;

		zsx=(xmin+(xmax-xmin)*((mousex)-px)/(WIDTH-1));
		zsy=(ymin+(ymax-ymin)*((mousey)-py)/(HEIGHT-1));
		zex=(xmin+(xmax-xmin)*((mousex)-px)/(WIDTH-1));
		zey=(ymin+(ymax-ymin)*((mousey)-py)/(HEIGHT-1));

		tempx=xmin;
		tempy=ymin;
		xmin=zsx;
		ymin=zsy;

		textout();
	}
} break; 

WM_MOUSEMOVE 消息

当用户拖动鼠标时,会调用 WM_MOUSEMOVE 消息。当鼠标被拖动时,会绘制一个矩形框以显示下一个缩放区域将在哪里。

case WM_MOUSEMOVE:
{
	if (mouse_x>=0 && mouse_x<=WIDTH && mouse_y>=0 && mouse_y<=HEIGHT)
	{
		if (mouse_x>=rekt.sx && mouse_y >=rekt.sy )
		{
			rekt.ex = (float)mouse_x;
			rekt.ey = (float)mouse_y;
			dx=zex-zsx;
			dy=zey-zsy;
		}

		if (rekt.visa )
		{
			BitBlt(hdc, 0, 0, WIDTH, HEIGHT, hdcMem, 0, 0, SRCCOPY);
			SetROP2(hdc,R2_NOTXORPEN);
			int DrawMode = GetROP2(hdc);
			MoveToEx (hdc, (int)rekt.sx, (int)rekt.sy, NULL) ;
			LineTo (hdc, (int)rekt.ex ,(int)rekt.sy) ;
			LineTo (hdc, (int)rekt.ex ,(int)rekt.ey) ;
			LineTo (hdc, (int)rekt.sx ,(int)rekt.ey) ;
			LineTo (hdc, (int)rekt.sx ,(int)rekt.sy) ;
			SetROP2(hdc,R2_COPYPEN);

		}
	mousex=mouse_x;
	mousey=mouse_y;
	textout();
	}

} break; 

WM_LBUTTONUP 消息

当释放左键时,会调用 WM_LBUTTONUP 消息。一旦用户释放左鼠标按钮,我们的应用程序会将鼠标的当前 x 和 y 坐标存储在变量 end.xend.y 中。我们的应用程序现在计算用于计算曼德勃罗特集的新插值。

case WM_LBUTTONUP:
{
	if (mouse_x>=0 && mouse_x<=WIDTH && mouse_y>=0 && mouse_y<=HEIGHT)
	{

		rekt.visa = false;
		end.x=mouse_x;
		end.y=mouse_y;
		rekt.ex =(float)mousex;
		rekt.ey =(float)mousey;
		if (end.x >start.x+5 && end.y >start.y +5)
		{

			// Free-up the off-screen DC
			initWalk();
			MouseX=WIDTH/2;
			MouseY=HEIGHT/2;

			SelectObject(hdcMem, hOld);
			DeleteObject(hbmMem);
			DeleteDC(hdcMem);

			dx=zex-zsx;
			dy=zey-zsy;

			if (mouse_x>=rekt.sx && mouse_y >=rekt.sy )
			{
				zex=(xmin+(xmax-xmin)*((mousex)-px)/(WIDTH-1));
				zey=(ymin+(ymax-ymin)*((mousey)-py)/(HEIGHT-1));

				xmax=zex;
				ymax=zey;
				dx=zex-zsx;
				dy=zey-zsy;
				textout();
				//if (rekt.sx!=rekt.ex && rekt.sy!=rekt.ey)
				 fract(/*hdc*/);
				 putCursor();
				 walkabout();
			}

			}
			else
			{
				BitBlt(hdc, 0, 0, WIDTH, 
					HEIGHT, hdcMem, 0, 0, SRCCOPY);
				xmin=tempx;
				ymin=tempy;

		       }
	}
} break; 

WM_KEYDOWN 消息

当按下键时,会调用 WM_KEYDOWN 消息

case WM_KEYDOWN:
{
	int virtual_code = (int) wparam;
	int key_bits     = (int) lparam;

	switch (virtual_code)
	{
		case 27: {
					PostQuitMessage(0); //<esc> quits
				} break;

		case 13: {
					//<enter>
				resetFrac();
				fract(/*hdc*/);
				} break;
		case 32:{
				}break;

		case VK_RIGHT: { } break;
		case VK_LEFT: { } break;
	default: break;
}

} break;

WM_QUIT 和 WM_DESTROY 消息

当应用程序发出想要退出的信号时,会调用 WM_QUIT WM_DESTROY 消息

		WM_QUIT:
		case WM_DESTROY:
			KillTimer(hwnd,ID_TIMER);
			PostQuitMessage(0);
		break;

		return 0;

		default:
		return DefWindowProc(hwnd, msg, wparam, lparam);
		}

	ReleaseDC(hwnd, hdc);
	return 0;
} // end  LRESULT CALLBACK WndProc()

这就是创建在 Win32 设备上下文中绘制和缩放曼德勃罗特集的 Win32 应用程序所需的一切。

感谢阅读。

历史

  • 2010-05-08 更新完成
  • 2002-06-22 代码完成
一个曼德勃罗特集探器/缩放器,带有朱利亚集漫游 - CodeProject - 代码之家
© . All rights reserved.