|
|
|
|
Programmieren mit C++Code-Beispiele & LösungenAllgemeine visuelle ObjektklassenKlasse TCalendarEdit
|
Die Klasse TCalendarEdit erlaubt das Eingeben von Datumsangaben durch Auswahl aus einem Popup-Fenster, das mit der Edit Control verbunden ist und bei Bedarf über die Schaltfläche, die rechts neben der Edit Control gezeichnet wird, aufgeklappt werden kann. Die Datumseingabe läßt sich sowohl in allgemeinen Dialogen wie auch als Control in einem Standardfenster bzw. einer Werkzeugleiste plazieren.
Abbildung 7/2.1.1.7-1: Datumseingaben per Popup-Fenster eingeben
Die Formatierung der Datumseingabe ergibt sich über die Standard-Einstellungen des Windows-Systems sowie über Vorgaben der Control. Diese steuert die Formatierung der Datumsangaben sowie sämtliche Datumsberechnungen über die Klasse TIntlDate, die bei Bedarf individualisiert werden kann.
Die Klasse TCalendarEdit ist von TEdit abgeleitet. Der Konstruktor entspricht daher in den ersten beiden Varianten dem von TEdit bekannten Konstruktoren:
| |
TCalendarEdit(TWindow* parent, int id,
const char far* text,
int x, int y, int w, int h,
uint textLen = 0,
TModule* module = 0);
TCalendarEdit(TWindow* parent,
int resourceId,
uint textLen = 0,
TModule* module = 0);
TCalendarEdit(TGadgetWindow* parent,
int id, int w);
Der Konstruktor erzeugt ein Fenster der Klasse TCalendar-Edit, das einer Ressource zugeordnet wird. Diese kann entweder über den Dialog-Editor oder durch direkte Code-Anweisungen im Fenster plaziert worden sein.
| Konstruktor TCalendarEdit |
~TCalendarEdit();
Der Destruktor stellt sicher, daß die vom Konstruktor allokierten Elemente wieder freigegeben werden.
| Destruktor TCalendarEdit |
const TIntlDate& GetDate();
Die Memberfunktion GetDate returniert das aktuell eingegebene Datum im Format TIntlDate.
| Memberfunktion GetDate |
void SetText(const TIntlDate& date);
void SetText(const char far* str);
Das Setzen des Datums erfolgt wahlweise über einen String, der ein korrektes Datum spezifiziert, oder über einen Parameter vom Typ TIntlDate.
| Memberfunktion SetText |
static TIntlDate::HowToSpeak
SetLanguage(TIntlDate::HowToSpeak l);
Über SetLanguage wird die zu verwendende Sprache festgelegt. Die hierfür notwendigen Konstanten sind in der Klasse TIntlDate vorgegeben und können beliebig erweitert werden.
| Memberfunktion SetLanguage |
static TIntlDate::HowToPrint
SetPrintOption(TIntlDate::HowToPrint h);
Mit SetPrintOption wird die Formatierung des Datums spezifiziert. Auch diese Angabe kann über TIntlDate angepaßt und erweitert werden.
Interna der Implementierung
Objekte der Klasse TCalendarEdit reagieren auf Ereignisse vom Typ
- WM_CHAR
- WM_KEYDOWN
- WM_SIZE
Erstere werden zum Filtern der Tastatureingaben in der EditControl verwendet, während WM_SIZE abgefangen wird, um die zugehörige Schaltfläche nach einer Größenänderung korrekt zu plazieren.
Die Schaltfläche selbst ist ein Objekt vom Typ TCalendarBtn, der von TButton abgeleitet ist. Die einzige Funktion der Schaltfläche besteht darin, bei Betätigung ein Popup-Fenster zu erzeugen, das Eingaben per Maus akzeptiert, die dann an die Edit Control weitergegeben werden. Nach Auswahl eines Datums per Maus wird das Popup-Fenster automatisch wieder geschlossen. Das Popup-Fenster wird bereits im Konstruktor erzeugt und lediglich bei Bedarf angezeigt:
TCalendarBtn::TCalendarBtn(TWindow *parent,
TCalendarEdit* edit,
TModule* module)
: TButton(parent, 0, "", 0, 0, 0, 0,
false, module)
{
Attr.Style |= BS_OWNERDRAW;
Attr.Style &= ~WS_TABSTOP;
CalEdit = edit;
CalWin = new TPopupCalWin(Parent, edit, module);
CalWin->DisableAutoCreate();
BmpUp = new TBitmap(*GetApplication(), IDB_CALBTNUP);
BmpDn = new TBitmap(*GetApplication(), IDB_CALBTNDN);
if (TYPESAFE_DOWNCAST(Parent, TGadgetWindow))
CalEdit->Attr.H = BmpUp->Height();
}
Nach dem Anklicken wird das Popup-Fenster dann angezeigt:
void TCalendarBtn::EvClicked()
{
if (*CalWin)
return;
TRect r = CalEdit->GetWindowRect();
CalWin->Attr.X = r.left;
CalWin->Attr.Y = r.bottom;
CalWin->Create();
}
Das Popup-Fenster ist von der Klasse TPopupCalWin, die von TWindow abgeleitet wurde. Das Fenster zeichnet sich selbst und übernimmt sämtliche Eingaben von Tastatur und Maus. Jede gültige Eingabe bzw. Datumsauswahl wird an die zugehörige Edit Control weitergegeben, die im Konstruktor zu spezifizieren ist:
| Memberfunktion SetPrintOption |
TPopupCalWin(TWindow* parent,
TCalendarEdit* edit,
TModule* module = 0);
Der Konstruktor TPopupCalWin erwartet als erste Parameter Zeiger auf das Elternfenster sowie die zugehörige EditControl.
| Konstruktor TPopupCalWin | |
Das Zeichnen des Kalenderfensters durch die Methode Paint ist die aufwendigste Funktion der Klasse. Sie soll hier etwas genauer vorgestellt werden, da Anpassungen und Änderungen aller Art in dieser Funktion vorzunehmen wären.
| Kalender zeichnen |
void TPopupCalWin::Paint(
TDC& dc,
bool /* Hintergrund löschen */,
TRect& /* Rechteck */)
Die Memberfunktion Paint zeichnet den Kalender abhängig vom aktuell eingestellten Datum des Popup-Fensters, das beim erstmaligen Anzeigen mit der Eingabe in der EditControl übereinstimmt, sofern dort ein gültiges Datum vorliegt, ansonsten wird das aktuelle Systemdatum als Vorgabe gesetzt.
| Memberfunktion Paint | |
Die Funktion bestimmt als erstes den ersten Wochentag sowie das Clientrechteck und selektiert anschließend den benötigten Font für die nachfolgenden Ausgaben der Kalenderüberschriften:
{
int i;
TRect r;
int weekday = Date.WeekDay(1);
TRect clientRect = GetClientRect();
PaintBorders(dc, clientRect);
dc.SelectObject(*Font);
dc.SetBkMode(TRANSPARENT);
| Vorbereitung | |
Die Pfeile zum Blättern im Kalender werden über Bitmaps einkopiert, die durch den Konstruktor aus den Ressourcen geladen wurden:
TMemoryDC memDC(dc);
memDC.SelectObject(*BmpPrev);
dc.BitBlt(BtnPrevRect, memDC, TPoint(0,0));
memDC.SelectObject(*BmpNext);
dc.BitBlt(BtnNextRect, memDC, TPoint(0,0));
| Pfeile anzeigen | |
Im nächsten Schritt erfolgt die Ausgabe des Monatsnamens:
char buf[80];
wsprintf(buf, "%s %d", Date.NameOfMonth(), Date.Year());
r = TRect(0, MonthRow, clientRect.right, MonthRow + FontHeight);
dc.DrawText(buf, -1, r, DT_CENTER | DT_VCENTER);
| Monatsnamen | |
Die Kurzbezeichnungen der Wochentage werden als Spaltenüberschriften für den Kalender im Kopfteil gesetzt, wobei als erster Wochentag derjenige verwendet wird, der zuvor durch Date.Weekday bestimmt wurde:
r = TRect(StartCol, WeekDaysRow, StartCol + FontWidth,
WeekDaysRow + FontHeight);
for (i = 0; i < 7; i++) {
dc.DrawText(Date.ShortDayName(i+1).c_str(), -1, r,
DT_CENTER | DT_VCENTER);
r.left += FontWidth;
r.right += FontWidth;
}
| Spaltenüber-schriften | |
Der Hintergrund des Kalenderbereichs wird per PatBlt mit einem grauen Pinsel eingefärbt:
dc.SaveDC();
clientRect.top = WeekDaysRow + FontHeight;
clientRect.bottom = clientRect.top + 2;
dc.SelectObject(TBrush(TColor(TColor::Gray)));
dc.PatBlt(clientRect.left, clientRect.top,
clientRect.Width() - 1, 1, PATCOPY);
dc.SelectObject(TBrush(TColor(TColor::White)));
dc.PatBlt(clientRect.left, clientRect.bottom - 1,
clientRect.Width(), 1, PATCOPY);
dc.RestoreDC();
| Hintergrund | |
Das Ausgaberechteck für die Kalendertage ergibt sich aus den Werten:
r = TRect(StartCol + ((weekday -1) * FontWidth), DaysRow,
StartCol + ((weekday -1) * FontWidth) + FontWidth,
DaysRow + FontHeight);
| Ausgaberechteck bestimmen | |
Nach diesen Vorarbeiten können die maximal 31 Tage des Monats, dessen Länge über Date.DaysInMonth bestimmt wird, in einer Schleife ausgegeben werden. Dabei werden automatisch Umbrüche gemäß der Wocheneinteilung vorgenommen, indem die Ränder des Ausgaberechtecks angepaßt werden. Ist eine Woche beendet, wird der obere Rand entsprechend inkrementiert, so daß die Ausgabe eine Zeile tiefer erfolgt:
for (i = 1; i <= Date.DaysInMonth(); i++, weekday++) {
char buf[3];
dc.DrawText(itoa(i, buf, 10), -1, r, DT_CENTER | DT_VCENTER);
r.left += FontWidth;
r.right += FontWidth;
if (weekday % 7 == 0) {
r.left = StartCol;
r.right = StartCol + FontWidth;
r.top += FontHeight;
r.bottom += FontHeight;
}
}
| Monatstage ausgeben | |
Für den aktuellen Tag wird anschließend ein Fokusrechteck gezeichnet:
DrawFocusRect(dc, Date.WeekDay()-1,
(Date.DayOfMonth()+Date.WeekDay(1)-2)/7);
}
Erweiterungen
Die vorgestellte Control ist in der vorliegenden Fassung komplett einsatzfähig. Erweiterungen wären im Sprachumfang der Klasse TIntlDate denkbar, da auch BC++ nicht alle Sprachen unterstützt, sondern einfach die englischen Bezeichner in Formatanweisungen einsetzt.
Durch Anpassung der Memberfunktion Paint der Klasse TPopupCalWin kann das Aussehen des Kalenders individuell gestaltet werden.
| Fokusrechteck
|
|
|