Mike M. Guest
|
Posted: Thu Jul 29, 2004 4:04 am Post subject: Help installing a custom component. |
|
|
I have written a custom component in BCB6 that is derived from
TGraphicControl; I have also derived it from TCustomControl. The
control works well when dynamically created in an application during
testing.
However, when I compile the control into a package, install the
package, and attempt to drop the control on a form, the control
generates an access violation. The message generated is "Access
violation at ADDRESS in module 'SunDial.bpl.'"
I have been trying for two days to figure out what I am doing wrong.
I have attached my source code to help. I would really appreciate any
guidance on this problem. It's driving me crazy.
Thank you!
Mike
==== SDCalendar.h ===========================================
#ifndef SDCalendarH
#define SDCalendarH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Classes.hpp>
#include <Controls.hpp>
//---------------------------------------------------------------------------
const int iNumRows = 8;
const int iNumCols = 7;
typedef void __fastcall (__closure *TDayDblClickEvent)(System::TObject
*Sender, int iDay);
//class PACKAGE TSDCalendar : public TCustomControl
class PACKAGE TSDCalendar : public TGraphicControl
{
private:
unsigned short int iRed, iGreen, iBlue;
unsigned short iMonth;
unsigned short iYear;
TColor bgColor;
TColor txtColor;
TColor bgEventColor;
TColor bgSelectedDayColor;
TColor txtEventColor;
bool bEventFlag[31];
int iRowTops[iNumRows];
int iColLefts[iNumCols];
int iRowHeight;
int iColWidth;
int iSelectedDay;
TDayDblClickEvent FOnDayDblClick;
void __fastcall CenterTextOut(int x, int y, int w, AnsiString str);
void __fastcall CenterRectTextOut(int x, int y, int h, int w,
AnsiString str);
protected:
DYNAMIC void __fastcall MouseDown(TMouseButton Button,
Classes::TShiftState Shift, int
X, int Y);
public:
__fastcall TSDCalendar(TComponent* Owner);
void __fastcall Paint(void);
void __fastcall SetMonth(const unsigned short Value);
unsigned short __fastcall GetMonth(void);
void __fastcall SetYear(const unsigned short Value);
void __fastcall SetTextColor(const TColor Value);
void __fastcall SetBGColor(const TColor Value);
void __fastcall SetTextEventColor(const TColor Value);
void __fastcall SetBGEventColor(const TColor Value);
void __fastcall ClearEventFlags(void);
bool __fastcall GetEventFlag(const int Value);
void __fastcall SetEventFlag(const int Index, const bool Value);
__published:
__property unsigned short Month = {read = GetMonth, write =
SetMonth};
__property unsigned short Year = {read = iYear, write = SetYear};
__property TColor BackgroundColor = {read = bgColor, write =
SetBGColor};
__property TColor TextColor = {read = txtColor, write =
SetTextColor};
__property TColor EventBackgroundCOlor = {read = bgEventColor,
write = SetBGEventColor};
__property TColor EventTextColor = {read = txtEventColor, write =
SetTextEventColor};
__property bool EventFlag[Integer AnIndex] = {read = GetEventFlag,
write = SetEventFlag};
__property TDayDblClickEvent OnDayDoubleClick = {read =
FOnDayDblClick, write = FOnDayDblClick};
};
//---------------------------------------------------------------------------
#endif
=============================================================
==== SDCalendar.cpp ===========================================
#include <vcl.h>
#pragma hdrstop
#include <dateutils.hpp>
#include <types.hpp>
#include "time.h"
#include "stdio.h"
//#pragma hdrstop
#include "SDCalendar.h"
#pragma package(smart_init)
char *szDays[] = {"S", "M", "T", "W", "T", "F", "S"};
const int iMonthsInYear = 12;
const int iDaysInWeek = 7;
const int iDaysOfWeekRow = 1;
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not
have
// any pure virtual functions.
//
static inline void ValidCtrCheck(TSDCalendar *)
{
new TSDCalendar(NULL);
}
//---------------------------------------------------------------------------
__fastcall TSDCalendar::TSDCalendar(TComponent* Owner)
: TGraphicControl(Owner)
// : TCustomControl(Owner)
{
TDateTime tdt;
unsigned short day;
iRed = 153;
iGreen = 188;
iBlue = 235;
tdt = TDateTime::CurrentDate();
tdt.DecodeDate(&iYear, &iMonth, &day);
bgColor = clDkGray;
txtColor = clWhite;
bgEventColor = clNavy;
bgSelectedDayColor = clDkGray;
txtEventColor = clWhite;
iSelectedDay = -1;
Visible = true;
Enabled = true;
}
//---------------------------------------------------------------------------
namespace Sdcalendar
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TSDCalendar)};
RegisterComponents("SunDial", classes, 0);
}
}
//---------------------------------------------------------------------------
void __fastcall TSDCalendar::Paint(void)
{
int iLeft;
int w = this->Width;
int h = this->Height;
int iDayCol;
int iRow;
TDateTime dtDate;
AnsiString asBuf;
//
// set up DateTime structure for use
//
dtDate = EncodeDate(iYear, iMonth + 1, (unsigned short)1);
iRowHeight = (this->Height * 0.95) / iNumRows;
iColWidth = (this->Width * 0.95) / iNumCols;
//
// Determine the maximum row height and column width
// given the control's current size
//
for (int i = 0; i < iNumRows; i++) {
iRowTops[i] = i * iRowHeight + (this->Height * 0.025);
}
for (int i = 0; i < iNumCols; i++) {
iColLefts[i] = i * iColWidth + (this->Width * 0.025);
}
//
// Fill the background
//
Canvas->Brush->Color = bgColor;
Canvas->FillRect(Rect(0,0, w, h));
Canvas->Font->Color = txtColor;
//
// Select the font
//
Canvas->Font->Name = "Arial";
Canvas->Font->Size = 8;
//
// Fill the 'month/year' string for display
//
asBuf = dtDate.FormatString("mmmm yyyy");
//
// Setup font to display month name and year
// using the full row height
//
Canvas->Font->Size = -iRowHeight * 72 /
Canvas->Font->PixelsPerInch;
iLeft = (this->Width / 2) - (Canvas->TextWidth(asBuf) / 2);
Canvas->TextOutA(iLeft, iRowTops[0], asBuf);
//
// Setup font to display day numbers in smaller font using
// less row height; remove bold style
//
float flFontSizeFactor = 0.9;
Canvas->Font->Size = -(iRowHeight*flFontSizeFactor) * 72 /
Canvas->Font->PixelsPerInch;
//
// Draw days of the week
//
// NOTE: eventually need this to follow windows setting for
// what day is the first day of the week.
//
Canvas->MoveTo(0 + (w * 0.05), iRowTops[1]);
Canvas->LineTo(w - (w * 0.05), iRowTops[1]);
Canvas->MoveTo(0 + (w * 0.05), iRowTops[2] - 1);
Canvas->LineTo(w - (w * 0.05), iRowTops[2] - 1);
for (int i = 0; i < iDaysInWeek; i++) {
CenterRectTextOut(iColLefts[i],
iRowTops[iDaysOfWeekRow],
iRowHeight, iColWidth,
szDays[i]);
}
//
// Draw the days of the month
//
iDayCol = dtDate.DayOfWeek() - 1;
for (int i = 1; i <= (int)DaysInMonth(dtDate); i++) {
dtDate = EncodeDate(iYear, iMonth + 1, (unsigned short)i);
iRow = 1 + ((int)(iDayCol+i-1) / (int)7);
//
// If an Event is scheduled for this day, highlight the day
// with a rounded rectangle
//
if (EventFlag[i] == true) {
int iCurvature = iColWidth / 4;
Canvas->Font->Color = txtEventColor;
Canvas->Brush->Color = bgEventColor;
Canvas->RoundRect(iColLefts[dtDate.DayOfWeek() - 1],
iRowTops[iRow + 1],
iColLefts[dtDate.DayOfWeek() - 1] +
iColWidth,
iRowTops[iRow + 1] + iRowHeight,
iCurvature, iCurvature);
}
//
// If the day has been selected by the user, highlight it.
//
if (iSelectedDay == i) {
int iCurvature = iColWidth / 4;
TColor tcSave = Canvas->Pen->Color;
Canvas->Font->Color = txtEventColor;
if (!EventFlag[i])
Canvas->Brush->Color = bgSelectedDayColor;
Canvas->Pen->Color = clSilver;
Canvas->RoundRect(iColLefts[dtDate.DayOfWeek() - 1],
iRowTops[iRow + 1],
iColLefts[dtDate.DayOfWeek() - 1] +
iColWidth,
iRowTops[iRow + 1] + iRowHeight,
iCurvature, iCurvature);
Canvas->Pen->Color = tcSave;
}
CenterRectTextOut(iColLefts[dtDate.DayOfWeek() - 1],
iRowTops[iRow+ 1],
iRowHeight, iColWidth,
IntToStr(i).c_str());
Canvas->Brush->Color = bgColor;
Canvas->Font->Color = txtColor;
}
}
//---------------------------------------------------------------------------
void __fastcall TSDCalendar::CenterTextOut(int x, int y, int w,
AnsiString str)
{
int left;
left = x + (w / 2) - (Canvas->TextWidth(str) / 2);
Canvas->TextOutA(left, y, str);
}
//---------------------------------------------------------------------------
void __fastcall TSDCalendar::CenterRectTextOut(int x, int y, int h,
int w, AnsiString str)
{
int left;
int top;
left = x + (w / 2) - (Canvas->TextWidth(str) / 2);
top = y + (h / 2) - (Canvas->TextHeight(str) / 2);
Canvas->TextOutA(left, top, str);
}
//---------------------------------------------------------------------------
void __fastcall TSDCalendar::SetMonth(const unsigned short Value)
{
if (Value > 12)
return;
iMonth = Value - 1;
Refresh();
}
//---------------------------------------------------------------------------
unsigned short __fastcall TSDCalendar::GetMonth(void)
{
return (iMonth + 1);
}
//---------------------------------------------------------------------------
void __fastcall TSDCalendar::SetYear(const unsigned short Value)
{
iYear = Value;
Refresh();
}
//---------------------------------------------------------------------------
void __fastcall TSDCalendar::SetTextColor(const TColor Value)
{
txtColor = Value;
Refresh();
}
//---------------------------------------------------------------------------
void __fastcall TSDCalendar::SetBGColor(const TColor Value)
{
bgColor = Value;
Refresh();
}
//---------------------------------------------------------------------------
void __fastcall TSDCalendar::SetTextEventColor(const TColor Value)
{
txtEventColor = Value;
Refresh();
}
//---------------------------------------------------------------------------
void __fastcall TSDCalendar::SetBGEventColor(const TColor Value)
{
bgEventColor = Value;
Refresh();
}
//---------------------------------------------------------------------------
void __fastcall TSDCalendar::MouseDown(TMouseButton Button,
TShiftState Shift,
int x, int y)
{
char szBuf[60];
int iDayClicked = -1;
TPoint tp;
TRect tr;
if (Shift.Contains(ssDouble) || Shift.Contains(ssLeft)) {
//
// Calculate which day was clicked.
//
sprintf(szBuf, "%d/1/%02d", iMonth+1,iYear%100);
TDateTime dtDate = StrToDate(szBuf);
int iDayCol = dtDate.DayOfWeek() - 1;
for (int i = 1; i <= (int)DaysInMonth(dtDate); i++) {
sprintf(szBuf, "%d/%d/%02d", iMonth+1, i, iYear%100);
TDateTime dtDate = StrToDate(szBuf);
int iRow = 1 + ((int)(iDayCol+i-1) / (int)7);
tp.x = x;
tp.y = y;
tr.left = iColLefts[dtDate.DayOfWeek() - 1];
tr.top = iRowTops[iRow+ 1];
tr.right = tr.left + iColWidth;
tr.bottom = tr.top + iRowHeight;
if (PtInRect(tr, tp)) {
iDayClicked = i;
}
}
}
if( Shift.Contains(ssDouble) && Shift.Contains(ssLeft) &&
iDayClicked > -1 ) {
if (FOnDayDblClick) {
FOnDayDblClick(this, iDayClicked);
}
}
if( Shift.Contains(ssLeft) && !Shift.Contains(ssDouble) &&
iDayClicked > -1 ) {
iSelectedDay = iDayClicked;
Refresh();
}
}
void __fastcall TSDCalendar::ClearEventFlags(void)
{
for (int i=0; i <= 31; i++) {
EventFlag[i] = false;
}
}
bool __fastcall TSDCalendar::GetEventFlag(const int Value)
{
if (Value <= 31) {
return bEventFlag[Value];
}
return false;
}
void __fastcall TSDCalendar::SetEventFlag(const int Index, const bool
Value)
{
if ((Index < 1) || (Index > 31))
return;
bEventFlag[Index] = Value;
}
=============================================================
|
|