TDate Datum in TMonthCalendar anzeigen
-
Linnea schrieb:
kpeter schrieb:
Mit Betonung auf 31 statt 0. Denn soviele Tage kann ein Monat haben...
ich glaub die Zahl gibt eher die Menge der Elemente im Array an,
Das war jetzt eher überflüssig.
Da man ja nun nicht weiss, wieviele Tage der Anwender fett dargestellt haben will,
legt man das Array im Vorhinein auf 31 Tage aus. Das dies dann die Anzahl der Arrayelemente ist,
ist wohl klar.
-
also ich muss wohl etwas weiter ausholen.
ich mache zurzeit ein projekt bei dem ich ein kühlschrank über einen rfid reader produkte und das mindeshaltbarkeitsdatum erkennen lasse.
jetzt wollte ich wenn die rfid transponder eingelesen werden das datum an so einem kalender anzeigen lassen.
(eventuell falls möglich noch durch klick auf das jeweilige datum, direkt zu den produkten die an dem tag ablaufen wechseln und falls möglich wenn man über das datum fäht das eine kleine nachrichtkommt die ebenfalls die ablaufenden produkte anzeigt)das eingelesene mhd ist als tdate deklariert.
jetzt dachte ich mir ich löse das neuhinzufügen von frisch eingelesen mhds so:
TDateTime date[2] = {TDateTime("01.01.1990"),TDateTime("01.01.1990")};
for (int u=1; u < 2; u++)
{
if (date[u]=="01.01.1990")
{
date[u]=MHD;
u=3;
}}
ich erstelle das array date mit den 2 werten ("01.01.1990") als standartwert. wenn jetzt ein neues datum eingelesen wird, wird es in mhd übergeben!
jetzt will ich abfragen wenn ein neues übergeben wird an welcher stelle noch ein standartdatum ("01.01.1990") steht und es durch das neue ersetzen. klingt sicherlich nicht ganz profesionell und sicherlich gibt es noch einfachere und übersichtlichere methoden aber diese hier kam mir zuerst in den kopf:)
-
ahh ich habs es funktioniert....
mein problem war ich hab anstatt = den vergleich mit == geschrieben...
so einfach kanns sein:)
void __fastcall TForm1::MonthCalendar1GetMonthInfo(TObject *Sender, DWORD Month, DWORD &MonthBoldInfo) { MHDX = "21.04.2010"; int j = 0; TDateTime date[2] = {TDateTime("01.01.1990"),TDateTime("01.01.1990")}; for (int u=1; u < 2; u++) { if (date[u]=="01.01.1990") { date[u]=MHDX; u=3; } } WORD day,month,year,hour,minute,seconde,millisecond; unsigned Buffer = MonthBoldInfo; for (int i = 0; i < 2; i++) { DecodeDateTime(date[i],year,month,day,hour,minute,seconde,millisecond); unsigned bolddays[31]; if (Month == month) { bolddays[j] = day; MonthCalendar1->BoldDays(bolddays,j,Buffer); j++; } } MonthBoldInfo = Buffer; }
-
was nicht funktioniert hast du immernoch nicht gesagt...
in deinem Quellcode ist ein Fehler in der For-Schleife: u muß bei 0 beginnen, da jedes Array mit dem Index 0 anfängt
außerdem stimmt die Abfrage nicht ganz:TDateTime date[2] = {TDateTime("01.01.1990"),TDateTime("01.01.1990")}; for (int u=0; u < 2; u++) { if (date[u]==TDateTime("01.01.1990")) { date[u]=MHD; break; } }
aber damit wird immer wieder das erste Datum überschreiben, weil du die Definition für das Datums-Array in der Funktion MonthCalendar1GetMonthInfo stehen hast und nicht als Variable der Klasse, da bei jedem Aufruf der Funktion das Datums-Array neu erstellt wird -> Thema "Variablengültigkeit/Scop"
außerdem bist du so immer auf 2 Datumswerte begrenzt
hast du die MHD alle in einer Datenbank oder werden die nur zum Zeitpunkt des "Einlesens" dargestellt?
-
Linnea schrieb:
was nicht funktioniert hast du immernoch nicht gesagt...
sorry:) es wurde kein oder nur ein datum angezeigt!
Linnea schrieb:
aber damit wird immer wieder das erste Datum überschreiben, weil du die Definition für das Datums-Array in der Funktion MonthCalendar1GetMonthInfo stehen hast und nicht als Variable der Klasse, da bei jedem Aufruf der Funktion das Datums-Array neu erstellt wird -> Thema "Variablengültigkeit/Scop"
ok reicht es wenn ich die variable einfach global definiere?
Linnea schrieb:
außerdem bist du so immer auf 2 Datumswerte begrenzt
ich kann das ganze ja noch endlos erweitern...
Linnea schrieb:
hast du die MHD alle in einer Datenbank oder werden die nur zum Zeitpunkt des "Einlesens" dargestellt?
jaa ich hab die ganzen datums(daten!?) in einer access datenbank stehen die ich über eine ado connection und nem query in meinem programmcode zugreife..
-
Otz110 schrieb:
jaa ich hab die ganzen datums(daten!?) in einer access datenbank stehen die ich über eine ado connection und nem query in meinem programmcode zugreife..
na dann ist es doch recht einfach: mach die SQL-Abfrage in die Funktion, beim SQL-Kommando kannst du sogar nur die mit dem gerade angezeigten Monat eingrenzen, dann ein Feld mit den Werten füllen und anzeigen, fertig.
-
Linnea schrieb:
na dann ist es doch recht einfach: mach die SQL-Abfrage in die Funktion, beim SQL-Kommando kannst du sogar nur die mit dem gerade angezeigten Monat eingrenzen, dann ein Feld mit den Werten füllen und anzeigen, fertig.
hmm einfach
dann will ichs mal probieren
ich hab mir meine sql anweisung
Form3->ADOQuery1->SQL->Clear(); Form3->ADOQuery1->SQL->Add("Select MHD From DerInhalt"); Form3->ADOQuery1->Open();
dann hab ich hier mein kalenderprogramm von vorhin:
MHDX = "21.04.2010"; int j = 0; TDateTime date[2] = {TDateTime("01.01.1990"),TDateTime("01.01.1990")}; for (int u=1; u < 2; u++) { if (date[u]=="01.01.1990") break; { date[u]=MHDX; u=3; } } WORD day,month,year,hour,minute,seconde,millisecond; unsigned Buffer = MonthBoldInfo; for (int i = 0; i < 2; i++) { DecodeDateTime(date[i],year,month,day,hour,minute,seconde,millisecond); unsigned bolddays[31]; if (Month == month) { bolddays[j] = day; MonthCalendar1->BoldDays(bolddays,j,Buffer); j++; } } MonthBoldInfo = Buffer;
aber jetzt zusammenfügen?!?!?!?!?
wohin werden die mhds aus der tabele gespeichert wenn ich sie mit meiner sql abrufe?
-
ungetestet, aber ein bißchen was kannst du ja auch selbst machen:
ADOQuery1->SQL->Clear(); ADOQuery1->SQL->Add("Select distinct day(MHD) as ttag From DerInhalt where month(MHD) = :monat "); ADOQuery1->Parameters->ParamByName("monat")->Value = Month; ADOQuery1->Open(); int count = ADOQuery1->RecordCount; if (count <= 0) return; unsigned feld[31]; unsigned Buffer = MonthBoldInfo; for (ADOQuery1->First();!ADOQuery1->Eof;ADOQuery1->Next()) { feld[ADOQuery1->RecNo-1] = ADOQuery1->FieldByName("ttag")->AsInteger; } MonthCalendar1->BoldDays(feld,count-1,Buffer); ADOQuery1->Close(); MonthBoldInfo = Buffer;
[Edit] ups da hab ich wohl noch die Abfrage nach dem Jahr des angezeigten Kalender vergessen
-
hmm das funktioniert ja schon aber irgendwie markiert er mir nur die mhds von april und mai...
hab in der tabelle aber noch von oktober... und von nächstem jahr stehen.
was ist da denn der fehler? ist das array zu klein gewählt?
-
Nein, die SQL-Abfrage ist, so wie sie da steht, unvollständig: es fehlt die Abfrage des Jahres, dazu brauchst du die Information in welchem Kalenderblatt du grad bist und die bekommst du aus Date vom MonthCalender. Und noch als Tip: YearOf gibt das Jahr eines Datumswertes zurück.
das Array kann - wie ja kpeter schon feststellte - nur maximal 31 Tage haben, soviel Tage hat nunmal ein Monat maximal
und jetzt bitte mal das Hirnschmalz umrühren :p
-
Hallo,
auch ich muss einen Hinweis hinzutun, da ich denke, dass das Verhalten der Komponente noch nicht
ganz bewusst ist.Je nachdem, wie weit die Komponente auf dem Formular aufgezogen ist, und somit Monate sichtbar sind,
sooft tritt (bereits bei Programmstart) das Ereignis OnGetMonthInfo auf.Dazu kommt ein OnGetMonthInfo für den Vormonat und eins für einen Monat nach den letzten abgebildeten.
D.h., wenn drei Monate von der Kompo abgebildet werden, treten 5 Ereinisse auf. Leicht nachzuprüfen im Debug-Modus.
Die Daten für diese Monate müssen also bereitstehen, damit die Anzeige der Bolddays korrekt erfolgt.mfg
kpeter
-
ohje... ihr überfordert mich gerade ein bischen....
das ganze ist für mich totales neuland....
ich probier mal bischen rum. meld mich dann wieder!
-
Linnea schrieb:
es fehlt die Abfrage des Jahres, dazu brauchst du die Information in welchem Kalenderblatt du grad bist und die bekommst du aus Date vom MonthCalender. Und noch als Tip: YearOf gibt das Jahr eines Datumswertes zurück.
hmm ich hab ne idee aber kein plan ob ich auf dem richtigen weg bin...
also meine "idee":
ich muss mittels ner if schleife schauen ob das date vom monthcalender = yearof dem wert dem mhd den ich mittels einer sql anweisung aus meiner tabelle auslese.
falls das richtig sein sollte, hab ich leider kein plan wie ich das um setzen soll...
-
einfacher ists die SQL-Anweisung um die Suche nach dem Jahr zu erweitern:
ADOQuery1->SQL->Clear(); ADOQuery1->SQL->Add("Select distinct day(MHD) as ttag From DerInhalt where month(MHD) = :monat and year = :jahr "); ADOQuery1->Parameters->ParamByName("monat")->Value = Month; ADOQuery1->Parameters->ParamByName("jahr")->Value = YearOf(MonthCalendar1->Date); ADOQuery1->Open();
Das geht allerdings nur gut wenn du nur einen Monat im MonthCalendar anzeigen läßt.
Wenn du mehrere Monate gleichzeitig anzeigen willst wirds etwas komplizierter. Aber auch dafür gibts eine Lösung in den Weiten des Internets
-
Linnea schrieb:
einfacher ists die SQL-Anweisung um die Suche nach dem Jahr zu erweitern:
ADOQuery1->SQL->Clear(); ADOQuery1->SQL->Add("Select distinct day(MHD) as ttag From DerInhalt where month(MHD) = :monat and year = :jahr "); ADOQuery1->Parameters->ParamByName("monat")->Value = Month; ADOQuery1->Parameters->ParamByName("jahr")->Value = YearOf(MonthCalendar1->Date); ADOQuery1->Open();
hmm klar, einfacher gehts immmer.... wenn man weiss wie:)
aber muss das nicht so heissen:Linnea schrieb:
ADOQuery1->SQL->Add("Select distinct day(MHD) as ttag From DerInhalt where month(MHD) = :monat and year(MHD) = :jahr ");
[/cpp]Linnea schrieb:
Das geht allerdings nur gut wenn du nur einen Monat im MonthCalendar anzeigen läßt.
Wenn du mehrere Monate gleichzeitig anzeigen willst wirds etwas komplizierter. Aber auch dafür gibts eine Lösung in den Weiten des Internets
was meinst du damit?
ich möchte, wenn ich den kalender durchklicke von monat zu monat die jeweiligen tage sehen...
-
Otz110 schrieb:
aber muss das nicht so heissen:
Linnea schrieb:
ADOQuery1->SQL->Add("Select distinct day(MHD) as ttag From DerInhalt where month(MHD) = :monat and year(MHD) = :jahr ");
[/cpp]richtig
Otz110 schrieb:
ich möchte, wenn ich den kalender durchklicke von monat zu monat die jeweiligen tage sehen...
Wenn du den MonthCalendar auf das Formular legst, kannst du das mal größer ziehen, dann werden je nach Größe des Feldes mehrere Kalenderblätter angezeigt. Das Maximum liegt bei 4x3 Kalenderblätter, also ein Jahr.
Wenn du aber nur einen Monat anzeigen willst ist der Quellcode, so wie vorher besprochen, durchaus ausreichend
-
hmm also ich hab jetzt diesen quellcode:
void __fastcall TForm1::MonthCalendar1GetMonthInfo(TObject *Sender, DWORD Month, DWORD &MonthBoldInfo) { Form3->ADOQuery1->SQL->Clear(); Form3->ADOQuery1->SQL->Add("Select distinct day(MHD) as ttag From DerInhalt where month(MHD) = :monat and year(MHD) = :jahr "); Form3->ADOQuery1->Parameters->ParamByName("monat")->Value = Month; Form3->ADOQuery1->Parameters->ParamByName("jahr")->Value = YearOf(MonthCalendar1->Date); Form3->ADOQuery1->Open(); int count = Form3->ADOQuery1->RecordCount; if (count <= 0) return; unsigned feld[31]; unsigned Buffer = MonthBoldInfo; for (Form3->ADOQuery1->First();!Form3->ADOQuery1->Eof;Form3->ADOQuery1->Next()) { feld[Form3->ADOQuery1->RecNo] = Form3->ADOQuery1->FieldByName("ttag")->AsInteger; } MonthCalendar1->BoldDays(feld,count-1,Buffer); Form3->ADOQuery1->Close(); MonthBoldInfo = Buffer;
aber irgendwas klappt da noch nicht.
ich hab in meiner access tabelle das datum 09.01.1987 drin! wenn ich den monat aufrufe ist zuerst der 14.01. markiert. wenn ich jetzt einen monat weiter mache und wieder zurück ist aufeinmal der 11.01. markier. was kann das sein?
-
Zeile 14 ist noch falsch:
feld[Form3->ADOQuery1->RecNo[u]-1[/u]] = Form3->ADOQuery1->FieldByName("ttag")->AsInteger;
hat aber trotzdem noch nen Haken: wenn man auf Dez 1986 geht und danach auf Jan 1987 ist der Wert auch nicht da...
Das liegt daran, daß auch der Vormonat und der Monat nach dem angezeigten mit ausgewertet werden und dann interessanterweise nicht das blaumarkierte Datum genommen wird, sondern das was im Vormonat markiert ist.Die einzig wirklich gute Lösung für das Problem ist eine Komponente von TMonthCalendar abzuleiten und beim OnGetMonthInfo auch das angezeigte Jahr mit auszugeben, siehe hier. Ich schau mal ob ich die Komplettlösung hinbekomm.
-
hier mal die Lösung mit Beispielaufruf:
man macht einen neue Unit und speichert die unter MonthCalFix, der Header (.h) hat folgenden Inhalt:
#ifndef MonthCalFixH #define MonthCalFixH #include <Controls.hpp> #include <ComCtrls.hpp> //--------------------------------------------------------------------------- typedef void __fastcall (__closure *TOnGetYearMonthInfoEvent)(TObject *Sender, Word Year, Word Month, MONTHDAYSTATE &MonthBoldInfo); class TMonthCalendarFix : public TMonthCalendar { typedef TMonthCalendar inherited; private: TOnGetYearMonthInfoEvent FOnGetMonthInfo; MESSAGE void __fastcall CNNotify(TWMNotify &Message); protected: // Protected declarations public: // Public declarations __fastcall TMonthCalendarFix(TComponent *Owner); BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(CN_NOTIFY, TWMNotify, CNNotify) END_MESSAGE_MAP(TMonthCalendar) __published: __property TOnGetYearMonthInfoEvent OnGetMonthInfo = {read=FOnGetMonthInfo, write=FOnGetMonthInfo}; }; #endif
in der .cpp steht:
//--------------------------------------------------------------------------- #pragma hdrstop #include "MonthCalFix.h" //--------------------------------------------------------------------------- #pragma package(smart_init) //--------------------------------------------------------------------------- __fastcall TMonthCalendarFix::TMonthCalendarFix(TComponent *Owner) : TMonthCalendar(Owner) { } //--------------------------------------------------------------------------- void __fastcall TMonthCalendarFix::CNNotify(TWMNotify &Message) { switch( Message.NMHdr->code ) { case MCN_GETDAYSTATE: { LPNMDAYSTATE lpnmDayState = (LPNMDAYSTATE) Message.NMHdr; memset(lpnmDayState->prgDayState, 0, lpnmDayState->cDayState * sizeof(MONTHDAYSTATE)); if( FOnGetMonthInfo ) { LPMONTHDAYSTATE CurState = lpnmDayState->prgDayState; Word YearNo = lpnmDayState->stStart.wYear; //the year is passed anyways, so why not use it? for(Word I = 0; I < lpnmDayState->cDayState; ++I) { Word MonthNo = lpnmDayState->stStart.wMonth + I; if( MonthNo > 12 ) { MonthNo -= 12; ++YearNo; } FOnGetMonthInfo(this, YearNo, MonthNo, *CurState); ++CurState; } } Message.NMHdr->code = 0; //don't handle this message again in inherited handler break; } /* the MCN_SELCHANGE message is also fired for year and month changes, actually it is also fired just before MCN_SELECT */ case MCN_SELCHANGE: Message.NMHdr->code = MCN_SELECT; //make inherited handler assume it's MCN_SELECT break; } inherited::Dispatch(&Message); }
diese Unit bindet man dann dort ein wo man den Kalender haben möchte, in diesem Beispiel in Unit1/Form1 (die Kommentare bezeichnen die Funktionen/Zeilen, die in eine eigene Anwendung übernommen werden müssen):
#include "MonthCalFix.h" //eingebundener Hearder des MonthCalendarFix //--------------------------------------------------------------------------- class TForm1 : public TForm { __published: TADOConnection *ADOConnection1; TADOQuery *ADOQuery1; TButton *Button1; void __fastcall Button1Click(TObject *Sender); private: void __fastcall MonthCalendarFixGetMonthInfo(TObject *Sender, Word Year, Word Month, MONTHDAYSTATE &MonthBoldInfo); //OnGetMonthInfo TMonthCalendarFix *MonthCalendarFix; //MonthCalendarZeiger public: __fastcall TForm1(TComponent* Owner); __fastcall ~TForm1(void); //Destructor des Formulars };
in der cpp:
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { //der Konstructor von Form1 ist im Normalfall schon vorhanden //folgendes zeigt den MonthCalendarFix an MonthCalendarFix = new TMonthCalendarFix(Form1); MonthCalendarFix->Parent = Form1; MonthCalendarFix->Top = 200; MonthCalendarFix->Left = 200; MonthCalendarFix->Visible = true; MonthCalendarFix->OnGetMonthInfo = MonthCalendarFixGetMonthInfo; } //--------------------------------------------------------------------------- // der Destructor von Form1 __fastcall TForm1::~TForm1(void) { delete MonthCalendarFix; } //--------------------------------------------------------------------------- // die neue OnGetMonthInfo-Methode void __fastcall TForm1::MonthCalendarFixGetMonthInfo(TObject *Sender, Word Year, Word Month, MONTHDAYSTATE &MonthBoldInfo) { ADOQuery1->SQL->Clear(); ADOQuery1->SQL->Add("Select distinct day(MHD) as ttag From DerInhalt where month(MHD) = :monat and year(MHD) = :jahr "); ADOQuery1->Parameters->ParamByName("monat")->Value = Month; ADOQuery1->Parameters->ParamByName("jahr")->Value = Year; ADOQuery1->Open(); int count = ADOQuery1->RecordCount; if (count <= 0) return; unsigned feld[31] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; unsigned Buffer = MonthBoldInfo; for (ADOQuery1->First();!ADOQuery1->Eof;ADOQuery1->Next()) { feld[ADOQuery1->RecNo-1] = ADOQuery1->FieldByName("ttag")->AsInteger; } MonthCalendarFix->BoldDays(feld,count-1,Buffer); ADOQuery1->Close(); MonthBoldInfo = Buffer; }
-
ohje das ist aber gewachsen....
erstmal danke für die mühe:)
muss mich da jetzt mal durch kämpfen und schauen ob ich das zum laufen bekomme