VC++课程设计实验报告-时钟

湖南农业大学

VC++程序设计课程设计报告

时钟

学生姓名:XXX

学号:XXXXXXXXXXXX

QQ:XXXXXXXXX

班级:X班

年级专业:2010级计算机

指导老师及职称:X老师高级工程师

学院:XXXXXXXXXXXXXXX

湖南·长沙

提交日期:2010年6月

时钟

学生:XX

指导老师:XXX

(XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX)

1.摘要:利用MFC设计制作一个能联网调时时钟,当按下F1键时,能打开或关闭帮助,单击左键是,能拖动窗口,双击左键时,能联网校时,滚动中轴时,能调整时间,单击右键,能随机变换背景颜色。

2.关键词:MFC;Clock;C++……

3.前言:

1.我们学习MFC,除了可以掌握一种Windows应用程序设计的基本方法之外,还可以使他们进一步全面、深刻地理解向对象程序设计的思想。而且MFC所蕴含的程序设计思想、代码实现技巧、则是其他开发工具所不能及的。

2.我们通过制作这个时钟,可以加深对MFC的设计思想的理解。也可以加强对C++的思想的理解。

4.正文:

4.1:窗口的创建于注册

class CAboutDlg : public CDialog

{

public:

CAboutDlg();

// Dialog Data

//{{AFX_DATA(CAboutDlg)

enum { IDD = IDD_ABOUTBOX };

//}}AFX_DATA

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CAboutDlg)

protected:

virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support

//}}AFX_VIRTUAL

// Implementation

protected:

//{{AFX_MSG(CAboutDlg)

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)

{

//{{AFX_DATA_INIT(CAboutDlg)

//}}AFX_DATA_INIT

}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CAboutDlg)

//}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)

//{{AFX_MSG_MAP(CAboutDlg)

// No message handlers

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

///////////////////////////////////////////////////////////////////////////// // CAlarmClockDlg dialog

CAlarmClockDlg::CAlarmClockDlg(CWnd* pParent /*=NULL*/)

: CDialog(CAlarmClockDlg::IDD, pParent)

{

//{{AFX_DATA_INIT(CAlarmClockDlg)

// NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT

// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

m_hThread = NULL;

m_bkColor = RGB(110, 200, 255);

m_bHelp = TRUE;

}

void CAlarmClockDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CAlarmClockDlg)

// NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CAlarmClockDlg, CDialog)

//{{AFX_MSG_MAP(CAlarmClockDlg)

ON_WM_SYSCOMMAND()

ON_WM_PAINT()

ON_WM_QUERYDRAGICON()

ON_WM_LBUTTONDOWN()

ON_WM_TIMER()

ON_WM_ERASEBKGND()

ON_WM_LBUTTONDBLCLK()

ON_WM_RBUTTONDOWN()

ON_WM_MOUSEWHEEL()

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

///////////////////////////////////////////////////////////////////////////// // CAlarmClockDlg message handlers

void CAlarmClockDlg::OnSysCommand(UINT nID, LPARAM lParam)

{

if ((nID & 0xFFF0) == IDM_ABOUTBOX)

{

CAboutDlg dlgAbout;

dlgAbout.DoModal();

}

else

{

CDialog::OnSysCommand(nID, lParam);

}

}

// The system calls this to obtain the cursor to display while the user drags // the minimized window.

HCURSOR CAlarmClockDlg::OnQueryDragIcon()

{

return (HCURSOR)m_hIcon;

}

BOOL CAlarmClockDlg::OnInitDialog()

{

CDialog::OnInitDialog();

// Add "About..." menu item to system menu.

// IDM_ABOUTBOX must be in the system command range.

ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);

if (pSysMenu != NULL)

{

CString strAboutMenu;

strAboutMenu.LoadString(IDS_ABOUTBOX);

if (!strAboutMenu.IsEmpty())

{

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

}

}

// Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog

SetIcon(m_hIcon, TRUE); // Set big icon

SetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here

//1. 将窗口改成正方形

CRect rc;

this->GetWindowRect(&rc);

int iNewWH = min(rc.Width(), rc.Height());

this->MoveWindow(rc.left, rc.top, iNewWH, iNewWH);

//2. 设置绘图区域

this->GetWindowRect(&rc);

