안녕하세요. Calendar의 특정날짜에 제가 원하는 그래픽을 표시해 넣고 싶은데 어떻게 하면 되나요? 예를 들면 토요일이나 일요일을 붉은색으로 표시해 넣는다던지, 혹은 기념일에 해당하는 날짜에 원하는 특별한 기호같은 것을 삽입해 넣고 싶은데요, 혹시 방법이 있다면 알려 주시겠어요?
> 안녕하세요. Calendar의 특정날짜에 제가 원하는 그래픽을 표시해 넣고 싶은데 어떻게 하면 되나요? 예를 들면 토요일이나 일요일을 붉은색으로 표시해 넣는다던지, 혹은 기념일에 해당하는 날짜에 원하는 특별한 기호같은 것을 삽입해 넣고 싶은데요, 혹시 방법이 있다면 알려 주시겠어요?
> 안녕하세요. Calendar의 특정날짜에 제가 원하는 그래픽을 표시해 넣고 싶은데 어떻게 하면 되나요? 예를 들면 토요일이나 일요일을 붉은색으로 표시해 넣는다던지, 혹은 기념일에 해당하는 날짜에 원하는 특별한 기호같은 것을 삽입해 넣고 싶은데요, 혹시 방법이 있다면 알려 주시겠어요?
>
안녕하세요 김영대입니다
아래 예제는 제가 전에 만들었던 스케쥴관리의 일부를 발췌한건대
폼위에는 크기가 700*500 정도의 비어있는 TImage 하고
년월을 입력받는 TMaskEdit 와 TButton 하나를 올려놓은 다음
아래 소스를 추가하세요
아래 소스는 TImage에 직접 그래픽으로 달력을 그리므로 그림같은것은
직접 Canvas 에 그리시면 됩니다
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, Mask, ComCtrls, Printers;
type
TMainForm = class(TForm)
Button1: TButton;
ME_yyyymm: TMaskEdit;
Image_Schedule: TImage;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure DrawBackGround(yyyymm: String);
procedure DrawProgressBar(yyyymm, StartDate, EndDate: String; iColor: TColor);
procedure DrawEvent(yyyymm, EventDate, Event: String; iColor: TColor);
end;
const
DayOfWeekNames: array[0..6] of String =('일','월','화','수','목','금','토');
NameHeight = 22;
var
MainForm: TMainForm;
OccupationEvent: array[0..31] of Integer;
OccupationBar: array[0..31] of Integer;
MasterCanvas: TCanvas;
implementation
{$R *.DFM}
procedure TMainForm.FormCreate(Sender: TObject);
begin
Image_Schedule.Picture.Bitmap := TBitmap.Create; {bitmap 생성}
MasterCanvas := Image_Schedule.Picture.Bitmap.Canvas;
ME_yyyymm.EditMask := '####.##;0;_';
ME_yyyymm.Text := '199905';
end;
{===============================================================================
주어진 년월의 마지막 일자를 구한다
===============================================================================}
function Get_LastDay(yyyy,mm: Integer): Integer;
var
MyDate: TDateTime;
Convert_OK: Boolean;
dd: Integer;
begin
Convert_OK := True;
dd := 28;
while Convert_OK do
begin
try
MyDate := EncodeDate(yyyy, mm, dd);
except
on EConvertError do
Convert_OK := False;
end;
if Convert_OK then
Inc(dd)
else
Dec(dd);
end;
Get_LastDay := dd;
end;
{===============================================================================
주어진 달의 주수를 구한다(마지막 주의 의미)
===============================================================================}
Function Get_weeks(yyyy,mm: Integer): Integer;
var
MyDate: TDateTime;
i, weeks: Integer;
Convert_OK: Boolean;
begin
weeks := 0;
for i := 1 to 31 do
begin
try
Convert_OK := True;
MyDate := EncodeDate(yyyy, mm, i);
except
on EConvertError do
Convert_OK := False;
end;
if Convert_OK then
if (DayOfWeek(MyDate) = 7) or (Get_LastDay(yyyy,mm) = i) then {토요일이나 달의 마지막이면 1주}
Inc(weeks);
end;
Get_weeks := weeks;
end;
{===============================================================================
주어진 달의 주에 해당하는 날짜from, to, 주의 첫번째 날의 요일번호를 구한다
===============================================================================}
procedure Get_weekfrto(yyyy,mm,week:Integer; var weekfrom:Integer; var weekto:Integer; var dayweek:Integer);
var
MyDate: TDateTime;
i, j, weeks: Integer;
Convert_OK: Boolean;
begin
weekfrom := 0;
weekto := 0;
dayweek := 0;
weeks := 0;
for i := 1 to 31 do
begin
try
Convert_OK := True;
MyDate := EncodeDate(yyyy, mm, i);
except
on EConvertError do
Convert_OK := False;
end;
if Convert_OK then
begin
if (DayOfWeek(MyDate) = 7) or (Get_LastDay(yyyy,mm) = i) then {토요일이나 달의 마지막이면 1주}
Inc(weeks);
if weeks = week then
begin
weekto := i; {주의 마지막 일자}
for j := i downto 1 do
begin
MyDate := EncodeDate(yyyy, mm, j);
if (DayOfWeek(MyDate) = 1) or (j = 1) then {일요일이나 그달의 1일이면 주의 시작 일자}
begin
weekfrom := j; {주의 시작 일자}
dayweek := DayOfWeek(MyDate); {주의 첫번째 날의 요일번호}
Break;
end;
end;
System.Exit;
end;
end;
end;
end;
function indc_date(yyyymmdd: String; disc: Integer): String;
var
yyyy,mm,dd: Integer;
MyDate: TDateTime;
Convert_OK: Boolean;
begin
yyyy := StrToIntDef(Copy(yyyymmdd,1,4),-1);
mm := StrToIntDef(Copy(yyyymmdd,5,2),-1);
dd := StrToIntDef(Copy(yyyymmdd,7,2),-1);
if (yyyy <= 0) or (mm <= 0) or (dd <= 0) then
begin
indc_date := '';
System.exit;
end;
if disc = 0 then
begin
try
Convert_OK := True;
MyDate := EncodeDate(yyyy, mm, dd);
except
on EConvertError do
Convert_OK := False;
end;
if Convert_OK then
begin
indc_date := FormatDateTime('yyyymmdd', MyDate);
end
else
begin
indc_date := '';
end;
end
else
begin
Convert_OK := True;
try
MyDate := EncodeDate(yyyy, mm, dd);
except
on EConvertError do
Convert_OK := False;
end;
if Convert_OK then
begin
indc_date := FormatDateTime('yyyymmdd', MyDate+disc);
end
else
begin
indc_date := '';
end;
end;
end;
{===============================================================================
주어진 년,월,일이 들어가는 주를 구한다
===============================================================================}
Function Get_thisweek(yyyy,mm,dd: Integer): Integer;
var
MyDate: TDateTime;
i, weeks: Integer;
Convert_OK: Boolean;
begin
weeks := 0;
for i := 1 to 31 do
begin
try
Convert_OK := True;
MyDate := EncodeDate(yyyy, mm, i);
except
on EConvertError do
Convert_OK := False;
end;
if Convert_OK then
if (DayOfWeek(MyDate) = 7) or (Get_LastDay(yyyy,mm) = i) then {토요일이나 달의 마지막이면 1주}
begin
Inc(weeks);
if dd <= i then // 해당 주를 찾았다
Break;
end;
end;
Get_thisweek := weeks;
end;
function DayOfWeekNum(yyyymmdd: String): Integer;
var
yyyy,mm,dd: Integer;
MyDate: TDateTime;
begin
yyyy := StrToIntDef(Copy(yyyymmdd,1,4),-1);
mm := StrToIntDef(Copy(yyyymmdd,5,2),-1);
dd := StrToIntDef(Copy(yyyymmdd,7,2),-1);
Result := -1;
try
MyDate := EncodeDate(yyyy, mm, dd);
Result := DayOfWeek(MyDate);
except
on EConvertError do
Result := -1;
end;
end;
procedure TMainForm.DrawBackGround(yyyymm: String);
var
max_day, max_week: Integer;
day_width, day_height: Integer;
weekfrom, weekto, dayweek: Integer;
i, j, k, yyyy, mm: Integer;
temp: String;
begin
yyyy := StrToIntDef(Copy(yyyymm,1,4),0);
mm := StrToIntDef(Copy(yyyymm,5,2),0);
if (yyyy = 0) or (mm = 0) then
System.Exit;
for i := Low(OccupationEvent) to High(OccupationEvent) do
OccupationEvent[i] := 0;
for i := Low(OccupationBar) to High(OccupationBar) do
OccupationBar[i] := 0;
// 달의 마지막일자
max_day := Get_LastDay(yyyy, mm);
// 달의 주수
max_week := Get_weeks(yyyy, mm);
day_width := Image_Schedule.Width div 7; // 가로 7칸의 각 폭
day_height := (Image_Schedule.Height-NameHeight) div 6; // 세로 6칸의 각 높이
MasterCanvas.Font := Self.Font;
// 이전의 화면을 지운다
Image_Schedule.Picture.Bitmap.Width := Image_Schedule.Width;
Image_Schedule.Picture.Bitmap.Height := Image_Schedule.Height;
MasterCanvas.Brush.Color := clBtnFace;
MasterCanvas.FillRect(Rect(0, 0, Image_Schedule.Width, Image_Schedule.Height));
// 각 일자명을 그린다
MasterCanvas.Brush.Color := clYellow;
for i := 0 to 6 do
begin
MasterCanvas.Rectangle(day_width*i, 0,
day_width*(i+1), NameHeight);
if i = 0 then // 일요일
MasterCanvas.Font.Color := clRed
else if i = 6 then // 토요일
MasterCanvas.Font.Color := clBlue
else // 평일
MasterCanvas.Font.Color := clBlack;
MasterCanvas.TextOut(day_width*i+5, 5, DayOfWeekNames[i]);
end;
// 스케줄의 각 일자의 직사각형을 그린다
MasterCanvas.Brush.Color := clWhite;
for i := 0 to (max_week-1) do
begin
for j := 0 to 6 do
MasterCanvas.Rectangle(day_width*j, day_height*i+NameHeight,
day_width*(j+1), day_height*(i+1)+NameHeight);
end;
// 스케줄의 각 일자를 출력
k := 0;
for i := 0 to (max_week-1) do // 달의 주수만큼
begin
// 주어진 달의 주에 해당하는 날짜from, to, 주의 첫번째 날의 요일번호
Get_weekfrto(yyyy,mm,i+1, weekfrom, weekto, dayweek);
for j := 0 to 6 do
begin
if ((j+1) >= dayweek) and
((k+1) <= max_day) then
begin
Inc(k);
if j = 0 then // 일요일
MasterCanvas.Font.Color := clRed
else if j = 6 then // 토요일
MasterCanvas.Font.Color := clBlue
else // 평일
MasterCanvas.Font.Color := clBlack;
MasterCanvas.Brush.Color := clWhite;
MasterCanvas.TextOut(day_width*j+5, day_height*i+5+NameHeight, inttostr(k));
end;
end;
end;
end;
procedure TMainForm.DrawProgressBar(yyyymm, StartDate, EndDate: String; iColor: TColor);
var
day_width, day_height: Integer;
daynum, dayweek: Integer;
yyyy, mm: Integer;
CurDate: String;
iPos: Integer;
begin
yyyy := StrToIntDef(Copy(yyyymm,1,4),0);
mm := StrToIntDef(Copy(yyyymm,5,2),0);
if (yyyy = 0) or (mm = 0) then
System.Exit;
iPos := 1;
CurDate := StartDate; // 시작일자
while CurDate <= EndDate do
begin
if Copy(CurDate,1,6) = yyyymm then // 기준월의 날짜만 그린다
begin
// 요일에 출력되는 막대 카운트
OccupationBar[StrToIntDef(Copy(CurDate,7,2),0)] :=
OccupationBar[StrToIntDef(Copy(CurDate,7,2),0)] + 1;
if iPos < OccupationBar[StrToIntDef(Copy(CurDate,7,2),0)] then // 해당기간의 최대 카운트
iPos := OccupationBar[StrToIntDef(Copy(CurDate,7,2),0)];
end;
CurDate := indc_date(CurDate, 1); // 날짜증가
end;
day_width := Image_Schedule.Width div 7; // 가로 7칸의 각 폭
day_height := (Image_Schedule.Height-NameHeight) div 6; // 세로 6칸의 각 높이
CurDate := StartDate; // 시작일자
while CurDate <= EndDate do
begin
if Copy(CurDate,1,6) = yyyymm then // 기준월의 날짜만 그린다
begin
daynum := Get_thisweek(StrToInt(Copy(CurDate,1,4)), // 해당 년월일의 주번호
StrToInt(Copy(CurDate,5,2)),
StrToInt(Copy(CurDate,7,2)));
dayweek := DayOfWeekNum(CurDate); // 요일번호
// 막대기
MasterCanvas.Brush.Color := iColor;
MasterCanvas.FillRect(Rect(day_width*(dayweek-1)+ 4,
day_height*(daynum-1)+ day_height-(iPos*5)-2+NameHeight,
day_width*(dayweek-1)+ day_width-4,
day_height*(daynum-1)+ day_height-(iPos*5)+1+NameHeight));
if CurDate = StartDate then // 시작점 그리기
MasterCanvas.FillRect(Rect(day_width*(dayweek-1)+ 4,
day_height*(daynum-1)+ day_height-(iPos*5)-2+NameHeight-1,
day_width*(dayweek-1)+ 6,
day_height*(daynum-1)+ day_height-(iPos*5)-2+NameHeight+1));
if CurDate = EndDate then // 종료점 그리기
MasterCanvas.FillRect(Rect(day_width*(dayweek-1)+ day_width-6,
day_height*(daynum-1)+ day_height-(iPos*5)+1+NameHeight-1,
day_width*(dayweek-1)+ day_width-4,
day_height*(daynum-1)+ day_height-(iPos*5)+1+NameHeight+1));
end;
CurDate := indc_date(CurDate, 1); // 날짜증가
end;
end;
procedure TMainForm.DrawEvent(yyyymm, EventDate, Event: String; iColor: TColor);
var
day_width, day_height: Integer;
daynum, dayweek: Integer;
iPos: Integer;
begin
if Copy(EventDate,1,6) <> yyyymm then // 기준월의 날짜에 속하지 않으면...
System.Exit;
// 요일에 출력되는 이벤트 카운트
OccupationEvent[StrToIntDef(Copy(EventDate,7,2),0)] :=
OccupationEvent[StrToIntDef(Copy(EventDate,7,2),0)] + 1;
iPos := OccupationEvent[StrToIntDef(Copy(EventDate,7,2),0)];
day_width := Image_Schedule.Width div 7; // 가로 7칸의 각 폭
day_height := (Image_Schedule.Height-NameHeight) div 6; // 세로 6칸의 각 높이
daynum := Get_thisweek(StrToInt(Copy(EventDate,1,4)), // 해당 년월일의 주번호
StrToInt(Copy(EventDate,5,2)),
StrToInt(Copy(EventDate,7,2)));
dayweek := DayOfWeekNum(EventDate); // 요일번호
MasterCanvas.Font.Color := iColor;
MasterCanvas.Brush.Color := clWhite;
MasterCanvas.TextOut(day_width*(dayweek-1)+ (day_width div 2) - (MasterCanvas.TextWidth(Event) div 2),
day_height*(daynum-1)+ (iPos*13) +3+ NameHeight, Event);
end;
procedure TMainForm.Button1Click(Sender: TObject);
begin
// 기준년월의 달력을 그린다
DrawBackGround(ME_yyyymm.Text);
// 기준년월의 각 스케쥴과 이벤트를 그린다
DrawProgressBar(ME_yyyymm.Text, '19990506', '19990510', clRed);
DrawEvent(ME_yyyymm.Text, '19990507', '검토', clGreen);
DrawEvent(ME_yyyymm.Text, '19990503', '술먹는날', clGreen);
DrawEvent(ME_yyyymm.Text, '19990513', '술먹는날', clGreen);
DrawEvent(ME_yyyymm.Text, '19990523', '술먹는날', clGreen);
DrawProgressBar(ME_yyyymm.Text, '19990501', '19990505', clRed);
DrawEvent(ME_yyyymm.Text, '19990502', '생일이브', clRed);
DrawEvent(ME_yyyymm.Text, '19990503', '생일', clRed);
DrawProgressBar(ME_yyyymm.Text, '19990520', '19990530', clBlue);
DrawEvent(ME_yyyymm.Text, '19990522', '검수일', clBlue);
DrawEvent(ME_yyyymm.Text, '19990529', '토요근무', clBlue);
DrawProgressBar(ME_yyyymm.Text, '19990503', '19990506', clBlack);
DrawEvent(ME_yyyymm.Text, '19990503', '시연회', clBlack);
DrawProgressBar(ME_yyyymm.Text, '19990726', '19990726', clBlue);
DrawEvent(ME_yyyymm.Text, '19990726', '생일', clBlue);
end;
end.