MFC编写时钟

C_apple 2011-09-14 05:07:57
初次学习MFC,想要编写一个时钟程序,包含日历,但是不知道从哪里开始动手,希望在此等到解答。
...全文
538 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
向立天 2011-10-11
  • 打赏
  • 举报
回复
您好
我是本版版主
此帖已多日无人关注
请您及时结帖
如您认为问题没有解决可按无满意结帖处理
另外本版设置了疑难问题汇总帖
并已在版面置顶
相关规定其帖子中有说明
您可以根据规定提交您帖子的链接
如您目前不想结帖只需回帖说明
我们会删除此结帖通知

见此回复三日内无回应
我们将强制结帖
相关规定详见界面界面版关于版主结帖工作的具体办法
  • 打赏
  • 举报
回复
http://wenku.baidu.com/view/4b8cd9e9856a561252d36fae.html
xu20101010 2011-09-14
  • 打赏
  • 举报
回复
三角函数呀 你计算出每一秒钟所转过的角度就行了
study_wuwenyao 2011-09-14
  • 打赏
  • 举报
回复
我觉着这个程序最重要的就是如何随着时间的改变擦除旧的指针的指向和绘制新的指向。我就卡在这,数学不过关啊,每改变一点时间其新点坐标的值的计算我死活搞不出来,蛋疼至死啊!!!!
study_wuwenyao 2011-09-14
  • 打赏
  • 举报
回复
我昨天也是看到这个问题,也是初学。刚好做到这个问题。(我还没开始学MFC,目前正在学习windows程序设计,我觉着这个思想应该差不多)目前也卡上了。找了一段代码模仿。希望共同进步,共同学习。
代码出处:windows程序设计第二版光盘 王艳萍等著。

///////////////////////////////////////////////////////////////
// Clock.cpp文件


#include <windows.h>


#include "resource.h"
#include <math.h>

LRESULT __stdcall WndProc(HWND, UINT, WPARAM, LPARAM);
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
char szWindowClass[] = "Clock";

// 注册窗口类
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = ::LoadIcon(hInstance, (LPCTSTR)IDI_MAIN);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); // 此域可以是一个系统定义的颜色值
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = NULL;

::RegisterClassEx(&wcex);


// 创建并显示主窗口
HWND hWnd = ::CreateWindowEx(NULL, szWindowClass, "时钟",
WS_POPUP|WS_SYSMENU|WS_SIZEBOX, 100, 100, 300, 300, NULL, NULL, hInstance, NULL);
::ShowWindow(hWnd, nShowCmd);
::UpdateWindow(hWnd);

// 进入消息循环
MSG msg;
while(::GetMessage(&msg, NULL, 0, 0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}

return 1;
}



//////////////////////////////////////////////////////////////////////////////////////
// 消息处理代码

#define IDT_CLOCK 1
const int IDM_HELP = 100;
const int IDM_TOPMOST = 101;

// 实现函数
void SetIsotropic(HDC hdc, int cxClient, int cyClient);
void DrawClockFace(HDC hdc);
void DrawHand(HDC hdc, int nLength, int nWidth, int nDegrees, COLORREF clrColor);

// 上一次Windows通知时的时间
static int s_nPreHour; // 小时
static int s_nPreMinute; // 分钟
static int s_nPreSecond; // 秒
// 窗口客户区的大小
static int s_cxClient;
static int s_cyClient;
// 是否位于最顶层
static BOOL s_bTopMost;