HRGN hRgn = ::CreateEllipticRgn(rc.left, rc.top, rc.right, rc.bottom);

this->SetWindowRgn(hRgn, TRUE);

//3. 设置定时器

this->SetTimer(110, 7000, NULL); //110 = Help

this->SetTimer(2359, 1000, NULL); //23:59 = move time

//4. 主动触发鼠标双击消息

this->PostMessage(WM_LBUTTONDBLCLK);

//5. 设置窗口标题

this->SetWindowText("Internet时钟");

return TRUE; // return TRUE unless you set the focus to a control

}

void CAlarmClockDlg::OnTimer(UINT nIDEvent)

{

if (nIDEvent == 2359)

{

this->Invalidate();

}

else if (nIDEvent == 110)

{

m_bHelp = FALSE;

this->KillTimer(110);

}

CDialog::OnTimer(nIDEvent);

}

// If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework.

void CAlarmClockDlg::OnPaint()

{

CPaintDC dc(this); // device context for painting

if (IsIconic())

{

SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0);

// Center icon in client rectangle

int cxIcon = GetSystemMetrics(SM_CXICON);

int cyIcon = GetSystemMetrics(SM_CYICON);

CRect rect;

GetClientRect(&rect);

int x = (rect.Width() - cxIcon + 1) / 2;

int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon

dc.DrawIcon(x, y, m_hIcon);

}

else

{

OnDraw(&dc);

//CDialog::OnPaint();

}

}

BOOL CAlarmClockDlg::OnEraseBkgnd(CDC* pDC)

{

// TODO: Add your message handler code here and/or call default

return TRUE;

// return CDialog::OnEraseBkgnd(pDC);

}

void CAlarmClockDlg::OnDraw(CDC *pDC)

{

// TODO: add draw code for native data here

/////////////////////////////////////////////////////////////////////////

//

//如下的做法能避免绘图闪烁, 强烈推荐使用. KouConghua.

//

//主要思想是将以前直接画在pDC上的图,改画到一个内存DC(如dcMem)中去,

//然后使用BitBlt函数,将dcMem这个内存中的图复制到当前屏幕即pDC中去.

//

//具体步骤如下, 其中a 和b 选择一步即可, 不可二者都做:

//a. 直接在OnDraw()中增加如下语句, 以改变窗口背景为透明色:

// ::SetClassLong(this->m_hWnd, GCL_HBRBACKGROUND,

// (LONG)(HBRUSH)::GetStockObject(NULL_BRUSH));

//b. 在CxxxView类中增加OnEraseBkgnd()消息响应函数,

// 将其中的代码改为: return TRUE;

// 直接返回TRUE表示告诉系统绘图时不再绘制背景,相当于设置窗口背景为NULL刷子.

//c. 为CxxxView类增加一个成员函数void OnDrawMem(CDC &dcMem),

// 并将你以前写在OnDraw()中的代码,移到OnDrawMem()中去即可.

//

/////////////////////////////////////////////////////////////////////////

// //1. 改变当前View窗口的背景为空刷子

// ::SetClassLong(this->m_hWnd, GCL_HBRBACKGROUND,

(LONG)(HBRUSH)::GetStockObject(NULL_BRUSH));

//2. 获取当前绘图区的宽度和高度

CRect rcClient;

this->GetClientRect(&rcClient);

int nWidth = rcClient.Width();

int nHeight= rcClient.Height();

//3. 创建一个和pDC兼容的内存DC: dcMem

CDC dcMem;

dcMem.CreateCompatibleDC(pDC); //pDC换成NULL也可以,指定为显示器

//创建一个位图对象, 其宽度和高度就用当前绘图区的nWidth 和nHeight

CBitmap bmp;

bmp.CreateCompatibleBitmap(pDC, nWidth, nHeight);

//将bmp选入到dcMem中, 只有选入了位图的dcMem才有地方绘图,画到指定的bmp位图上

CBitmap * pOldBit = dcMem.SelectObject(&bmp);

//4. 先用背景色将位图清除干净,这里我用的是m_bkColor作为背景

dcMem.FillSolidRect(0, 0, nWidth, nHeight, m_bkColor);

//5. 执行真正的绘图代码, 如dcMem.MoveTo(……); dcMem.LineTo(……); 等等

OnDrawMem(&dcMem);

//6. 将dcMem中的图拷贝到pDC上进行显示. 关键点.

