Page 1 of 1

Reusable CalendarGadget

Posted: Sat Feb 04, 2012 3:45 am
by yrreti
When using the CalendarGadget, it has a bad flaw in that you can't select the same date twice in a row.
For instance, if you need to use it to assign a date to a job, and then assign a completed date, that is
finished on the same day. You can't, unless you first select another date first, and then that date.
The following code shows this problem. Click on Assigned and select any date. then click on Accept Date
and then click on Completed, and try clicking on the 'same' date on the CalendarGadget. It won't work!

Code: Select all

Enumeration
  #Main_Window
EndEnumeration

Enumeration
  #AssignedDateString
  #CompletedDateString
  #AssignedButton
  #CompletedButton
  #AcceptButton
  #CloseButton
  #WorkCalendar
  #DateResultsString
  #InfoText
EndEnumeration

Procedure OpenWindow_Main_Window()
  If OpenWindow(#Main_Window, 1212, 96, 837, 322, Space(30)+"Attached Calendar Window Test",#PB_Window_SystemMenu|#PB_Window_TitleBar|#PB_Window_ScreenCentered)
    CalendarGadget(#WorkCalendar , 640,20, 180, 155)
    StringGadget(#AssignedDateString, 670, 190, 60, 20, "",#PB_String_ReadOnly)
    StringGadget(#CompletedDateString, 750, 190, 60, 20, "",#PB_String_ReadOnly)
    ButtonGadget(#AssignedButton, 668, 215, 65, 20, "Assigned")
    ButtonGadget(#CompletedButton, 749, 215, 65, 20, "Completed")
    ButtonGadget(#AcceptButton, 705, 241, 65, 30, "Accept Date", #PB_Button_MultiLine)
    StringGadget(#DateResultsString, 670, 280, 145, 20, "Date Result:",#PB_String_ReadOnly)
    ButtonGadget(#CloseButton, 368, 215, 65, 20, "Close")
    TextGadget(#InfoText, 510, 217, 120, 100, "Click on either Button -->  and then select date. Then Click on the Accept Button to Accept that dates input.")
  EndIf
EndProcedure

OpenWindow_Main_Window()

ac=0 ;default

Repeat
  Select WaitWindowEvent()
  Case #PB_Event_Gadget
    Select EventGadget()
    Case #WorkCalendar
      seldate=GetGadgetState(#WorkCalendar)
      seldate$ = FormatDate("%mm/%dd/%yy", seldate)
      If ac=1
        SetGadgetText(#AssignedDateString,seldate$)
      ElseIf ac=2
        SetGadgetText(#CompletedDateString,seldate$)
      EndIf
    Case #AssignedButton
      ac=1
      DisableGadget(#AssignedButton, 1)
      DisableGadget(#CompletedButton, 0)
      SetGadgetText(#AssignedDateString,"")
      SetGadgetColor(#AssignedDateString,#PB_Gadget_BackColor,$90FF90)
    Case #CompletedButton
      ac=2
      DisableGadget(#CompletedButton, 1)
      DisableGadget(#AssignedButton, 0)
      SetGadgetText(#CompletedDateString,"")
      SetGadgetColor(#CompletedDateString,#PB_Gadget_BackColor,$90FF90)
    Case #AcceptButton
      If ac=1
        SetGadgetText(#DateResultsString,"Assigned Date = "+seldate$)
      ElseIf ac=2
        SetGadgetText(#DateResultsString,"Completed Date = "+seldate$)
      EndIf
      ac=0
      DisableGadget(#AssignedButton, 0)
      DisableGadget(#CompletedButton, 0)
      SetGadgetColor(#AssignedDateString,#PB_Gadget_BackColor,-1)
      SetGadgetColor(#CompletedDateString,#PB_Gadget_BackColor,-1)
      
    Case #CloseButton
      End
    EndSelect
    
  Case #PB_Event_CloseWindow
    Select EventWindow()
    Case #Main_Window
      CloseWindow(#Main_Window)
      Break
    EndSelect
  EndSelect
ForEver

I coded two different ways to get around this, by basically creating a calendar window, which I close and
re-open when ever I accept the date. This way the CalendarGadget gets reset each time, and I can select
the same date. I tried a method using StickyWindow(), and using a window coordinate approach to keep
the calendar window in it's place that worked well, except that the calendar window would always be on
top of any window placed over it. It didn't look good. The following method uses an unusual approach
using WindowChild and SetParent_ and ResizeWindow to do this with out the StickyWindow() problem.
The only complaint that I wish could be solved is that the main windows title bar flickers a little when ever
you use this method. I also could have just used the Accept and Completed buttons to do the job with out
the Accept button, but prefered using a visual Accept button in order to verify the date first before accepting
it. Explanation is in the code.

If you know a way to improve it -- Please -- add and post it here. That's how we learn.

Code: Select all

Enumeration
  #Main_Window
  #CalendarWin
EndEnumeration

Enumeration
  #AssignedDateString
  #CompletedDateString
  #AssignedButton
  #CompletedButton
  #AcceptButton
  #CloseButton
  #WorkCalendar
  #DateResultsString
  #InfoText
EndEnumeration

Global WindowChild

Procedure OpenWindow_CalendarWin(calx,caly)
  If OpenWindow(#CalendarWin, calx, caly, 180, 160, "", #PB_Window_BorderLess)
    CalendarGadget(#WorkCalendar , 0, 5, 180, 155)
  EndIf
EndProcedure

Procedure OpenWindow_Main_Window()
  If OpenWindow(#Main_Window, 1212, 96, 837, 322, Space(30)+"Attached Calendar Window Test",#PB_Window_SystemMenu|#PB_Window_TitleBar|#PB_Window_ScreenCentered)
    StringGadget(#AssignedDateString, 670, 190, 60, 20, "",#PB_String_ReadOnly)
    StringGadget(#CompletedDateString, 750, 190, 60, 20, "",#PB_String_ReadOnly)
    ButtonGadget(#AssignedButton, 668, 215, 65, 20, "Assigned")
    ButtonGadget(#CompletedButton, 749, 215, 65, 20, "Completed")
    ButtonGadget(#AcceptButton, 705, 241, 65, 30, "Accept Date", #PB_Button_MultiLine)
    StringGadget(#DateResultsString, 670, 280, 145, 20, "Date Result:",#PB_String_ReadOnly)
    ButtonGadget(#CloseButton, 368, 215, 65, 20, "Close")
    TextGadget(#InfoText, 510, 217, 120, 100, "Click on either Button -->  and then select date. Then Click on the Accept Button to Accept that dates input.")
   
  EndIf
EndProcedure

OpenWindow_Main_Window()

OpenWindow_CalendarWin(-180,20);create off screen
WindowChild = WindowID(#CalendarWin)
SetParent_(WindowID(#CalendarWin), WindowID(#Main_Window));put on Main Window
ResizeWindow(#CalendarWin, 640, 20, #PB_Ignore , #PB_Ignore );resize to the place you want it.

ac=0 ;default

Repeat
  Select WaitWindowEvent()
  Case #PB_Event_Gadget
    Select EventGadget()
    Case #WorkCalendar
      seldate=GetGadgetState(#WorkCalendar)
      seldate$ = FormatDate("%mm/%dd/%yy", seldate)
      If ac=1
        SetGadgetText(#AssignedDateString,seldate$)
      ElseIf ac=2
        SetGadgetText(#CompletedDateString,seldate$)
      EndIf
    Case #AssignedButton
      ac=1
      DisableGadget(#AssignedButton, 1)
      DisableGadget(#CompletedButton, 0)
      SetGadgetText(#AssignedDateString,"")
      SetGadgetColor(#AssignedDateString,#PB_Gadget_BackColor,$90FF90)
    Case #CompletedButton
      ac=2
      DisableGadget(#CompletedButton, 1)
      DisableGadget(#AssignedButton, 0)
      SetGadgetText(#CompletedDateString,"")
      SetGadgetColor(#CompletedDateString,#PB_Gadget_BackColor,$90FF90)
    Case #AcceptButton
      If ac=1
        SetGadgetText(#DateResultsString,"Assigned Date = "+seldate$)
      ElseIf ac=2
        SetGadgetText(#DateResultsString,"Completed Date = "+seldate$)
      EndIf
      ac=0
      DisableGadget(#AssignedButton, 0)
      DisableGadget(#CompletedButton, 0)
      SetGadgetColor(#AssignedDateString,#PB_Gadget_BackColor,-1)
      SetGadgetColor(#CompletedDateString,#PB_Gadget_BackColor,-1)
      If IsWindow(#CalendarWin)
        CloseWindow(#CalendarWin);Reset the CalendarGadget by closing and re-openning the window.
      EndIf
      OpenWindow_CalendarWin(-180,20);create off screen
      SetParent_(WindowID(#CalendarWin), WindowID(#Main_Window));put on Main Window
      ResizeWindow(#CalendarWin, 640, 20, #PB_Ignore , #PB_Ignore );resize to the place you want it.
      
    Case #CloseButton
      End
    EndSelect
    
  Case #PB_Event_CloseWindow
    Select EventWindow()
    Case #Main_Window
      CloseWindow(#Main_Window)
      Break
    EndSelect
  EndSelect
ForEver

Re: Reusable CalendarGadget

Posted: Sat Feb 04, 2012 4:08 pm
by Demivec
I didn't see any significant difference between the two versions you posted.

I think a simple solution is just to select the date first then push the appropriate button, Assign or Completed, for it to register.

Like so:

Code: Select all

Enumeration
  #Main_Window
EndEnumeration

Enumeration
  #AssignedDateString
  #CompletedDateString
  #AssignedButton
  #CompletedButton
  #AcceptButton
  #CloseButton
  #WorkCalendar
  #DateResultsString
  #InfoText
EndEnumeration

Procedure OpenWindow_Main_Window()
  If OpenWindow(#Main_Window, 1212, 96, 837, 322, Space(30)+"Attached Calendar Window Test",#PB_Window_SystemMenu|#PB_Window_TitleBar|#PB_Window_ScreenCentered)
    CalendarGadget(#WorkCalendar , 640,20, 180, 155)
    StringGadget(#AssignedDateString, 670, 190, 60, 20, "",#PB_String_ReadOnly)
    StringGadget(#CompletedDateString, 750, 190, 60, 20, "",#PB_String_ReadOnly)
    ButtonGadget(#AssignedButton, 668, 215, 65, 20, "Assigned")
    ButtonGadget(#CompletedButton, 749, 215, 65, 20, "Completed")
    ButtonGadget(#AcceptButton, 705, 241, 65, 30, "Accept Date", #PB_Button_MultiLine)
    StringGadget(#DateResultsString, 550, 280, 280, 20, "Date Result:",#PB_String_ReadOnly)
    ButtonGadget(#CloseButton, 368, 215, 65, 20, "Close")
    TextGadget(#InfoText, 510, 205, 120, 100, "Select date and then Click on either Button --> . Then Click on the Accept Button to Accept that dates input.")
  EndIf
EndProcedure

OpenWindow_Main_Window()

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #WorkCalendar
        Case #AssignedButton
          seldate$ = FormatDate("%mm/%dd/%yy", GetGadgetState(#WorkCalendar))
          SetGadgetText(#AssignedDateString,seldate$)
          SetGadgetColor(#AssignedDateString,#PB_Gadget_BackColor,$90FF90)
        Case #CompletedButton
          seldate$ = FormatDate("%mm/%dd/%yy", GetGadgetState(#WorkCalendar))
          SetGadgetText(#CompletedDateString,seldate$)
          SetGadgetColor(#CompletedDateString,#PB_Gadget_BackColor,$90FF90)
        Case #AcceptButton
          assignedDate$ = GetGadgetText(#AssignedDateString)
          completedDate$ = GetGadgetText(#CompletedDateString)
          If assignedDate$ = ""
            SetGadgetText(#DateResultsString,"Need to select the Assignment Date.")
          ElseIf completedDate$ = ""
            SetGadgetText(#DateResultsString,"Need to select the Completetion Date.")
          Else
            SetGadgetText(#DateResultsString,"Assigned Date = " + assignedDate$ + ", Completed Date = " + completedDate$)
            SetGadgetText(#AssignedDateString, "")
            SetGadgetText(#CompletedDateString, "")
          EndIf
          
          DisableGadget(#AssignedButton, 0)
          DisableGadget(#CompletedButton, 0)
          SetGadgetColor(#AssignedDateString,#PB_Gadget_BackColor,-1)
          SetGadgetColor(#CompletedDateString,#PB_Gadget_BackColor,-1)
          
        Case #CloseButton
          End
      EndSelect
      
    Case #PB_Event_CloseWindow
      Select EventWindow()
        Case #Main_Window
          CloseWindow(#Main_Window)
          Break
      EndSelect
  EndSelect
ForEver

Re: Reusable CalendarGadget

Posted: Sat Feb 04, 2012 4:26 pm
by MachineCode
yrreti wrote:When using the CalendarGadget, it has a bad flaw in that you can't select the same date twice in a row.
Yeah? So what? If the date is selected, why are you trying to click it again? Of course that won't generate a second event -- the date is already selected from the first click! Did you not store that result? I think you're creating problems where none exist. ;)

Re: Reusable CalendarGadget

Posted: Sat Feb 04, 2012 9:05 pm
by yrreti
MachineCode
Yeah? So what? If the date is selected, why are you trying to click it again? Of course that won't generate a second event -- the date is already selected from the first click! Did you not store that result? I think you're creating problems where none exist.
Of course that won't generate a second event
That's my point! If you read the above and tried the first code, the CalendarGadget won't generate a second event if you need to select the same number. The 'received date' goes to two different paths.
One you select for the Assigned date, and one you select for the Completed date, because the completed date could be a
different date. The problem occurs only if it's the same date. I like Demivec's approach and will have to look into that.
Here's the issue. If some one purchases and uses the program and is use to clicking the Assigned button and selecting a date.
And then clicking on the Completed button and selecting the same date. It won't work! and they will probably think the programs
defective.

Demivec
I didn't see any significant difference between the two versions you posted.
The first code I posted above is with the problem as listed above. You can't click on the same date for the next requested
input. For instance you selected 02/12/12 for the Assigned. Now click on Completed and try to assign the same date to it.
You can't. The second code I posted above does allow you to do this.
But I appreciate your interesting approach to the problem, and am definitely going to investigate trying to adapt
it to my much more complex code, then the code I posted here as an example, to see if I can do it that way.
Thank you very much for your input and sharing your interesting approach to the problem.
If you know a way to improve it -- Please -- add and post it here. That's how we learn.
Like I previously quoted above. That's what nice about this forum. There is always some one willing to help, or share interesting
code or ideas, to help you learn and try to solve any coding problems you may have. :D

Re: Reusable CalendarGadget

Posted: Sat Feb 04, 2012 9:20 pm
by IdeasVacuum
Well, I have not checked your code but it seems to me that: it could be you. I have a couple of (PB4.60) 32bit apps using the calendar as a pop-up for date input and you can select the same date all day long, it always works......

Re: Reusable CalendarGadget

Posted: Sat Feb 04, 2012 10:04 pm
by yrreti
IdeasVacuum
Thanks for your reply.
But if you just try the first code, You will see that it won't work on your computer either.
Your popup method will work every time, because the CalendarGadget is reset each time.
That's what I'm accomplishing with the second code example above by closing and reloading the
calendar window with the CalendarGadget in it.
The pop up idea is nice, and I even use that in some other programs that I wrote too.
But in this case, I need the CalendarGadget to remain visible on the screen.

Re: Reusable CalendarGadget

Posted: Sat Feb 04, 2012 11:08 pm
by IdeasVacuum
Oh I see. When I use it as a pop-up, it's on it's own window (so that I can improve it slightly cosmetically). The window is created on launch of the main app, hidden. It's un-hidden whenever the User calls it (right-mouse click in a ListIcon cell), and that all fits-in with what you have said about having a separate calendar window as a solution.

So, here is the answer to your issue. In the main loop of the original code, Case #WorkCalendar, add 2 lines of code on the end:

Code: Select all

    Case #WorkCalendar
      seldate=GetGadgetState(#WorkCalendar)
      seldate$ = FormatDate("%mm/%dd/%yy", seldate)
      If ac=1
        SetGadgetText(#AssignedDateString,seldate$)
      ElseIf ac=2
        SetGadgetText(#CompletedDateString,seldate$)
      EndIf

      FreeGadget(#WorkCalendar)
      CalendarGadget(#WorkCalendar, 640, 20, 180, 155)

Re: Reusable CalendarGadget

Posted: Sat Feb 04, 2012 11:39 pm
by yrreti
IdeasVacuum
Something about how PB changes over the years. I somehow missed the FreeGadget command or never
used it before, so I didn't even look for it to try it. Those two lines of code work absolutely beautiful here.
At least now if someone else tries or needs to do this, we have a decent solution.

Thank you very much for your help, and so simple a solution. :oops:

Re: Reusable CalendarGadget

Posted: Sun Feb 05, 2012 12:27 am
by yrreti
The above two lines work great, but I soon found there was one little addition that needed to be added.
If you have multiple windows open, you also need to use UseGadgetList(WindowID(#ECF_Window)).

For example: If the CalendarGadgets from the #ECF_Window, you need to tell it which gadget list from which
window to use, or it won't work.

Code: Select all

      FreeGadget(#WorkCalendar)
      UseGadgetList( WindowID(#ECF_Window))
      CalendarGadget(#WorkCalendar, 635, 5, 180, 155)

Re: Reusable CalendarGadget

Posted: Sun Feb 05, 2012 1:47 am
by MachineCode
yrreti wrote:For instance, if you need to use it to assign a date to a job, and then assign a completed date, that is
finished on the same day.
You can't, unless you first select another date first, and then that date.
I still disagree. Based literally on what you wrote above (bold added by myself), I tried your original code.

Here's how I started:

(1) I clicked "Assigned".
(2) I clicked 15th Feb.
(3) I clicked "Accept Date".
(4) I see "Assigned Date = 02/15/12".

So far, so good. Then I did this:

(1) I clicked "Completed".
(2) The completed date is the same as the first, so there's no need to click the date, as it's already selected.
(3) So I just clicked "Accept Date" instead of clicking the calendar at all.
(4) I see "Completed Date = 02/15/12" -- exactly what you wanted.

I fail to see the problem.

Re: Reusable CalendarGadget

Posted: Sun Feb 05, 2012 3:28 am
by IdeasVacuum
I fail to see the problem.
....because you are looking at it through developer's eyes.

Users would expect to be able to select the same date from the calender widget, they would be accustomed to selecting two dates, just occasionally those two dates are the same. It isn't possible to make a GUI completely foolproof because some fools are ingenious, but there is no need to make life difficult if it can be helped.

Re: Reusable CalendarGadget

Posted: Sun Feb 05, 2012 6:48 am
by yrreti
IdeasVacuum wrote:
Users would expect to be able to select the same date from the calender widget, they would be accustomed to selecting two dates, just occasionally those two dates are the same.
(I added the underline)
Thanks IdeasVacuum :lol: That's exactly my point.
And thanks again for showing me how to do it, because it works great now from a users point of view.