LRESULT __stdcall WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
switch(nMsg)
{
case WM_CREATE:
{
// 向系统菜单中添加自定义的项
HMENU hSysMenu;
hSysMenu = ::GetSystemMenu(hWnd, FALSE);
::AppendMenu(hSysMenu, MF_SEPARATOR, 0, NULL);
::AppendMenu(hSysMenu, MF_STRING, IDM_TOPMOST, "总在最前");
::AppendMenu(hSysMenu, MF_STRING, IDM_HELP, "帮助");

// 设置时间
SYSTEMTIME time;
::GetLocalTime(&time);
s_nPreHour = time.wHour%12;
s_nPreMinute = time.wMinute;
s_nPreSecond = time.wSecond;

// 创建定时器
::SetTimer(hWnd, IDT_CLOCK, 1000, NULL);
return 0;
}
case WM_SIZE:
{
s_cxClient = LOWORD(lParam);
s_cyClient = HIWORD(lParam);
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = ::BeginPaint(hWnd, &ps);

// 设置坐标系
SetIsotropic(hdc, s_cxClient, s_cyClient);

// 绘制时钟外观
DrawClockFace(hdc);

// 绘制指针

// 经过1个小时时针走30度(360/12),经过1分钟时针走0.5度(30/60)
DrawHand(hdc, 200, 8, s_nPreHour*30 + s_nPreMinute/2, RGB(0, 0, 0));
// 经过1分钟分针走6度(360/60)
DrawHand(hdc, 400, 6, s_nPreMinute*6, RGB(0, 0, 0));
// 经过1秒钟秒针走6度(360/60)
DrawHand(hdc, 400, 1, s_nPreSecond*6, RGB(0, 0, 0));

::EndPaint(hWnd, &ps);
return 0;
}
case WM_TIMER:
{
// 如果窗口处于最小化状态就什么也不做
if(::IsIconic(hWnd)) // IsIconic函数用来判断窗口是否处于最小化状态
return 0;

// 取得系统时间
SYSTEMTIME time;
::GetLocalTime(&time);

// 建立坐标系
HDC hdc = ::GetDC(hWnd);
SetIsotropic(hdc, s_cxClient, s_cyClient);

// 以COLOR_3DFACE为背景色就可以擦除指针了(因为窗口的背景色也是COLOR_3DFACE)
COLORREF crfColor = ::GetSysColor(COLOR_3DFACE);

// 如果分钟改变的话就擦除时针和分针
if(time.wMinute != s_nPreMinute)
{
// 擦除时针和分针
DrawHand(hdc, 200, 8, s_nPreHour*30 + s_nPreMinute/2, crfColor);
DrawHand(hdc, 400, 6, s_nPreMinute*6, crfColor);
s_nPreHour = time.wHour;
s_nPreMinute = time.wMinute;
}

// 如果秒改变的话就擦除秒针,然后重画所有指针
if(time.wSecond != s_nPreSecond)
{
// 擦除秒针
DrawHand(hdc, 400, 1, s_nPreSecond*6, crfColor);

// 重画所有指针
DrawHand(hdc, 400, 1, time.wSecond*6, RGB(0, 0, 0));
DrawHand(hdc, 200, 8, time.wHour*30 + time.wMinute/2, RGB(0, 0, 0));
DrawHand(hdc, 400, 6, time.wMinute*6, RGB(0, 0, 0));
s_nPreSecond = time.wSecond;
}
return 0;
}
case WM_CONTEXTMENU:
POINT pt; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam);
{
// 取得系统菜单的句柄
HMENU hSysMenu = ::GetSystemMenu(hWnd, FALSE);

// 弹出系统菜单
int nID = ::TrackPopupMenu(hSysMenu,TPM_LEFTALIGN|TPM_RETURNCMD,
pt.x, pt.y, 0, hWnd, NULL);
if(nID > 0)
::SendMessage(hWnd, WM_SYSCOMMAND, nID, 0);
return 0;
}
case WM_CLOSE:
{
::KillTimer(hWnd, IDT_CLOCK);
::DestroyWindow(hWnd);
return 0;
}
case WM_DESTROY:
{
::PostQuitMessage(0);
return 0;
}
case WM_NCHITTEST:
{
UINT nHitTest;
nHitTest = ::DefWindowProc(hWnd, WM_NCHITTEST, wParam, lParam);
if (nHitTest == HTCLIENT &&
::GetAsyncKeyState(MK_LBUTTON) < 0) // 如果鼠标左键按下,GetAsyncKeyState函数的返回值小于0
nHitTest = HTCAPTION;
return nHitTest;
}
case WM_SYSCOMMAND:
int nID = wParam;
{
if(nID == IDM_HELP)
{
::MessageBox(hWnd, "一个时钟的例子", "时钟", 0);
}
else if(nID == IDM_TOPMOST)
{
HMENU hSysMenu = ::GetSystemMenu(hWnd, FALSE);
if(s_bTopMost)
{
::CheckMenuItem(hSysMenu, IDM_TOPMOST, MF_UNCHECKED);
::SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
s_bTopMost = FALSE;
}
else
{
::CheckMenuItem(hSysMenu, IDM_TOPMOST, MF_CHECKED);
::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
s_bTopMost = TRUE;
}
}
return ::DefWindowProc(hWnd, WM_SYSCOMMAND, nID, 0);
}
}

return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
}




void SetIsotropic(HDC hdc, int cx, int cy)
{
::SetMapMode(hdc, MM_ISOTROPIC);
::SetWindowExtEx(hdc, 1000, 1000, NULL);
::SetViewportExtEx(hdc, cx, -cy, NULL);
::SetViewportOrgEx(hdc, cx/2, cy/2, NULL);
}

// 绘制时钟的外观
void DrawClockFace(HDC hdc)
{
const int SQUARESIZE = 20;
static POINT pt[] =
{
0, 450, // 12点
225, 390, // 1点
390, 225, // 2点
450, 0, // 3点
390, -225, //... 下面的坐标是上面的点的对称点(以X轴、Y轴或原点对称)
225, -390,
0, -450,
-225, -390,
-390, -225,
-450, 0,
-390, 225,
-225, 390
};

// 选择一个黑色的画刷
::SelectObject(hdc, ::GetStockObject(BLACK_BRUSH));

// 画12个圆
for(int i=0; i<12; i++)
{
::Ellipse(hdc, pt[i].x - SQUARESIZE, pt[i].y + SQUARESIZE,
pt[i].x + SQUARESIZE, pt[i].y - SQUARESIZE);
}
}



// 指针的长度、宽度、相对于0点偏移的角度、颜色分别由参数nLength、nWidth、nDegrees、clrColor指定
void DrawHand(HDC hdc, int nLength, int nWidth, int nDegrees, COLORREF clrColor)
{
// 将角度nDegrees转化成弧度 . 2*3.1415926/360 == 0.0174533
double nRadians = (double)nDegrees*0.0174533;

// 计算坐标
POINT pt[2];
pt[0].x = (int)(nLength*sin(nRadians));
pt[0].y = (int)(nLength*cos(nRadians));
pt[1].x = -pt[0].x/5;
pt[1].y = -pt[0].y/5;

// 创建画笔,并选如DC结构中
HPEN hPen = ::CreatePen(PS_SOLID, nWidth, clrColor);
HPEN hOldPen = (HPEN)::SelectObject(hdc, hPen);

// 画线
::MoveToEx(hdc, pt[0].x, pt[0].y, NULL);
::LineTo(hdc, pt[1].x, pt[1].y);

::SelectObject(hdc, hOldPen);
::DeleteObject(hPen);
}

15,980

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