教材:《Visual C++面向对象与可视化程序设计习题解析与编程实例》
题目:在昨晚讲解的最后一个例子上,实现如下功能:
(1)圆圈到达正弦曲线的尾部,可以自动往回移动,半径改为由大变小的模式,颜色模式和先前的一样。
(2)点击鼠标左键,圆圈停止移动,再点击一次,圆圈继续按照上一次的方向移动。
(3)点击鼠标右键,圆圈可以向反方向移动,比如,原来方向向左,点击一次右键,则变为向右移动,再次点击右键,则变为向左移动。
变量说明:
//m_dir代表想圆走的方向,dir代表圆正在走的方向,1为向右走,-1为向左走
int m_dir = 1, dir = 1;
做了更改的部分:
case WM_RBUTTONDOWN://右键反向
{
m_dir = -m_dir;
dir = -dir;
break;
}
case WM_LBUTTONDOWN://左键静止或运动
{
if (m_dir == 0)//如果处于静止状态就更改为圆本该走的运动方向
{
m_dir = dir;
}
else//在运动则更改为静止状态
{
m_dir = 0;
}
break;
}
case WM_PAINT:
{
if (i == 0)//起点
{
m_dir = 1; dir = 1;
}
else if (i == 99)//终点
{
m_dir = -1; dir = -1;
}
//...
i += m_dir;
//...
}
完整代码:
#include "framework.h"
#include "WindowsProject1.h"
#include <math.h>
#define Pi 3.1415926
#define MAX_LOADSTRING 100
// 全局变量:
HINSTANCE hInst; // 当前实例
WCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
// 此代码模块中包含的函数的前向声明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
//正弦曲线的角度变量.
double dfTheta = 0, dfRange = 100.0;
long i = 0, j = 0;
//定义圆心坐标和圆半径.
long lCentreX = 0, lCentreY = 0, lRadious = (long)(0.2 * dfRange);
//定义正弦曲线的点坐标.
POINT lpSin[100];
//m_dir代表想圆走的方向,dir代表圆正在走的方向,1为向右走,-1为向左走
int m_dir = 1, dir = 1;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此处放置代码。
// 初始化全局字符串
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT1));
MSG msg;
for (int j = 0; j < 100; j++) //生成正弦曲线的点坐标.
{
lpSin[j].x = (long)(j * 2 * Pi / 100 * 60);
lpSin[j].y = (long)(dfRange * sin(j * 2 * Pi / 100));
}
// 主消息循环:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
//
// 函数: MyRegisterClass()
//
// 目标: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT1));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT1);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// 函数: InitInstance(HINSTANCE, int)
//
// 目标: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 将实例句柄存储在全局变量中
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目标: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc; //定义设备环境句柄
HBRUSH hBrush; //定义画刷句柄
HPEN hPen; //定义画笔句柄
PAINTSTRUCT PtStr; //定义包含绘图信息的结构体变量
switch (message)
{
case WM_RBUTTONDOWN://右键反向
{
m_dir = -m_dir;
dir = -dir;
break;
}
case WM_LBUTTONDOWN://左键静止或运动
{
if (m_dir == 0)//如果处于静止状态就更改为圆本该走的运动方向
{
m_dir = dir;
}
else//在运动则更改为静止状态
{
m_dir = 0;
}
break;
}
// 其他消息处理代码...
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
if (i == 0)//起点
{
m_dir = 1; dir = 1;
}
else if (i == 99)//终点
{
m_dir = -1; dir = -1;
}
hdc = BeginPaint(hWnd, &PtStr);
// TODO: 在此处添加使用 hdc 的任何绘图代码...
SetWindowOrgEx(hdc, -200, -200, NULL); //设置原点坐标为(-200,-200)
hPen = CreatePen(PS_DASH, 1, RGB(255, 0, 0)); //创建新画笔
SelectObject(hdc, hPen); //选入画笔
Polyline(hdc, lpSin, 100); //绘制正弦曲线
if (i <= 25) //第一个1/4周期.
{
hPen = CreatePen(PS_DASH, 1, RGB(255, 0, 0));//红画笔.
hBrush = CreateHatchBrush(HS_BDIAGONAL, RGB(255, 0, 0));//红画刷.
lRadious = (long)(dfRange * 0.2 + i % 25 * dfRange * 0.4 / 25);//计算半径.
}
else if (i <= 50)//第二个1/4周期.
{
hPen = CreatePen(PS_DASH, 1, RGB(0, 255, 0));//绿画笔.
hBrush = CreateHatchBrush(HS_DIAGCROSS, RGB(0, 255, 0));//绿画刷.
lRadious = (long)(dfRange * 0.2 + i % 25 * dfRange * 0.4 / 25);//计算半径.
}
else if (i <= 75)//第三个周期.
{
hPen = CreatePen(PS_DASH, 1, RGB(0, 0, 255));//蓝画笔
hBrush = CreateHatchBrush(HS_CROSS, RGB(0, 0, 255));//蓝画刷.
lRadious = (long)(dfRange * 0.2 + i % 25 * dfRange * 0.4 / 25);//计算半径.
}
else//第四个周期.
{
hPen = CreatePen(PS_DASH, 1, RGB(255, 255, 0));//黄画笔
hBrush = CreateHatchBrush(HS_VERTICAL, RGB(255, 255, 0));//黄画刷.
lRadious = (long)(dfRange * 0.2 + i % 25 * dfRange * 0.4 / 25);//计算半径.
}
SelectObject(hdc, hBrush); //选入画刷.
SelectObject(hdc, hPen); //选入画笔.
lCentreX = lpSin[i].x; //圆心x坐标.
lCentreY = lpSin[i].y; //圆心y坐标.
Ellipse(hdc, lCentreX - lRadious, lCentreY - lRadious,
lCentreX + lRadious, lCentreY + lRadious); //画圆.
DeleteObject(hPen); //删除画笔.
DeleteObject(hBrush); //删除画刷.
EndPaint(hWnd, &PtStr);
i += m_dir;
Sleep(20); //每隔0.02秒绘制一次画面
if (i < 100) InvalidateRect(hWnd, NULL, 1); //刷新用户区.
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}