计科101
冯康 201000814128
桌面精灵
程序介绍
桌面精灵的主窗体运行结果如图1.1所示。桌面精灵模块是以阴历和阳历相结合的方式显示的日历,其中还包含二十四节气以及一些中西方节日,这些特殊的日期都用不同的颜色进行标注。
图1.1 桌面精灵主窗体
窗口设置
右键单击主界面,在弹出的菜单中选择“窗口设置”命令,打开“窗口设置”模块,如图1.2所示。在该模块中,用户可以设置窗口的显示风格,包括普通窗口、总在最前和嵌入桌面3种,还可以进行系统设置,包括开机自动运行、鼠标穿透和透明度设置。通过设置这些风格可以更灵活的使用桌面精灵模块。
– – 1
图1.2 窗口设置
新建备忘录
右键单击主界面,在弹出的菜单中选择“新建备忘录”命令,打开“新建备忘录”窗口,如图1.3所示。在该模块中,可以添加备忘录信息,用来提醒用户,一以免忘记重要的工作。
图1.3 新建备忘录模块
备忘录列表
右键单击主界面,在弹出的菜单中选择“备忘录列表”命令,打开“备忘录列表”窗口,如图1.4所示。在该模块中,用户可以查看所有的备忘提醒,并可以对这些提醒进行管理。
– – 2
图1.4 备忘录列表模块
提示显示
图1.5 备忘录的提示界面
托盘显示
图1.6 静止状态 图1.7 鼠标滑过
图1.8 右键单击
– – 3
图1.9 在主窗口上单击右键菜单显示
功能实现代码介绍:
关键代码
1、 阳历转换成阴历的方法
(1)定义一个LeapYear函数,用来判断当前年份是否是闰年 2、 BOOL CEidolonDlg::LeapYear(int year)
{ return ((year%4==0 && year%100!=0) || year%400==0); }
(2)添加自定义函数FirstDayOfMonth,用来计算月份的第一天是星期几 int CEidolonDlg::FirstDayOfMonth(int year,int month)
{
int n=0,d=0;//d来保存这一天之前在全年中的天数 for(int i=1;i (3)添加GetMonthDays函数用来计算各个月份的天数 int CEidolonDlg::GetMonthDays(int year,int month) { switch(month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31; case 4: case 6: case 9: case 11: return 30; case 2: if(LeapYear(year))//如果是闰年则返回29天 return 29; – – 4 else return 28; } return 0; } (4)添加DaysFrom1900函数,用来计算Y年M月D日到1900年相差的天数,就是将1900年作为一个基数,根据它来计算当前日期是星期几即农历日期 LONG CEidolonDlg::DaysFrom1900(CustomDate Date) { LONG days; days = 365*Date.Year+(Date.Year-1)/4-(Date.Year-1)/100+(Date.Year-1)/400- (365*1900+(1900-1)/4-(1900-1)/100+(1900-1)/400); for(int i=0;i (6)添加 LeapMonth函数该函数是用来计算农历Y年闰月的天数 int CEidolonDlg::LeapMonth(UINT year) { return LunarInfo[year-1900] & 0xf; } (7)添加LeapDays函数,用来计算农历Y年M月的天数 int CEidolonDlg::LeapDays(int year) { if(LeapMonth(year)) { return (LunarInfo[year-1900] & 0x10000) ? 30: 29; } else { return 0; – – 5 } } (8)添加MonthDays函数,计算Y年M月的总天数 int CEidolonDlg::MonthDays(UINT year, UINT month) { return (LunarInfo[year-1900] & (0x10000>>month))? 30: 29;} (9)添加GetLunar函数,根据输入的阳历日期来计算阴历日起 CustomDate CEidolonDlg::GetLunar(CustomDate date) { LONG offset; int i, leap=0, temp=0; CustomDate retdate; offset=DaysFrom1900(date)-30; for(i=1900; i<2050 && offset>0; i++) { temp = YearDays(i); offset -= temp; } if(offset<0) { offset += temp; i--; } retdate.Year = i; leap = LeapMonth(i); bool isLeap = false; for(i=1; i<13 && offset>0; i++) { if(leap>0 && i==(leap+1) && isLeap==false) { --i; isLeap = true; temp = LeapDays(retdate.Year); } else { – – 6 } } temp = MonthDays(retdate.Year, i); if(isLeap==true && i==(leap+1)) isLeap = false; offset -= temp; if(offset==0 && leap>0 && i==leap+1) { } if(offset<=0) { } retdate.Month = i; retdate.Day = offset ; retdate.IsRunYue=isLeap; return retdate; offset += temp; --i; if(isLeap) else { } isLeap = true; --i; isLeap = false; } (10)添加GetLunarString函数,将阴历日期转化成天干地支字符串 char* CEidolonDlg::GetLunarString(CustomDate date) { TCHAR szNongli[30], szNongliDay[10],szShuXiang[10]; const char *cTianGan[] = {\"甲\乙\丙\丁\戊\己\庚\辛\壬\癸\天干 const char *cDiZhi[] = {\"子\丑\寅\卯\辰\巳\午\未\申\酉\戌\亥\ //地支 const char *cShuXiang[] = {\"鼠\牛\虎\兔\龙\蛇\马\羊\猴\鸡\狗\猪\ – – 7 //生肖 const char *cDayName[] = { \"*\初一\初二\初三\初四\初五\ \"初六\初七\初八\初九\初十\ \"十一\十二\十三\十四\十五\ \"十六\十七\十八\十九\二十\ \"廿一\廿二\廿三\廿四\廿五\ \"廿六\廿七\廿八\廿九\三十\农历日期 const char *cMonName[] = {\"*\正\二\三\四\五\六\七\八\九\十\十一\腊\"}; //生成农历天干、地支、属相 int nShuXiang = ((date.Year - 4) % 60) % 12; if ( nShuXiang < 0 || nShuXiang >= sizeof(cShuXiang)/sizeof(cShuXiang[0]) ) return NULL ; wsprintf(szShuXiang,\"%s\int nTianGan = ((date.Year - 4) % 60) % 10; if ( nTianGan < 0 || nTianGan >= sizeof(cTianGan)/sizeof(cTianGan[0]) ) { return NULL; } int nDiZhi = ((date.Year - 4) % 60) % 12; if ( nDiZhi < 0 || nDiZhi >= sizeof(cDiZhi)/sizeof(cDiZhi[0]) ) return NULL; wsprintf(szNongli,\"%s(%s%s)年\//生成农历月、日 if( date.Month < 0 || date.Month >= sizeof(cMonName)/sizeof(cMonName[0]) ) else – – return NULL; wsprintf(szNongliDay,\"闰%s\strcpy(szNongliDay,cMonName[date.Month]); 8 if(date.IsRunYue) strcat(szNongliDay,\"月\"); if( date.Day < 0 || date.Day >= sizeof(cDayName)/sizeof(cDayName[0]) ) return NULL; strcat(szNongliDay,cDayName[date.Day]); strcat(szNongli,szNongliDay); sprintf(m_slunar,szNongli); return m_slunar; } 3、 时钟算法 在新建备忘录的左上角有一个时钟,时钟的表盘只能是一个图片,指针是设备上下文绘制道到图片上。由于时间的不断变化,故绘制的表针也要不断变化,这需要用到CDC类的MoveTo和LineTo函数。 添加变量int m_hour,m_min,m_sec;//声明三个变量分别来保存时分秒。在定时器中设置这三个变量的值。 void CNewMemoDlg::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default CDC *pDC=m_Clock.GetDC(); CRect m_rect; m_Clock.GetClientRect(m_rect);//获得绘制区域 DrawClock(pDC,m_rect);//绘制秒针 m_sec = m_sec+1; if(m_sec==60) { m_sec=0; m_min=m_min+1; if(m_min==60) { m_min=0; m_hour=m_hour+1; } } CDialog::OnTimer(nIDEvent); } 表针的绘制: void CNewMemoDlg::DrawClock(CDC* pDC,CRect m_rect) { CRgn rgn; HRGN m_hrgn; m_hrgn = ::CreateEllipticRgn(25,22,75,72); rgn.Attach(m_hrgn); CBrush m_brush (1,RGB(255,255,255)); pDC->SelectClipRgn(&rgn,0); – – 9 pDC->FillRgn(&rgn,&m_brush); int x=m_rect.Width()/2; int y=m_rect.Height()/2;//点(x,y)刚好是圆的中心 CPen SecondPen(PS_SOLID,1,RGB(255,0,0));//设置秒针画笔 pDC->SelectObject(&SecondPen); pDC->MoveTo (x,y);//设置画笔位置 pDC->LineTo (x+(long)23*cos(pi/2-2*pi*m_sec/60.0),y-(long)23*sin(pi/2-2*pi*m_sec/60.0)); CPen MinutePen(PS_SOLID,2,RGB(0,0,0));//设置分针画笔 pDC->SelectObject(&MinutePen); pDC->MoveTo (x,y); pDC->LineTo (x+(long)20*cos(pi/2-2*pi*m_min/60.0),y-(long)20*sin(pi/2-2*pi*m_min/60.0)); CPen HourPen(PS_SOLID,3,RGB(0,0,0));//设置时针画笔 pDC->SelectObject(&HourPen); pDC->MoveTo (x,y); pDC->LineTo (x+(long)15*cos(pi/2-5*2*pi*m_hour/60.0),y-(long)15*sin(pi/2-5*2*pi*m_hour/60.0)); } 4、 添加系托盘 自定义函数响应函数OnTray,在主窗体头文件中声明该函数 afx_msg void OnTray(WPARAM wParam, LPARAM lParam); 在主体窗的宏映射中添加如下代码 ON_MESSAGE(WM_ONTRAY,OnTray); 在OnTray函数中设置鼠标右键单击及左键双击的一系列操作 void CEidolonDlg::OnTray(WPARAM wParam, LPARAM lParam) { UINT uMouseMsg = (UINT) lParam; if(uMouseMsg == WM_RBUTTONDOWN) { CMenu* pPopup = m_Menu.GetSubMenu(0); CPoint point; GetCursorPos(&point); SetForegroundWindow();//实现在别处点击鼠标,隐藏右键菜单 pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON TPM_VERTICAL, point.x,point.y,AfxGetApp()->m_pMainWnd,TPM_LEFTALIGN); } if(uMouseMsg == WM_LBUTTONDBLCLK) //双击鼠标 { ShowWindow(SW_SHOWNOACTIVATE); //恢复窗口的显示 } } 5、 自绘右键弹出菜单 在绘制菜单项的背景位图时,采用StretchBit方法,该方法用于绘制位图文件。(1) 创建一个以CMenu为基类的新类CCustomMen; (2) 定义一个数据结构CMenuItemInfo,用来保存菜单信息。 (3) 添加DrawMenuTile函数,用来绘制弹出菜单左侧的标题栏 – – | 10 void CCustomMenu::DrawMenuTitle(CDC *pDC, CRect rect) { CBitmap m_bitmap; m_bitmap.LoadBitmap(IDB_LEFTBITMAP); BITMAP m_size; m_bitmap.GetBitmap(&m_size); CDC m_memdc; m_memdc.CreateCompatibleDC(pDC); CGdiObject* m_oldobject; m_oldobject = m_memdc.SelectObject(&m_bitmap); pDC->StretchBlt(0,0,28,rect.bottom,&m_memdc,0,0, m_size.bmWidth,m_size.bmHeight,SRCCOPY); m_bitmap.DeleteObject(); CFont* m_oldfont = pDC->SelectObject(&m_TitleFont); pDC->SetTextColor(RGB(255,0,0)); pDC->TextOut(rect.left+5,rect.Height()-10,\"桌\"); pDC->TextOut(rect.left+5,rect.Height()+10,\"面\"); pDC->TextOut(rect.left+5,rect.Height()+30,\"精\"); pDC->TextOut(rect.left+5,rect.Height()+50,\"灵\"); pDC->SelectObject(m_oldfont); } (4) 添加DrawComMenu函数,用绘制址菜单项的背景位图 void CCustomMenu::DrawComMenu(CDC *pDC, CRect rect, BOOL select) { if(select) { pDC->SelectStockObject(BLACK_PEN); rect.DeflateRect(29,1,0,2); pDC->Rectangle(rect); CBitmap m_bitmap; m_bitmap.LoadBitmap(IDB_ITEMBITMAP); BITMAP m_size; m_bitmap.GetBitmap(&m_size); CDC m_memdc; m_memdc.CreateCompatibleDC(pDC); CGdiObject* m_oldobject; m_oldobject = m_memdc.SelectObject(&m_bitmap); pDC->StretchBlt(rect.left+1,rect.top+1,rect.Width()-2,rect.Height()-2, &m_memdc,0,0,m_size.bmWidth,m_size.bmHeight,SRCCOPY); m_bitmap.DeleteObject(); } else { pDC->FillSolidRect(rect,RGB(255,255,255)); } } (5) 添加DrawItemText函数,用来会址菜单项的文本 void CCustomMenu::DrawItemText(CDC *pDC, LPSTR str, CRect rect) { rect.DeflateRect(40,0,0,0); – – 11 pDC->DrawText(str,rect,DT_SINGLELINE|DT_VCENTER|DT_LEFT); } (6) 添加DrawSeparater函数,用来绘制菜单分割条 void CCustomMenu::DrawSeparater(CDC *pDC, CRect rect) { if(pDC != NULL) { rect.DeflateRect(29,0,0,0); pDC->Draw3dRect(rect,RGB(0,0,255),RGB(0,0,255)); } } (7) 添加ChangeMenuItm函数,用来修改菜单信息 BOOL CCustomMenu::ChangeMenuItem(CMenu *menu) { int m_index=0; if(menu != NULL) { int m_itemcount = menu->GetMenuItemCount(); //获得菜单项个数 for(int i=0;i (8) 重载MeasureItem函数,用来设置菜单项大小 void CCustomMenu::MeasureItem(LPMEASUREITEMSTRUCT lpStruct) { if(lpStruct->CtlType==ODT_MENU) { lpStruct->itemHeight = 22; //设置菜单项的高 lpStruct->itemWidth = 100; //设置菜单项的宽 CMenuItemInfo* m_iteminfo; – – 12 m_iteminfo = (CMenuItemInfo*)lpStruct->itemData; if(m_iteminfo->m_ItemID == 0) { lpStruct->itemHeight = 1; //设置分隔条 } } } (9) 重载DrawItem函数,用来重绘菜单项 void CCustomMenu::DrawItem(LPDRAWITEMSTRUCT lpStruct) { if(lpStruct->CtlType==ODT_MENU) { if(lpStruct->itemData == NULL) return; unsigned int m_state = lpStruct->itemState; //获得菜单项状态 CDC* pDC = CDC::FromHandle(lpStruct->hDC); CString str = ((CMenuItemInfo*)(lpStruct->itemData))->m_ItemText; LPSTR m_str = str.GetBuffer(str.GetLength()); int m_itemID = ((CMenuItemInfo*)(lpStruct->itemData))->m_ItemID; int m_itemicon = ((CMenuItemInfo*)(lpStruct->itemData))->m_ItemIndex; CRect m_rect = lpStruct->rcItem; pDC->SetBkMode(TRANSPARENT); //设置菜单项文本背景透明 switch(m_itemID) { case 0: //绘制分隔条 DrawSeparater(pDC,m_rect); break; default: //绘制菜单项和左侧标题 DrawComMenu(pDC,m_rect,m_state&ODS_SELECTED); DrawItemText(pDC,m_str,m_rect); DrawMenuTitle(pDC,m_rect); break; } } } 这是设计的主要代码,部分细节可参照程序源代码。 – – 13 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- howto234.com 版权所有 湘ICP备2022005869号-3
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务