![]() |
Daten bei TMonthCalendar markieren
Hallo.
Ich möchte bei einem TMonthCalendar bestimmte Daten markieren. Ich habe folgenden Codeteil gefunden:
Delphi-Quellcode:
Die Probleme sind jetzt:
procedure TMainForm.mntCalendarGetMonthInfo(Sender: TObject; Month: Cardinal;
var MonthBoldInfo: Cardinal); begin if Month = 10 then mntCalendar.BoldDays([1,2,5],MonthBoldInfo); if Month = 11 then mntCalendar.BoldDays([3,21,28],MonthBoldInfo); end; 1. Ich möchte auch das Jahr überprüfen. Der 11.10.2007 soll also anders markiert werden als der 11.10.2006. YearOf(mntCalendar.Date) ist keine gute Lösung, da 3 Monate zugleich angezeigt werden und so würde bei der Anzeige des Januar 2007 der Dezember 2006 als Dezember 2007 gesehen werden, oder? 2. Ich möchte die Datumsangaben möglichst mit 2 verschiedenen Merkmalen versehen. Wie kann ich eine Zahl rot schreiben lassen oder unterlegen? 3. Wie kann ich ein dynamisches Array [1, 5, 12] während der Laufzeit erstellen? Ich möchte Daten auslesen und dementsprechend eine unbekannte Anzahl von Tagen markieren. Hat jemand Ratschläge für mich? Gruß blackdrake |
Re: Daten bei TMonthCalendar markieren
Keine eine Ahnung?
|
Re: Daten bei TMonthCalendar markieren
Hi,
zu 1)
Delphi-Quellcode:
zu 2) kein Vorschlag
if (Sender is TMonthCalendar) then
begin DecodeDate((Sender as TMonthCalendar).Date, Y, M, D); case Y of 2005 : case M of 1 : (Sender as TMonthCalendar).BoldDays(DynArrRec[0].Months[0].Days, MonthBoldInfo); 2 : (Sender as TMonthCalendar).BoldDays(DynArrRec[0].Months[1].Days, MonthBoldInfo); end; end; end; zu 3)
Delphi-Quellcode:
Hätte man mit Hilfe der Hilfe(BoldDays) und ein bischen Suchen in der DP (dynamisches Array) auch selber rauskriegen können.
type
MonthsArr = record Month: Integer; Days : Array of LongWord; end; DynCalArr = record Year : Word; Months : Array of MonthsArr; end; var DynArrRec : Array of DynCalArr; procedure TForm1.FillDynaArrayRec; begin SetLength(DynArrRec, 1); // 1 Jahr DynArrRec[0].Year := 2005; // 2005 SetLength(DynArrRec[0].Months, 2); // 2 Monate DynArrRec[0].Months[0].Month := 1; // Januar SetLength(DynArrRec[0].Months[0].Days, 4); // 4 Tage DynArrRec[0].Months[0].Days[0] := 1; DynArrRec[0].Months[0].Days[1] := 8; DynArrRec[0].Months[0].Days[2] := 17; DynArrRec[0].Months[0].Days[3] := 25; DynArrRec[0].Months[1].Month := 2; // Februar SetLength(DynArrRec[0].Months[1].Days, 1); // 1 Tag DynArrRec[0].Months[1].Days[0] := 15; end; Also, bessere Dich. Gruß |
Re: Daten bei TMonthCalendar markieren
Ich denke mal, TMonthCalendar bringt einfach nicht genügend Features mit.
Schau dich mal hier um: ![]() |
Re: Daten bei TMonthCalendar markieren
Hallo.
Wäre irgendwie blöd, wenn ich eine Fremd-VCL nur wegen verschiedenfarbiger Markierungen verwenden müsste. Aber ich guck mir mal alle Freeware's an. @Alter Mann (zu 1). Das dachte ich mir auch schon mit dem Date auslesen. Aber der Kalender zeigt ja (je nach Fenstergröße mehrere Monate nebeneinander an. Was ist, wenn ich Januar 2007 wähle und der Dezember mit angezeigt wird? Dann denkt das Programm, es würde sich um den Dezember des Jahres YearOf(x. Januar 2007) = 2007 handeln, also Dezember 2007 und die Markierungen falsch setzen. Und da das Fenster theoretisch unendlich groß werden kann, hab ich irgendwie ein Problem. Dynamische Arrays guck ich mir nach der Lösung dieses Grundproblemes an. Gruß blackdrake |
Re: Daten bei TMonthCalendar markieren
Hallo blackdrake,
sicher zeigt er je nachdem wie Groß er aufgezogen ist, mehrere Monate/Jahre an, aber immer in Zeilen und Spalten und die Matrix wird nie größer als 3x4, also 12 Monate in max. 2 Jahren. Und was viel wichtiger ist, GetMonthInfo wird zuerst immer mit dem Monat oben links aufgerufen. Damit hat man das Jahr an dem die Zählung beginnt und braucht nur noch die Monate, also 1, 2, 3 usw., mitzuzählen und die Werte zuweisen. Alles Klar? Gruß |
Re: Daten bei TMonthCalendar markieren
Hallo.
Ich komme immer noch nicht so richtig zurecht. Gehen wir mal von folgendem Beispiel aus: Das Fenster sei so groß, dass 4 Monate angezeigt werden: November 2006, Dezember 2006, Januar 2007, Februar 2007. Es wird nun beim Wechseln der Ansicht folgende Befehlsfolge ausgeführt:
Code:
Ich weiß ebenfalls das Jahr zu dem Eintrag, den ich markiert habe. Aber woher weiß ich nun, welches Jahr zu welcher Zahl gehört? Woher weiß die Funktion mntCalendarGetMonthInfo(mntCalendar, 11, ...), dass sie die erste aufgerufene ist und dass kein Monat vor Ihr dran kam? Ich möchte die Erkennung des Jahres möglichst ohne problematische Codestellen realisieren. Rein theoretisch (aber wg. Auflösung nicht praktisch) könnte ich das Fenster ja auch so groß ziehen, dass 14 Monate untereinander gezeigt werden und dann müsste ich zwischen 3 Jahren unterscheiden. Das ist so kompliziert! :( Gibts da eine einfache Lösung? Denke ich zu verdreht?
mntCalendarGetMonthInfo(mntCalendar, 11, ...);
mntCalendarGetMonthInfo(mntCalendar, 12, ...); mntCalendarGetMonthInfo(mntCalendar, 1, ...); mntCalendarGetMonthInfo(mntCalendar, 2, ...); Gruß blackdrake |
Re: Daten bei TMonthCalendar markieren
Gibts dafür jetzt keine Lösung, weil nichts kommt? Die (Freeware) VCLs von Torry.net waren alle Müll, zum Großteil nicht mal im Windows-Design.
|
Re: Daten bei TMonthCalendar markieren
Hi blackdrake,
14 Monate? Den Screen möchte ich sehen! Gruß |
Re: Daten bei TMonthCalendar markieren
Es geht um die Theorie. Wenn ich was mache, dann soll es unter allen Bedingungen funktionieren und dynamisch sein.
|
Re: Daten bei TMonthCalendar markieren
OK, gehen wir mal nur von folgenden Dingen aus:
1. Statische Markierung (dynamische Folgt aus dieser Lösung dann heraus) 2. Es seien nur maximal 2 Jahre auf dem Calendar zu sehen. Wie kann ich dann bei mntCalendarGetMonthInfo() das Jahr errechnen? Ich komme wie gesagt mit der Beschreibung von "Alter Mann" nicht weiter. Gruß blackdrake |
Re: Daten bei TMonthCalendar markieren
Liste der Anhänge anzeigen (Anzahl: 1)
So, So,
was soll da denn noch erklärt werden? GetMonthInfo wird nun mal von oben links nach unten rechts für jeden dargestellten Monat aufgerufen! Dazu wird immer der jeweils für diesen (aktuellen) Monat der Monat als ZAHL übergeben und wenn (bei 3x4 Monaten) oben links Mai 2008 steht, heiß es, GetMonthInfo wird in der Reihenfolge 5,6,7,8,9,10,11,12,1,2,3,4 aufgerufen! Und da der Mai nach dem April kommt, ist es auch klar welches Jahr aktuell ist. Es gibt nun mal Sachen, die sind so wie sie sind und daran kann man nichts ändern, was soll's. Geht davon aus und reagiere erst wenn sich daran etwas ändert, du kannst unmöglich Änderungen voraussehen. Gruß |
Re: Daten bei TMonthCalendar markieren
Hallo.
Ja, das habe ich klar verstanden. Mein Problem ist aber: Woher soll GetMonthInfo() wissen, dass es zum ersten Mal (seit dem letzten "Scrollen" durch die Monate) aufgerufen ist? Es gibt auch kein Event, das aufgerufen wird, wenn der Benutzer durch die Monate scrollt. Ansonsten würde ich bei dem Scroll-Event eine Variable auf das aktuelle Jahr setzen und diese Variable bei jedem GetMonthInfo() für Januar um 1 erhöhen. Ich komme einfach nicht drauf, wie ich ohne ein solches Event auf das aktuelle Jahr von GetMonthInfo() kommen soll!
Delphi-Quellcode:
Gruß
procedure TForm1.MonthCalendar1GetMonthInfo(Sender: TObject; Month: Cardinal;
var MonthBoldInfo: Cardinal); var jahr, monat, tag: word; begin DecodeDate(monthcalendar1.Date, jahr, monat, tag); if Month > Monat then begin memo1.lines.add(inttostr(Month)+'/'+inttostr(jahr+1)); end else begin memo1.lines.add(inttostr(Month)+'/'+inttostr(jahr)); end; end; blackdrake |
Re: Daten bei TMonthCalendar markieren
Keiner eine Lösung?
|
Re: Daten bei TMonthCalendar markieren
Hi blackdrake,
hast Du den Source von ComCtrls und CommCtrl? Wenn JA dann schau Dir procedure TMonthCalendar.CNNotify(var Message: TWMNotify); (ComCtrls) und tagNMDAYSTATE = packed record(CommCtrl) an. Wenn NEIN dann musst Du damit leben. Zitat:
|
Re: Daten bei TMonthCalendar markieren
Hallo.
Danke für den Tipp. Leider hab ich hier ein Problem mit der Umsetzung:
Delphi-Quellcode:
Ich hab mir dieses CN_NOTIFY Modell von folgendem Tutorial abgeleitet:
private
OriginalCalendarWindowProc: TWndMethod; procedure CalendarWindowProcEx(var Message: TMessage); procedure TForm1.CalendarWindowProcEx(var Message: TMessage); begin if Message.Msg = CN_NOTIFY then begin memo1.lines.add('Message CN_NOTIFY ('+inttostr(message.Msg)+')'); end; end; procedure TForm1.FormCreate(Sender: TObject); begin OriginalCalendarWindowProc := MonthCalendar1.WindowProc; // EOSError: Ein Aufruf einer Betriebssystemfunktion ist fehlgeschlagen MonthCalendar1.WindowProc := CalendarWindowProcEx; end; ![]() Im Delphi-Quelltext ist TMonthCalendar.WindowProc folgendermaßen deklariert:
Delphi-Quellcode:
Ich denke also, dass die Funktion CalendarWindowProcEx korrekt deklariert ist. Aber was soll der Fehler bedeuten?
property WindowProc: TWndMethod read FWindowProc write FWindowProc;
type TWndMethod = procedure(var Message: TMessage) of object; Gruß blackdrake |
Re: Daten bei TMonthCalendar markieren
Danke nochmal für die Hilfe. Ich habe es nun mit dem CN_NOTIFY lösen können.
Über farbliche Markierungen (OwnerDraw?) mache ich mir zu einem anderen Zeitpunkt gedanken.
Delphi-Quellcode:
Gruß
type
TDynArrayLongWord = array of LongWord; TForm1 = class(TForm) MonthCalendar1: TMonthCalendar; Memo1: TMemo; procedure MonthCalendar1GetMonthInfo(Sender: TObject; Month: Cardinal; var MonthBoldInfo: Cardinal); procedure FormCreate(Sender: TObject); private OriginalCalendarWindowProc: TWndMethod; jahr_zusatz: integer; procedure CalendarWindowProcEx(var Message: TMessage); end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.CalendarWindowProcEx(var Message: TMessage); begin if Message.Msg = CN_NOTIFY then begin jahr_zusatz := 0; end; OriginalCalendarWindowProc(Message); end; procedure TForm1.FormCreate(Sender: TObject); begin OriginalCalendarWindowProc := MonthCalendar1.WindowProc; MonthCalendar1.WindowProc := CalendarWindowProcEx; end; function MyMonthMarker(Month, Year: integer): TDynArrayLongWord; begin // Zum Test SetLength(result, 2); result[0] := month; result[1] := year-2000; end; procedure TForm1.MonthCalendar1GetMonthInfo(Sender: TObject; Month: Cardinal; var MonthBoldInfo: Cardinal); var jahr, monat, tag: word; begin DecodeDate(monthcalendar1.Date, jahr, monat, tag); (Sender as TMonthCalendar).BoldDays(MyMonthMarker(Month, jahr+jahr_zusatz), MonthBoldInfo); if month = 12 then inc(jahr_zusatz); end; blackdrake |
Re: Daten bei TMonthCalendar markieren
Da ich grade mit einem ähnlichen Problem beschäftigt bin und über diesen Thread gestolpert bin, wollte ich kurz hinterlassen was ich bereits als mögliche Lösung entdeckt habe. Auf QualityCentral findet man folgenden Workaround:
![]()
Delphi-Quellcode:
anstatt die VCL Quellen zu überschreiben kann man natürlich einfach eine eigene Komponente ableiten...
//Edit ComCtrls.pas to change the TOnGetMonthInfoEvent type definition:
TOnGetMonthInfoEvent = procedure(Sender: TObject; Month, Year: LongWord; var MonthBoldInfo: LongWord) of object; //and change the (private) TMonthCalendar.CNNotify method adding the lines with comments: procedure TMonthCalendar.CNNotify(var Message: TWMNotifyMC); var ST: TSystemTime; I, MonthNo, YearNo: Integer; // Add year {$IF DEFINED(CLR)} DayState: TNMDayState; CurState: TMonthDayStateArray; {$ELSE} DayState: PNMDayState; CurState: PMonthDayState; {$IFEND} begin with Message, NMHdr{$IFNDEF CLR}^{$ENDIF} do begin case code of MCN_GETDAYSTATE: begin DayState := NMDayState; with DayState{$IFNDEF CLR}^{$ENDIF} do begin {$IF DEFINED(CLR)} SetLength(CurState, cDayState); {$ELSE} FillChar(prgDayState^, cDayState * SizeOf(TMonthDayState), 0); {$IFEND} if Assigned(FOnGetMonthInfo) then begin {$IF DEFINED(CLR)} CurState := TMonthDayStateArray(NativeBufToArray(prgDayState, CurState)); {$IFEND} for I := 0 to cDayState - 1 do begin YearNo := stStart.wYear; // Get year MonthNo := stStart.wMonth + I; if MonthNo > 12 then begin Inc(YearNo); // Update year MonthNo := MonthNo - 12; end; {$IF DEFINED(CLR)} FOnGetMonthInfo(Self, MonthNo, YearNo, CurState[I]); // Pass year {$ELSE} FOnGetMonthInfo(Self, MonthNo, YearNo, CurState^); // Pass year Inc(CurState); {$IFEND} end; end; {$IF DEFINED(CLR)} prgDayState := ArrayToNativeBuf(CurState, prgDayState); NmDayState := DayState; {$IFEND} end; end; MCN_SELECT, MCN_SELCHANGE: with NMSelChange{$IFNDEF CLR}^{$ENDIF} do begin ST := stSelStart; if not IsBlankSysTime(ST) then FDateTime := SystemTimeToDateTime(ST); if FMultiSelect then begin ST := stSelEnd; if not IsBlankSysTime(ST) then FEndDate := SystemTimeToDateTime(ST); end; end; end; end; inherited; end; entschuldigt bitte die Threadnekromantie, aber anderen Suchenden ist damit evtl geholfen |
Re: Daten bei TMonthCalendar markieren
Hallo.
Danke für deine Antwort. Ich werde es die nächsten Tage mal ausprobieren. Quasi alle meiner noch offenen Threads interessieren mich tatsächlich immer noch. Meist habe ich das Feature oder gar das Projekt liegengelassen, weil ich keine Lösung für etwas fand. Ist also nicht negativ, dass du das Thema wiederbelebt hast. Gruß blackdrake |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:14 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz