曾经项目中需要用日历控件。
头文件:
#ifndef Calendar_H_
#define Calendar_H_
#include <coecntrl.h>
class TCalendarObserver
{
public:
virtual void OnSelectCalendar(TDateTime sel) = 0;
};
class CCalendar : public CCoeControl
{
public:
static CCalendar* NewL(CCoeControl* parent,const TRect& aRect);
virtual ~CCalendar();
public: // from CCoeControl
void Draw(const TRect& aRect) const;
virtual void SizeChanged();
virtual void HandlePointerEventL(const TPointerEvent& aPointerEvent);
virtual TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);
public:
void SetObserver(TCalendarObserver* observer);
virtual TSize MinimumSize();
TDateTime GetSelDate();
private:
void ConstructL(CCoeControl* parent,const TRect& aRect);
CCalendar();
TKeyResponse ClickUpSelect();
TKeyResponse ClickDownSelect();
TKeyResponse ClickLeftSelect();
TKeyResponse ClickRightSelect();
private:
//获取某年某月某天是星期几
int GetWeek(int year, int month, int day = 1);
//得到某月天数
int GetDaysInMonth(int year,int month);
void ClearGrid();
TBool IsMoveOtherMonth(int index);
void ResetAndLoad();
void ToMonth(TBool add);
void LayoutGrid();
private:
struct TDayGridItem
{
int day;
TRect position;
};
TDayGridItem m_Grid[42];
RArray< TBuf<2> > m_Week;
TBuf<12> titleYear;
TBuf<12> titleMonth;
TRect YearArea;
TRect MonthArea;
TBuf<2> upFlag;
TBuf<2> DownFlag;
TRect YearUpArea;
TRect YearDownArea;
TRect MonthUpArea;
TRect MontyDownArea;
int m_CurMonth;
int m_CurYear;
int m_CurDays;
int m_CurDownIndex;
int m_CurFirstIndex;
TCalendarObserver* m_Observer;
};
#endif /* Calendar_H_ */
源文件:
#include "Calendar.h"
#include <e32cmn.h>
#include <EIKENV.H>
#include <GDI.H>
#define KGridRectW 25
#define KGridRectH 25
_LIT(KMonday,"\x4E00");
_LIT(KTuesday,"\x4E8C");
_LIT(KWednesday,"\x4E09");
_LIT(KThursday,"\x56DB");
_LIT(KFriday,"\x4E94");
_LIT(KSaturday,"\x516D");
_LIT(KSunday,"\x65E5");
_LIT(KFormatDate,"%d-%d-%d");
CCalendar* CCalendar::NewL(CCoeControl* parent, const TRect& aRect)
{
CCalendar* self = new (ELeave) CCalendar;
CleanupStack::PushL(self);
self->ConstructL(parent, aRect);
CleanupStack::Pop();
return self;
}
CCalendar::CCalendar()
{
}
CCalendar::~CCalendar()
{
m_Week.Close();
}
void CCalendar::ConstructL(CCoeControl* parent, const TRect& aRect)
{
if (parent)
{
SetContainerWindowL(*parent);
}
else
{
CreateWindowL();
}
SetRect(aRect);
m_Week.Append(KMonday());
m_Week.Append(KTuesday());
m_Week.Append(KWednesday());
m_Week.Append(KThursday());
m_Week.Append(KFriday());
m_Week.Append(KSaturday());
m_Week.Append(KSunday());
upFlag = _L(">");
DownFlag = _L("<");
TTime curTime;
curTime.HomeTime();
TDateTime date = curTime.DateTime();
m_CurMonth = date.Month()+1;
m_CurYear = date.Year();
ResetAndLoad();
TDateTime curSelDate = GetSelDate();
titleYear.AppendNum(curSelDate.Year());
titleMonth.AppendNum((int)curSelDate.Month()+1);
EnableDragEvents();
ActivateL();
}
void CCalendar::Draw(const TRect& aRect) const
{
CWindowGc& gc = SystemGc();
gc.SetBrushStyle(gc.ESolidBrush);
gc.SetBrushColor(KRgbGray);
gc.DrawRect(aRect);
const CFont* font = CEikonEnv::Static()->DenseFont();
int baseline = font->HeightInPixels() + (TSize(KGridRectW,KGridRectH).iHeight - font->HeightInPixels()) / 2;
gc.UseFont(font);
gc.SetBrushStyle(gc.ENullBrush);
gc.SetPenColor(KRgbBlack);
TPoint tl = TPoint(Rect().iTl + TPoint((Rect().Width()-KGridRectW*7)/2,0));
gc.DrawText(DownFlag,YearUpArea,baseline,CGraphicsContext::ECenter);
gc.DrawText(titleYear,YearArea,baseline,CGraphicsContext::ECenter);
gc.DrawText(upFlag,YearDownArea,baseline,CGraphicsContext::ECenter);
gc.DrawText(DownFlag,MonthUpArea,baseline,CGraphicsContext::ECenter);
gc.DrawText(titleMonth,MonthArea,baseline,CGraphicsContext::ECenter);
gc.DrawText(upFlag,MontyDownArea,baseline,CGraphicsContext::ECenter);
tl += TPoint(0,KGridRectH);
TRect gridItemRect;
//一二三四五六日
for(int i=0; i<7; ++i)
{
gridItemRect = TRect(tl + TPoint(i*KGridRectW,0), TSize(KGridRectW,KGridRectH));
gc.DrawRect(gridItemRect);
gc.DrawText(m_Week[i],gridItemRect,baseline,CGraphicsContext::ECenter);
}
for(int i=0; i<6; ++i)
{
for(int j=0; j<7; ++j)
{
int down = (i*7)+j;
if(m_CurDownIndex == down)
{
gc.SetBrushColor(KRgbBlue);
gc.SetBrushStyle(gc.ESolidBrush);
}
else
gc.SetBrushStyle(gc.ENullBrush);
gc.DrawRect(m_Grid[down].position);
if(m_Grid[down].day != 0)
{
TBuf<2> buf;
buf.AppendNum(m_Grid[down].day);
gc.DrawText(buf,m_Grid[down].position,baseline,CGraphicsContext::ECenter);
}
}
}
gc.DiscardFont();
}
void CCalendar::SizeChanged()
{
LayoutGrid();
}
TKeyResponse CCalendar::OfferKeyEventL(const TKeyEvent& aKeyEvent,
TEventCode aType)
{
TKeyResponse r = EKeyWasNotConsumed;
if (aType != EEventKey)
{
return r;
}
if (aKeyEvent.iCode == EKeyUpArrow)
{
r = ClickUpSelect();
}
else if (aKeyEvent.iCode == EKeyDownArrow)
{
r = ClickDownSelect();
}
else if(aKeyEvent.iCode == EKeyLeftArrow)
{
r = ClickLeftSelect();
}
else if(aKeyEvent.iCode == EKeyRightArrow)
{
r = ClickRightSelect();
}
else if(aKeyEvent.iCode == EKeyDevice3)
{
if(m_Observer)
m_Observer->OnSelectCalendar(GetSelDate());
}
if (r == EKeyWasConsumed)
{
TDateTime curSelDate = GetSelDate();
titleYear.Zero();
titleYear.AppendNum(curSelDate.Year());
titleMonth.Zero();
titleMonth.AppendNum((int)curSelDate.Month()+1);
DrawDeferred();
}
return r;
}
void CCalendar::HandlePointerEventL(const TPointerEvent& aPointerEvent)
{
TPoint pt = aPointerEvent.iPosition;
if (aPointerEvent.iType == TPointerEvent::EButton1Down)
{
for(int i=0; i<6; ++i)
{
for(int j=0; j<7; ++j)
{
int down = (i*7)+j;
if(m_Grid[down].position.Contains(pt))
{
if(m_Observer)
m_Observer->OnSelectCalendar(GetSelDate());
}
}
}
}
}
TKeyResponse CCalendar::ClickUpSelect()
{
m_CurDownIndex -= 7;
if(IsMoveOtherMonth(m_CurDownIndex))
{
ToMonth(EFalse);
ResetAndLoad();
}
return EKeyWasConsumed;
}
TKeyResponse CCalendar::ClickDownSelect()
{
m_CurDownIndex += 7;
if(IsMoveOtherMonth(m_CurDownIndex))
{
ToMonth(ETrue);
ResetAndLoad();
}
return EKeyWasConsumed;
}
TKeyResponse CCalendar::ClickLeftSelect()
{
m_CurDownIndex --;
if(IsMoveOtherMonth(m_CurDownIndex))
{
ToMonth(EFalse);
ResetAndLoad();
}
return EKeyWasConsumed;
}
TKeyResponse CCalendar::ClickRightSelect()
{
m_CurDownIndex ++;
if(IsMoveOtherMonth(m_CurDownIndex))
{
ToMonth(ETrue);
ResetAndLoad();
}
return EKeyWasConsumed;
}
void CCalendar::ToMonth(TBool add)
{
if(add)
{
m_CurMonth++;
if(m_CurMonth > 12)
{
m_CurMonth = 1;
m_CurYear++;
}
}
else
{
m_CurMonth--;
if(m_CurMonth < 1)
{
m_CurMonth = 12;
m_CurYear--;
}
}
}
void CCalendar::LayoutGrid()
{
TPoint tl = TPoint(Rect().iTl + TPoint((Rect().Width()-KGridRectW*7)/2,0));
TPoint moveTl = tl;
YearUpArea = TRect(moveTl,TSize(KGridRectW/2,KGridRectH));
moveTl += TPoint(KGridRectW/2,0);
YearArea = TRect(moveTl,TSize(KGridRectW*2,KGridRectH));
moveTl += TPoint(KGridRectW*2,0);
YearDownArea = TRect(moveTl,TSize(KGridRectW/2,KGridRectH));
moveTl += TPoint(KGridRectW*2+KGridRectW/2,0);
MonthUpArea = TRect(moveTl,TSize(KGridRectW/2,KGridRectH));
moveTl += TPoint(KGridRectW/2,0);
MonthArea = TRect(moveTl,TSize(KGridRectW,KGridRectH));
moveTl += TPoint(KGridRectW,0);
MontyDownArea = TRect(moveTl,TSize(KGridRectW/2,KGridRectH));
moveTl = tl + TPoint(0, KGridRectH*2);
TRect gridItemRect;
for(int i=0; i<6; ++i)
{
for(int j=0; j<7; ++j)
{
int down = (i*7)+j;
gridItemRect = TRect(moveTl + TPoint(j*KGridRectW,KGridRectH*i), TSize(KGridRectW,KGridRectH));
m_Grid[down].position = gridItemRect;
}
}
}
void CCalendar::ResetAndLoad()
{
ClearGrid();
int week = GetWeek(m_CurYear ,m_CurMonth );
m_CurDays = GetDaysInMonth(m_CurYear, m_CurMonth);
m_CurFirstIndex = week-1;
m_CurDownIndex = week-1;
for(int point = 1; point<=m_CurDays; point++)
{
int down = m_CurDownIndex+point-1;
m_Grid[down].day = point;
}
DrawDeferred();
}
TBool CCalendar::IsMoveOtherMonth(int index)
{
if(index < m_CurFirstIndex)
return ETrue;
if(index-m_CurFirstIndex >= m_CurDays)
return ETrue;
return EFalse;
}
TSize CCalendar::MinimumSize()
{
int h = 34*7;
int w = 34*7;
return TSize(w, h);
}
void CCalendar::SetObserver(TCalendarObserver* observer)
{
m_Observer = observer;
}
TDateTime CCalendar::GetSelDate()
{
TDateTime date;
date.SetYear(m_CurYear);
date.SetMonth(TMonth(m_CurMonth-1));
date.SetDay(m_Grid[m_CurDownIndex].day-1);
return date;
}
int CCalendar::GetWeek(int year, int month, int day)
{
int century = year/100;
int syear = year%100;
int smonth = month;
int w , weekres = 0;
if(month == 1)
{
century = (year-1)/100;
syear = (year-1)%100;
smonth = 13;
}
else if(month == 2)
{
century = (year-1)/100;
syear = (year-1)%100;
smonth = 14;
}
//蔡勒(Zeller)公式:w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1
w = syear + (syear/4) + (century/4) - 2*century + (26*(smonth+1)/10) + day - 1;
if(w < 0)
{
weekres = (w+Abs(w)*7)%7;
}
else
{
weekres = w%7;
}
if(weekres == 0)
weekres = 7;
return weekres;
}
int CCalendar::GetDaysInMonth(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((year%4==0)&&((year%100)||(year%400==0)))
return 29;
else
return 28;
}
}
}
void CCalendar::ClearGrid()
{
for(int i=0; i<42; ++i)
{
m_Grid[i].day = 0;
}
}
效果图: