Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Daten bei TMonthCalendar markieren (https://www.delphipraxis.net/103842-daten-bei-tmonthcalendar-markieren.html)

blackdrake 22. Nov 2007 15:24


Daten bei TMonthCalendar markieren
 
Hallo.

Ich möchte bei einem TMonthCalendar bestimmte Daten markieren. Ich habe folgenden Codeteil gefunden:

Delphi-Quellcode:
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;
Die Probleme sind jetzt:

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

blackdrake 23. Nov 2007 14:41

Re: Daten bei TMonthCalendar markieren
 
Keine eine Ahnung?

Alter Mann 23. Nov 2007 17:28

Re: Daten bei TMonthCalendar markieren
 
Hi,

zu 1)
Delphi-Quellcode:
  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 2) kein Vorschlag

zu 3)
Delphi-Quellcode:
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;
Hätte man mit Hilfe der Hilfe(BoldDays) und ein bischen Suchen in der DP (dynamisches Array) auch selber rauskriegen können.

Also, bessere Dich.

Gruß

shmia 23. Nov 2007 17:38

Re: Daten bei TMonthCalendar markieren
 
Ich denke mal, TMonthCalendar bringt einfach nicht genügend Features mit.
Schau dich mal hier um: http://www.torry.net/pages.php?id=293

blackdrake 23. Nov 2007 17:55

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

Alter Mann 24. Nov 2007 18:31

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ß

blackdrake 28. Nov 2007 16:46

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:
mntCalendarGetMonthInfo(mntCalendar, 11, ...);
mntCalendarGetMonthInfo(mntCalendar, 12, ...);
mntCalendarGetMonthInfo(mntCalendar, 1, ...);
mntCalendarGetMonthInfo(mntCalendar, 2, ...);
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?

Gruß
blackdrake

blackdrake 9. Dez 2007 14:06

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.

Alter Mann 9. Dez 2007 14:55

Re: Daten bei TMonthCalendar markieren
 
Hi blackdrake,

14 Monate? Den Screen möchte ich sehen!

Gruß

blackdrake 9. Dez 2007 15:07

Re: Daten bei TMonthCalendar markieren
 
Es geht um die Theorie. Wenn ich was mache, dann soll es unter allen Bedingungen funktionieren und dynamisch sein.

blackdrake 9. Dez 2007 17:44

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

Alter Mann 9. Dez 2007 18:06

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ß

blackdrake 9. Dez 2007 18:52

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:
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;
Gruß
blackdrake

blackdrake 13. Dez 2007 14:43

Re: Daten bei TMonthCalendar markieren
 
Keiner eine Lösung?

Alter Mann 13. Dez 2007 18:40

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:

// MCN_GETDAYSTATE is sent for MCS_DAYSTATE controls whenever new daystate
// information is needed (month or year scroll) to draw bolding information.
// The app must fill in cDayState months worth of information starting from
// stStart date. The app may fill in the array at prgDayState or change
// prgDayState to point to a different array out of which the information
// will be copied. (similar to tooltips)
Gruß

blackdrake 14. Dez 2007 19:08

Re: Daten bei TMonthCalendar markieren
 
Hallo.

Danke für den Tipp. Leider hab ich hier ein Problem mit der Umsetzung:

Delphi-Quellcode:
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;
Ich hab mir dieses CN_NOTIFY Modell von folgendem Tutorial abgeleitet: http://delphi.about.com/od/delphitip...iewchecked.htm

Im Delphi-Quelltext ist TMonthCalendar.WindowProc folgendermaßen deklariert:

Delphi-Quellcode:
property WindowProc: TWndMethod read FWindowProc write FWindowProc;

type
  TWndMethod = procedure(var Message: TMessage) of object;
Ich denke also, dass die Funktion CalendarWindowProcEx korrekt deklariert ist. Aber was soll der Fehler bedeuten?

Gruß
blackdrake

blackdrake 14. Dez 2007 19:33

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:
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;
Gruß
blackdrake

CmdrRicK 9. Mär 2009 09:53

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:

http://qc.embarcadero.com/wc/qcmain.aspx?d=26318

Delphi-Quellcode:
//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;
anstatt die VCL Quellen zu überschreiben kann man natürlich einfach eine eigene Komponente ableiten...

entschuldigt bitte die Threadnekromantie, aber anderen Suchenden ist damit evtl geholfen

blackdrake 12. Mär 2009 22:54

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