pDC->BitBlt(0, 0, nWidth, nHeight, &dcMem, 0, 0, SRCCOPY);

//7. 绘图完成后的清理

bmp.DeleteObject();

dcMem.DeleteDC();

4.2:中心时间显示

void CAlarmClockDlg::OnDrawMem(CDC *pDC)

{

CRect rc;

this->GetClientRect(&rc); //获取客户区矩形

//1. 获取设备资源

CPen *pOldPen = pDC->GetCurrentPen();

CPen pen(PS_SOLID, 1, RGB(0,0,0));

pDC->SelectObject(&pen);

CBrush *pOldBrush = pDC->GetCurrentBrush();

CBrush brush; //使圆背景透明,不至于遮挡住圆心处显示的时间文本brush.CreateStockObject(NULL_BRUSH);

pDC->SelectObject(&brush);

pDC->SetBkMode(TRANSPARENT); //设置文本背景为透明

pDC->SetTextColor(RGB(128, 0, 128)); //设置文本颜色

//2. 获取圆心和半径

POINT ptO; //圆心

int iR = min(rc.right - rc.left, rc.bottom-rc.top) / 2;

iR = iR - 10; //半径

ptO.x = (rc.right + rc.left) / 2;

ptO.y = (rc.bottom + rc.top) / 2;

//3. 取得时, 分, 秒

CString sTime;

SYSTEMTIME tm;

::GetLocalTime(&tm); //取得本地时间

float fSecond = tm.wSecond;

float fMinute = tm.wMinute + fSecond / 60.0f;

float fHour = tm.wHour % 12 + fMinute / 60.0f;

//在圆心附近显示时间

// CRect rtO(ptO.x - 40, ptO.y + 2, ptO.x + 40, ptO.y + 22);

CRect rtO(ptO.x - iR, ptO.y + 2, ptO.x + iR, ptO.y + iR);

sTime.Format("%.2d:%.2d:%.2d", tm.wHour, tm.wMinute, tm.wSecond);

pDC->DrawText(sTime, &rtO, DT_CENTER);

4.3:画时钟

算法:时钟的秒刻度分为60个刻度,每个刻度是6°

四个象限的刻度尺的算法如下:

//第一象限

for(int i=0;i<16;i++)

{

POINT pt0;

pt0.x = ptOrigin.x + iR * sin( PI/180 * 6*i) *

0.95f;

pt0.y = ptOrigin.y - iR * cos( PI/180 * 6*i) *

0.95f;

SetPixel(hdc,pt0.x,pt0.y,RGB(255,0,0));

}

//第四象限

for(i=1;i<16;i++)

{

POINT pt0;

pt0.x = ptOrigin.x + iR * cos( PI/180 * 6*i) * 0.95f;

pt0.y = ptOrigin.y + iR * sin( PI/180 * 6*i) * 0.95f;

SetPixel(hdc,pt0.x,pt0.y,RGB(255,0,0));

}

//第三象限

for(i=1;i<16;i++)

{

POINT pt0;

pt0.x = ptOrigin.x - iR * sin( PI/180 * 6*i) * 0.95f;

pt0.y = ptOrigin.y + iR * cos( PI/180 * 6*i) * 0.95f;

SetPixel(hdc,pt0.x,pt0.y,RGB(255,0,0));

}

//第二象限

for(i=1;i<15;i++)

{

POINT pt0;

pt0.x = ptOrigin.x - iR * cos( PI/180 * 6*i) * 0.95f;

pt0.y = ptOrigin.y - iR * sin( PI/180 * 6*i) * 0.95f;

SetPixel(hdc,pt0.x,pt0.y,RGB(255,0,0));

}

根据:

sin(PI/2+α)=cosα

cos(π/2+α)=-sinα

第四象限可以写成

for(int i=16;i<32;i++)

{

POINT pt0;

pt0.x = ptOrigin.x + iR * sin( PI/180 * 6*i) * 0.95f;

pt0.y = ptOrigin.y - iR * cos( PI/180 * 6*i) * 0.95f;

SetPixel(hdc,pt0.x,pt0.y,RGB(255,0,0));

}

根据:

sin(π+α)=-sinα

cos(π+α)=-cosα

第三象限可以写成:

for(int i=32;i<48;i++)

{

POINT pt0;

pt0.x = ptOrigin.x + iR * sin( PI/180 * 6*i) * 0.95f;

pt0.y = ptOrigin.y - iR * cos( PI/180 * 6*i) * 0.95f;

SetPixel(hdc,pt0.x,pt0.y,RGB(255,0,0));

}

根据:

sin(3π/2+α)=-cosα

cos(3π/2+α)=sinα

第二象限可以写成

for(int i=48;i<60;i++)

{

POINT pt0;

pt0.x = ptOrigin.x + iR * sin( PI/180 * 6*i) * 0.95f;

pt0.y = ptOrigin.y - iR * cos( PI/180 * 6*i) * 0.95f;

SetPixel(hdc,pt0.x,pt0.y,RGB(255,0,0));

}

最后统一成:

for(int i=0;i<60;i++)

{

POINT pt0;

pt0.x = ptOrigin.x + iR * sin( PI/180 * 6*i) * 0.95f;

pt0.y = ptOrigin.y - iR * cos( PI/180 * 6*i) * 0.95f;

SetPixel(hdc,pt0.x,pt0.y,RGB(255,0,0));

}

所以有程序代码如下:

// pDC->Ellipse(ptO.x - iR, ptO.y - iR, ptO.x + iR, ptO.y + iR);

//4.1 画秒刻度

pen.DeleteObject();

pen.CreatePen(PS_SOLID, 1, RGB(0,0,0));

pDC->SelectObject(&pen);

for (int i = 0; i < 60; i++)

{

POINT ptA, ptB;

ptA.x = ptO.x + iR * sin( PI/30 * i) * 0.98f;

ptA.y = ptO.y - iR * cos( PI/30 * i) * 0.98f;

ptB.x = ptO.x + iR * sin( PI/30 * i) * 1.00f;

ptB.y = ptO.y - iR * cos( PI/30 * i) * 1.00f;

pDC->MoveTo(ptA.x, ptA.y);

pDC->LineTo(ptB.x, ptB.y);

}

//4.2 画小时刻度

pen.DeleteObject();

pen.CreatePen(PS_SOLID, 2, RGB(0,0,0));

pDC->SelectObject(&pen);

for (i = 0; i < 60; i = i + 5)

{

POINT ptA, ptB;

ptA.x = ptO.x + iR * sin( PI/30 * i) * 0.95f;

ptA.y = ptO.y - iR * cos( PI/30 * i) * 0.95f;

ptB.x = ptO.x + iR * sin( PI/30 * i) * 1.00f;

ptB.y = ptO.y - iR * cos( PI/30 * i) * 1.00f;

pDC->MoveTo(ptA.x, ptA.y);

pDC->LineTo(ptB.x, ptB.y);

//写出小时数字

int j = i/5;

if (j == 0) j = 12;

CString sTime;

sTime.Format("%d", j);

POINT ptN;

ptN.x = ptO.x + iR * sin( PI/30 * i) * 0.87f;

ptN.y = ptO.y - iR * cos( PI/30 * i) * 0.87f;

CRect rtN(ptN.x - 10, ptN.y - 10, ptN.x + 10, ptN.y + 10);

pDC->DrawText(sTime, &rtN, DT_CENTER | DT_VCENTER);

}

//5. 画秒针 60s = 2*PI, 1s = PI / 30

pen.DeleteObject();

pen.CreatePen(PS_SOLID, 1, RGB(0,0,255));

pDC->SelectObject(&pen);

POINT ptSecond;

ptSecond.x = ptO.x + iR * sin( PI/30 * fSecond) * 0.94f; ptSecond.y = ptO.y - iR * cos( PI/30 * fSecond) * 0.94f;

pDC->MoveTo(ptO.x, ptO.y);

pDC->LineTo(ptSecond.x, ptSecond.y);

//6. 画分针 60m = 2*PI, 1m = PI / 30

pen.DeleteObject();

pen.CreatePen(PS_SOLID, 2, RGB(255,0,0));

pDC->SelectObject(&pen);

POINT ptMinute;

ptMinute.x = ptO.x +iR * sin( PI/30 * fMinute) * 0.84f; ptMinute.y = ptO.y - iR * cos( PI/30 * fMinute) * 0.84f;

pDC->MoveTo(ptO.x, ptO.y);

pDC->LineTo(ptMinute.x, ptMinute.y);

//7. 画时针 12h = 2*PI, 1h = PI / 6

pen.DeleteObject();

pen.CreatePen(PS_SOLID, 3, RGB(255,0,255));

pDC->SelectObject(&pen);

POINT ptHour;

ptHour.x = ptO.x + iR * sin( PI/6 * fHour) * 0.71f;

ptHour.y = ptO.y - iR * cos( PI/6 * fHour) * 0.71f;

pDC->MoveTo(ptO.x, ptO.y);

pDC->LineTo(ptHour.x, ptHour.y);

4.4:显示帮助信息及其相关操作

//帮助信息, 显示7s后关闭

if (m_bHelp)

{

CString sHelp;

sHelp += "按下F1键: 帮助开关\r\n";

sHelp += "单击左键: 拖动窗口\r\n";

sHelp += "双击左键: 联网校时\r\n";

sHelp += "滚动中轴: 调整时间\r\n";

sHelp += "单击右键: 随机背景\r\n";

sHelp += "按Esc 键: 退出程序\r\n";

if (int(fHour) % 12 >= 3 && (int)fHour % 12 < 9)

{

CRect rtHelp(ptO.x - iR, ptO.y - iR * 7 / 10, ptO.x + iR, ptO.y + iR * 3 / 10);

pDC->DrawText(sHelp, &rtHelp, DT_CENTER | DT_VCENTER);

}

else

{

CRect rtHelp(ptO.x - iR, ptO.y + iR / 5, ptO.x + iR, ptO.y + iR * 4 / 5);

pDC->DrawText(sHelp, &rtHelp, DT_CENTER | DT_VCENTER);

}

}

//8. 恢复现场, 释放资源

pDC->SelectObject(pOldPen);

pDC->SelectObject(pOldBrush);

pen.DeleteObject();

brush.DeleteObject();

}

