|
It's possible but then there would be a dependancy on MFC. My intention was to not make it dependant on MFC so that all Win32 c++ apps could use the class.
But this is source code. People can do their own thing to it if they want.
1: Derive it from CObject.
2: Add the macros IMPLEMENT_SERIAL and DECLARE_SERIAL
3: Override virtual function Serialize.
After restoring from an archive you'll need to put the clock into the proper state after reading and interpreting the vars. That's about all there is to it.
-- modified at 21:24 Friday 24th March, 2006
Forgot to say: If you want to make it serializable I'll be glad to help if you need it.
|
|
|
|
|
I am thinking of changing the way the alarm is scheduled (or maybe I can add more member funtions).
Right now, in order to use the repeat alarms, the programmer needs to set one alarm then add a repeat type. This was the way I implemented the class but I hadn't really thought it out too well at the time I wrote it. Using it this way is not that easy and it was supposed to be easy.
The problem with the way this thing is used right now is that an alarm has to be scheduled in order to use the repeat alarms. The burden is currently on the programmer/user because they have to call SetAlarm with a valid alarm time that hasn't expired yet. But it's not simple to make use of the class if this is necessary. It's a REAL PAIN.
So it needs to be changed.
In order to make the class easier to use, I need to add more functions, to allow the user to schedule a repeat alarm and activate the first of the repeat alarms automatically....by calling a single function.
I'm going to add a new set of function calls that have a name like ScheduleRepeatAlarm(with some parameters from SetAlarm and some from SetRepeat). By doing this, I can make it so that a single function call schedules and arms the clock.
- My idea for how to fix it is to add more functions to replace the existing ones. SetAlarm and SetRepeatxxx can be avoided and ScheduleRepeatAlarm() can be used instead.
An example with paremeters could be like this:
BOOL ScheduleRepeatAlarm_Interval(long nCount, HWND hWndAlert, SYSTEMTIME tmExpires, int dd, int hh, int mm, int ss, int ms);
BOOL ScheduleRepeatAlarm_Monthly(long nCount, HWND hWndAlert, SYSTEMTIME tmExpires, int DayOfMonth);
BOOL ScheduleRepeatAlarm_Weekly(long nCount, HWND hWndAlert, SYSTEMTIME tmExpires, BOOL *bWeekdays[7]);
Suggestions are welcome.
Dave
|
|
|
|
|
I was thinking, pondering - why dont you take a repeat 'specification' as text, for example, borrowing grammar from rfc2445 recurrence clauses .. then you dont need so many buttons etc
its probably harder in that you have to parse the grammar and map it back to your own methods, but its flexible (you could start with a subset even)
just an idea .. no criticism
'g'
added .. in fact, you could specify the whole alarm as text, then you wouldnt necessarily need a ui - you could then store alarms in a file
-- modified at 2:03 Friday 24th March, 2006
|
|
|
|
|
There are advantages to parsing text but I don't want to do that much work. I appreciate the input. It doesn't feel like a criticism but I can say that I'm ready for more criticism after the way I presented this thing.
It turns out that after publishing this class here, I'm finally getting around to trying to use it myself (as I originally intended) and it's too hard to use and make the human have to tell it the initial date/time. I should've waited until I was completely happy with it before publishing it.
Now that it's in the public domain, I'd like to fix the poor interface one more time and simply create sensible public member functions that do a lot without the programmer/user having to do much work. It shouldn't have to be necessary to call two functions in order to shedule and activate a repeated alarm....as it is right now.
|
|
|
|
|
I always find it interesting, that despite the language capabilities offered in C++, member functions continue to reflect C++'s heritage in C. Why not use overloading through the use of a single function name (ScheduleRepeatAlarm) and allow signature uniqueness via the argument list?
BOOL ScheduleRepeatAlarm(long nCount, HWND hWndAlert, SYSTEMTIME tmExpires, int dd, int hh, int mm, int ss, int ms);
BOOL ScheduleRepeatAlarm(long nCount, HWND hWndAlert, SYSTEMTIME tmExpires, int DayOfMonth);
BOOL ScheduleRepeatAlarm(long nCount, HWND hWndAlert, SYSTEMTIME tmExpires, BOOL *bWeekdays[7]);
Just a suggestion! This is by no means limited to your class, which I find interesting and worth further evaluation.
|
|
|
|
|
I absolutely agree. It can be just one function name with different parms.
But...what are the vital parms and which ones are not needed? That is the question I am ponding now...after the fact...
Each of these functions needs (IMHO)
- The time of day for the recurring event to happen at (only if it's daily, weeky or monthly).
- The count of recurring events (or an expiration date).
- The recurring info (interval period, weekdays, day of month)
- The means of signalling the caller (HWND, Event or Callback)
Daily time is only needed for daily, weekly, monthly.
Count can be zero (for forever).
Expiration date can be zero (to ignore exp-date and use count value instead).
This is what I'm pondering right now about what parameters are needed in a single (do everything) repeat-alarm-scheduling function.
|
|
|
|
|
Here's my proposal for a simpler way to use repeat alarms. I created another set of member functions to schedule and start the repeated alarm in a single call. I tried to think of everything that would be practical but I could've overlooked something.
(Sorry for the poor formatting. The CP web server won't keep the spacing the way I wanted it to look. It seems to remove most blanks that I added.)
The interval scheduling function currently looks like this:
BOOL SetRepeatAlarm(LPALARMCB lpCB, DWORD dwUser,
int iDD, int iHH, int iMM, int iSS, int iMS, // Alarm triggers every ...
BOOL bSyncDD, // 1st alarm starts at top of next hour (XX:00:00)
BOOL bSyncHH, // 1st alarm starts at top of next day (00:00:00)
long nCount = 0, // Alarm expires after nn counts or forever if zero.
LPSYSTEMTIME lpExpDate = NULL); // Alarm expires after this date & time has passed.
// (overrides nCount). Ignored if NULL or values in struct=0.
The monthly repeat scheduling function looks like:
BOOL SetRepeatAlarm(LPALARMCB lpCB, DWORD dwUser,
LPSYSTEMTIME lpTimeOfDay, // Time of alarm (only wHour, wMinute and wSecond are used)
int nDayOfMonth, // 1 to 31
long nCount = 0, LPSYSTEMTIME lpExpDate = NULL);
The weekly or daily:
BOOL SetRepeatAlarm(LPALARMCB lpCB, DWORD dwUser,
LPSYSTEMTIME lpTimeOfDay, // Time of alarm (only wHour, wMinute and wSecond are used)
BOOL *bWeekdays[7], // {F, T, T, T, F, F, F} = Day of Week starting at Sunday.
// Example shows Mon, Tues and Wed are set. F=FALSE, T=TRUE
long nCount = 0, LPSYSTEMTIME lpExpDate = NULL);
-------------
Recurring intervals not based on daily or weekly or monthly:
Regarding the first of the three example functions (used for non-daily recurring events) -
I can't imagine every possible way of using a recurring alarm, but I can think of how *I* would want to use it. I want to use it like a VCR clock calendar to control a recorder. There's probably ways of making the capability much more versatile (and complex) but it escapes my why someone would want to synchronize an hourly event to 20 minutes after every hour. So I left that capability out. But you can schedule a recurring alarm that starts at the top of the next hour or midnight of the next day. If you really need to set a recurring alarm that is hourly but occurs on the 1/2 hour of every hour, then you can still use the SetAlarm and SetRepeat functions to accomplish that. But for simplicity, I decided to make the single function calls less versatile but easier to use. So I added two flags: (bSyncHH and bSyncDD) to allow the user to sync an interval alarm to the hour or the day, (respectively).
The other recurring types (monthly, weekly) don't need sync because they have a way to specify the daily time: (lpTimeOfDay). For a daily, weekly or monthly alarm, use lpTimeOfDay to specify the alarm time for each day. Only the SYSTEMTIME::wHour, wMinute and wSecond values are used. The rest are ignored.
If someone wants to set a recurring alarm on the 1/2 hour point of every hour, this is how I recommend doing that:
// Declared in a place that won't lose scope -
CAlarmClock m_Clock;
// In your code to set the example recurring event to the bottom of every hour using the existing function set: (untested example code)
SYSTEMTIME tTime;
GetLocalTime(&tTime); // Get current time so we have a starting point
if (tTime.wMinute > 30)
{
tTime.wHour++;
// ... Need to handle all overflows... good luck
}
tTime.wMinute = 30;
m_Clock.SetRepeat_Interval(0, 0, 1, 0, 0, 0);
m_Clock.SetAlarm(tTime, hWnd, 0);
// From this point, you'll start getting the windows message every hour on the 1/2 mark.
Footnote: Maybe there's something important that I overlooked. If you have a concern about how I propose to define this, pls reply so I can avoid adding something that's based on flawed logic. It won't hurt my feelings. That's why I'm here asking so I can get it right,
I'll wait a few days before writing the code in case someone wants to reply to this thread.
-- modified at 16:35 Saturday 25th March, 2006
|
|
|
|
|
I'm going to add the following two functions only, in order to add a simpler way to use repeat alarms. The interval (DD, HH, MM, SS, MS) version of the function will not be needed AFAIK:
BOOL SetRepeatAlarm(LPALARMCB lpCB, DWORD dwUser,
LPSYSTEMTIME lpTimeOfDay,
int nDayOfMonth,
long nCount = 0, LPSYSTEMTIME lpExpDate = NULL);
BOOL SetRepeatAlarm(LPALARMCB lpCB, DWORD dwUser,
LPSYSTEMTIME lpTimeOfDay,
BOOL *bWeekdays[7],
long nCount = 0, LPSYSTEMTIME lpExpDate = NULL);
After consideration, I can't think that the 1st of the proposed functions from the previous post would be very useful. So it's only going to be the 2 functions I listed here that will be added to support easier repeat schedules. If someone needs a simple daily repeat alarm, they can use the weekly (above) with all days set to TRUE. If they want to make an hourly repeat alarm, it's not that big a deal to use two function calls (SetAlarm followed by SetRepeat_Interval ).
This will be the final update for this class except that there will probably still be some bug fixes if necessary, afterwards. And one last thing: I think it's best to rename the SetRepeat_Interval , SetRepeat_Monthly , etc. to just SetRepeat in order to make use of c++ overloading. That will break anyone's code if they're already using this class. Just need to rename their "SetRepeat_Monthly " to SetRepeat and their code should compile aggain. Hope no one minds this approach to clean up the names. It's better to rename them and keep everything consistent.
|
|
|
|
|
Just found a new bug - When repeating an alarm using the repeat by interval type, repeat nn days is being ignored.
The good news is that it's been fixed. But until the upload is processed, please change AlarmClock.cpp. Change the CalculateNewAlarmInterval member function to look like this:
-----------------------------
void CAlarmClock::CalculateNewAlarmInterval(CAlarmClock* pThis)
{
UFT u1, u2;
_ASSERT(pThis);
u1.ll = pThis->m_RepeatParms.dd * ONE_DAY;
u1.ll += pThis->m_RepeatParms.hh * ONE_HOUR;
u1.ll += pThis->m_RepeatParms.mm * ONE_MINUTE;
u1.ll += pThis->m_RepeatParms.ss * ONE_SECOND;
u1.ll += pThis->m_RepeatParms.ms * ONE_MILLISECOND;
u2.ft = pThis->m_AlarmTime; // Get old alarm
u2.ll += u1.ll; // Add offset to make new alarm.
pThis->m_AlarmTime = u2.ft;
}
-----------------------------
Sorry for letting this bug slip by me earlier.
|
|
|
|
|
Thansk for sharing with us the source code of your apllication.
Do you think you could minimize the application to the systray?
E.g. for improvement please see Chris Maunder's Tray Calendar[^]
|
|
|
|
|
Mihai Moga wrote: Do you think you could minimize the application to the systray?
There's a lot of things that could be done to the app. It's yours to hack at if you want. I just included the app to show how to use the CAlarmClock class. This app was written in a hurry to test the class and shouldn't be considered a proper example of how to write an app (as I've said before). The scope of this article is the CAlarmClock class and the app is here to provide an example use only.
|
|
|
|
|
Hi,
In many cases, we find that when there are alarms, we deal with multiple objects. For example: we set reminders to multiple tasks, reminders to multiple notes, reminders to multiple calendar items etc etc.
In your class, you create a single thread for every alarm set. So, this means that if I have 25 tasks with reminders. your class will create a thread for each reminder.
Am I right? If so, then this is a very poor design.
Am I missing something?
Regards,
Gautam Jain
|
|
|
|
|
I apologize for my immature statements.
It looks like you have a better approach to deal with alarms. It was just that your better class couldn't be implemented directly in to my existing app. Thats what made me think the other way. Probably I should change my existing design.
Sorry again.
Thanks.
Regards,
Gautam Jain
|
|
|
|
|
Nice
Anas M. AL-Hashki
Software Developer
|
|
|
|
|
Hey,
Thanks for taking the time to write this for all of us to use and learn from. I have adopted your class to another application of mine and for the most part it works like a champ.
The one bug I have noticed is lets say I want to create a weekday repeating alarm (ex: Wednesday), repeating forever, at 5:00pm. If I try to set this alarm on Tuesday at 4:00pm, the next alarm is set to Tuesday at 5:00pm instead of Wednesday. This bug only occurs if the time you select is later than the current time of the day. This bug has held true for both weekday repeat and Nth day repeats.
Is this something you were aware of and is just unavoidable? Or is this a bug you can perhaps offer a quick fix for?
Id appreciate any insight on it.
Note: I have read the other posts and have made the updates to any other bugs you have corrected.
-Mike
|
|
|
|
|
Hi Mike,
I was not able to recreate this problem using 9:00 pm set on tuesday with inf repeat of wednesday. But I suspect this bug might've been fixed. I'd like to see how it works if you apply the fix below:
-----------------
Inside the member function...
CAlarmClock::CalculateNewAlarmDOW(CAlarmClock* pThis)
Replace the following statement:
if (i > 7) i = 0; // Wrap around the weekend
to this:
i %= 7; // Wrap around the weekend
See if that makes it work and let me know if it's still broken.
----
BTW: I'm adding new functionality to the class and will try to get it uploaded soon. I'm modifying the GUI to make use of the new stuff rt now. And have fixed some of the thread problems that other people WILL see if I don't get it uploaded soon... So, people will not have to fix this annoying problem much longer....in case this is the reason.
Hope the above code change fixes it.
Regards,
Dave
-- modified at 23:53 Tuesday 7th March, 2006
|
|
|
|
|
Hey Dave,
Sweet to hear you're coming out with an updated version of this class, I will definitely update my application with the changes.
I had already made that modification to my program before writing the original post. Just to be clear, the bug ONLY surfaces if I try to set the time for the alarm to a later date than the CURRENT time on my computer. If I set a time that has already passed on that day, the alarm is set exactly as expected. The time being set is essential to recreating the problem. I tried to look through the class myself to see if I could spot the problem, but I had no luck. This problem isnt a deal breaker for me as it is very easy for me to consciously work-around.
Recreating the bug: Open the demo app included here. Use Repeat by Weekday, Repeat Forever, and assuming the time is Wednesday at 5pm when you do it, try doing weekday Thursday and time 7:00pm. (One day later, any hour later than the current hour on your computer). You should see the date the next alarm is set to is the same day you're setting it, instead of the day you select for it to actually repeat on.
Perhaps your updated class will fix this issue without any additional work. I look forward to seeing that soon. If after reading this you can replicate this bug (the bug exists with your demo application too) and fix it, i'll be sure to read this thread to make sure I see that update.
(Sorry this was a long reply ).
I appreciate you following up.
-Mike
|
|
|
|
|
Hi Mike,
No need to appologize for the long post. It's best to get as much detail as possible when bugs are involved.
I want to make sure I understand what the problem is. I tried following your directions and didn't see a failure...but I think we both might have a different idea of how it's suppose to behave...or I didn't understand exactly how to recreate the bug:
Here's what I tried:
1. If the current date, time, weekday is 3/8/2006, 5:00 PM, Wed...then I tried this:
2. I set up a repeat-forever using weekdays for every Thursday.
3. Now I set the alarm date and time to Today @ 6:00 p.m. I expect the first alarm to occur Today @ 6:00 p.m.
4. The next alarm (the 1st of the repeats) should occur @ Thursday @ 6:00 p.m.
--------------
Is that what you expected to happen too? When I read your decription, it sounded like you set an alarm for later in the same day and the repeat for the next day (repeating forever). Then the alarm happened today instead of tomorrow? If that's the case, then that was the correct behavior. So if the initial alarm is on Wed at 6:00 p.m. and the repeat is for Thu then the 1st alarm will be the Wed @ 6 (same date/time as you set on the little calendar and clock in the upper left of the demo app).
Sorry if I misunderstood. Let me know if this was the proper way to recreate it.
Dave
|
|
|
|
|
BTW: It's ok to use email at this point if you want. Maybe we should take this offline until it's resolved.
|
|
|
|
|
Hey Dave,
Perhaps you're right that this is not a bug but simply a different expectation of behavior. When I setup an alarm on Wednesday telling it to repeat on Thursday, I expected every alarm (Including the first one) to occur ONLY on Thursdays. Your recreation of the bug looks accurate, so I can only assume the first alarm occuring on Wednesday and then further repeats occurring on Thursdays is actually normal behavior and not a bug afterall.
Assuming that is the case, I can easily modify my code to adjust this behavior to suit my needs.
I will watch the behavior of the program over time to see how it works out in reality. I will keep you posted if I find anything bizarre after the first alarm is fired.
Again, I appreciate your follow-ups and look forward to seeing your updates to this class in the future.
-Mike
|
|
|
|
|
Well Mike, I think you've pointed out something important. Perhaps I should add another function to make it easier to use repeat alarms. I have to think about how it would make the best sense. Any inputs are welcome.
Thanks for all your inputs. It's got me thinking on how to make it work better.
P.S. I'm testing the new version now and then I have to write in something to explain the new features then I'll post the new code to here. If you want it before it's posted here, I can email it to you.
Regards,
Dave
|
|
|
|
|
Hi,
Notice that SetTimer is used in the program (alarmclockdlg.cpp).
Do you need to include KillTimer once the dialog is destroy?
I am trying to integrate the source code for some time trigger video recording.
Best regards,
Edmund
|
|
|
|
|
Hi,
No KillTimer huh? Oops...I have no excuse, I forgot it. Thanks for letting me know. I wouldn't say that the dialog code was very well thought out as it was just a quick toss-together to get this thing posted so I could have an example. But don't consider the example to be the right way to write an app...in this case.
You might want to add KillTimer to your own version (in OnDestroy I guess) until I get the code updated. I'm in the middle of making changes to the class so there'll be another update in a while with this fix added too.
Thanks!
Dave
-- modified at 22:59 Sunday 5th March, 2006
|
|
|
|
|
Hi,
Actually, your code is very helpful. Thank you.
Just have another question.
Anyway to change the code for working from 9.00am to 5.00pm.
Best regards,
Edmund
|
|
|
|
|
When i set m_RepeatParms.Type = Repeat_Weekdays and m_RepeatParms.bRepeatForever = TRUE. I want to alarm from mon to fri. But if today is friday. After AlarmTriggered, i found the next alarm time is tuesday of next week.
|
|
|
|
|