//移动无标题窗口

void CAlarmClockDlg::OnLButtonDown(UINT nFlags, CPoint point)

{

this->SendMessage(WM_NCLBUTTONDOWN, HTCAPTION, 0);

CDialog::OnLButtonDown(nFlags, point);

}

//Internet校时

void CAlarmClockDlg::OnLButtonDblClk(UINT nFlags, CPoint point)

{

if (m_hThread) ::TerminateThread(m_hThread, -1);

m_hThread = ::CreateThread(NULL, 0, SetInternetTimeProc, this, 0, NULL);

CDialog::OnLButtonDblClk(nFlags, point);

}

//随机背景

void CAlarmClockDlg::OnRButtonDown(UINT nFlags, CPoint point)

{

::srand(::GetTickCount());

m_bkColor = RGB(rand() * 100 % 255, rand() * 100 % 255, rand() * 100 % 255);

this->Invalidate();

CDialog::OnRButtonDown(nFlags, point);

}

//调整时间

BOOL CAlarmClockDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)

{

// TODO: Add your message handler code here and/or call default

SYSTEMTIME tm;

::GetLocalTime(&tm);

COleDateTime now = COleDateTime::GetCurrentTime();

now += COleDateTimeSpan(0, 0, zDelta > 0 ? -1 : 1, 0); // 1 Minute exactly

tm.wHour = now.GetHour();

tm.wMinute = now.GetMinute();

tm.wSecond = 0;//now.GetSecond();

::SetLocalTime(&tm);

this->Invalidate();

return CDialog::OnMouseWheel(nFlags, zDelta, pt);

}

//键盘控制

void CAlarmClockDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)

{

switch (nChar)

{

case VK_ESCAPE:

CDialog::OnOK();

break;

case VK_HOME:

this->SendMessage(WM_LBUTTONDBLCLK);

break;

case VK_END:

SYSTEMTIME tm;

::GetLocalTime(&tm);

tm.wHour = 0;

tm.wMinute = 0;

tm.wSecond = 0;

::SetLocalTime(&tm);

this->Invalidate();

break;

case VK_DOWN:

case VK_RIGHT:

case VK_NEXT:

OnMouseWheel(0, -1, 0);

break;

case VK_UP:

case VK_LEFT:

case VK_PRIOR:

OnMouseWheel(0, 1, 0);

break;

}

//CDialog::OnKeyDown(nChar, nRepCnt, nFlags);

相关文档
最新文档