Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

ComboBox not accepting a pre-recorded date 1

Status
Not open for further replies.

SitesMasstec

Programmer
Sep 26, 2010
508
Brasil
Hello colleagues!

I have a form with this code in the Init procedure:
Code:
    WITH thisform
         ...
        .dtSaida.Value=YDATASAIDA
        ...

Where YDATASAIDA stores a Date (I have confirmed that YDATASAIDA, is a D (Date) VARTYPE, so I am sure its type is Date).

This is the portion on the form to store the date:
FormDataSaida.JPG
It is a ComboBox, and I need it to show the date recorded from another session (using ctl32_DatePicker, from Carlos Alloatti). Of course the user will be able to alter the date.

When running the form an error appears (just for fields storing dates):
ErroDataSaida.JPG


What is wrong?
 
Couple of things you can do.
One, SET STEP ON before WITH, and then check the value of the variables/constants as you step through, and it will tell you what value is actually contained in ThisForm.dtSaida.Value (you can also check the value of YDATASAIDA is.
OR, if you're concerned that stepping through will change the outcome, use MESSAGEBOX(ThisForm.dtSaida.Value) or MESSAGEBIX(YDATASAIDA) (I would do both, just to see what they are).
That will tell you what the value is, and it may be clear where your data type mismatch is.
Also, what is the code on the line that is generating the mismatch error? Are you checking it for VARTYPE() or is it some other comparison, where one value on the other side of the comparison doesn't match you dtSaida type? (i.e. if you compare .T. == Thisform.dtSaida.Value) and dtSaida.Value is a date, then this will give you a data type mismatch error, as will any two different data types that are being compared).
 
I replied recently to a similar question and most likely this has a similar cause.

Datatype mismatches can only mean one thing, something you are storing in a control is trying to be placed in a field that does not match it.

You can assign any value to a variable or a control and it will never give you a data type mismatch error, so it's not a matter o the control allowing you to push a date to it. It works like a variable and FoxPro variables are not rigid. You can say X=4, then say X="HELLO", then say X={01/01/2024} and it won't throw an error.

The trouble comes when you try to push that control to a field, and that also depends on how you do it. Some people use a ControlSource, which binds it directly to the column. Some people will replace the value later by saying REPLACE MyColumn with ThisForm.MyControl.Value. It is at that moment that the column type needs to match.

One possibility here is that a ControlSource may be ambiguous, such as "MyColumn", instead of "MyTable.MyColumn", where there is also a variable with the same name but different type, or in cases where there is a DataSession (I never use them), and there is a reference in there to an entirely different table.

Lastly, another common cause is timing. If the control was bound while there was no selected record, where the value is essentially NULL at that moment.

As @Scott24x7 pointed out, the best way to know for sure what is going on is using the debugger to step through the code line by line and then look at what's going on just before the error is thrown and / or throwing some MessageBoxes out there at key moments to confirm things are as they should be.
 
A combobox value can only be a date if the items of its recordsource are also dates.

It doesn't matter that you want to display a date and have a date and think that's correct. Only a textbox could be set to a date without any further preparations on the side of the textbox, When you set a combobox value, you don't set an item it displays, that's always set with the combobox recordsource and recordsourcetype and the value has to match that of an item.

Without preparing any items or having items that are not the DATE type, you get a datatype mismatch - of course.
 
I need it to show the date recorded from another session (using ctl32_DatePicker, from Carlos Alloatti).
Then why are you using a combobx and not a ctl32_DatePicker? Anything you recorded should be displayed for further modification with the same control it was recorded with.
You're showing a deep non understanding of anything. You don't even realize that the error with not first setting combobox items is the same error you made in your last post. You don't even remember the last lesson you've been teached about comboboxes. It's insane to help you, if you don't learn anything.
 
Scott, Joe, Chris, I'm trying to understand and put into practice your advices
Chris, ctl32_DatePicker is "inside" the ComboBox, it is the Parent code for the ComboBox.
 
Hi SitesMasstec,
I use this same control, but I create the "Illusion" of a dropdown. The Ole control appers on the form only as the "drop down" for the combo. When you click it, the Ole calendar appears.
1727773218268.png
When you select a date with it, the calendar OLE Date picker pops up:
1727773347296.png

You pick a date, and then note that the date is then that value updates the apparent "selection" (in this case the date of an expense report entry).
The code in the "Change" event of the OLE Date Picker is simple:
Code:
*** ActiveX Control Event ***
* whenever user makes change in control update form with new values

dDate = DATE(This.Year, This.Month, This.Day)
*
This.Parent.txtEXPENSEDETAILDATE.Value = dDate

Where This.Parent.txtEXPENSEDATEDETAIL is the object that holds the date (The OLE Picker does not), it's just a control on the form to make it easy to pick the date, and always in the right "format").

Using a combobox where you have both .Value and .DisplayValue can cause a LOT of confusion, and you're probably working harder than you need to. Simplify it with a regular text box, and let the date picker do what it does best, while letting the text box do what it does best. And of course with the text box, you can still enforce the DATE format you want, and allow users to enter by hand instead of using the date picker, without "entangling" the two. (And not at the quantum level...)

Just thought you might try this simple(r) solution, I took your approach initially as well, but soon found creating the illusion of the combo box was easier to do, and easier for users to use without all the issues of working with the combo box for unnecessary complexity.

For clarity, note that there are TWO objects on the form, set next to each other after "Expense Date" in the image example I provided.
 
ctl32_DatePicker is "inside" the ComboBox.
Documentation of the ctl32_datepicker https://ctl32.blogspot.com/p/ctl32-datepicker.html says this:
This control uses a standard VFP combobox and a ctl32_monthcalendar
That doesn't change anything about what I su can't set the value of a VFP combobox before iut has items. And the ctl32_datepicker is managing is combobox, not you.
The last line in that documentation is the interesting line for you:
The date value can be set/retrieved in the ctlValue property.
Don't set .dtSaida.Value=YDATASAIDA, instead
Code:
.dtSaida.ctlValue=YDATASAIDA
That is, if dtSaida is your name for the ctl32_datepicker on your form.

It's all documented, you just have to read it.

Let me tell you a secret how you can get to the point in the documentation you're interested in faster than just reading it fully: You use CTRL+F to find somthing, then search for a relevant key word like SET and the amount of words you have to read reduces very much. If you don't get to what you're intereested in there, search other relevant terms, like date or value, in this case.

Edit, again: Just a few lines above that the documentaiton says:
The control can be bound by using the ctlControlSource property. DO NOT use the ControlSource property, since VFP comboboxes cannot be bound to a date type field/property/variable.
So that's another useful property: ctlControlSoure to be set to a date field of a table, for example. Also notice the warning and advice about VFP comboboxes not being able to be bound to date type values in fields, properties or variables, that also tells you what you tried had to error.

If you use a new (free) control, there's still one minimum prize you pay anyway: Learning how to use it. Especially when you encounter errors, why not refer to the documentation?
 
Last edited:
Hi,

If you don't want to work with ctl32_datepicker you may want to write your own datepicker. The attached demo project shows how to do. It is less fancy than the ctl32_datepicker but the code is VFP only

In order to run the demo:
- Copy the .zip file into a test folder
- Unzip it there
- Run the start.prg
- Doubleclick any date control on any of the displayed forms

All the rest is self explaining

hth

MarK
 

Attachments

  • formcommunication.zip
    4 KB · Views: 6
Last edited:
Hi,

The former .zip file seems to have been corrupted. Please find attached a new one

Enjoy

MarK
 

Attachments

  • formcommunication.zip
    8.2 KB · Views: 5
Hi,

... and for those who prefer the datepicker demo in code

Code:
**************************************************
PUBLIC goFDOne, goFDTwo, goFDatePicker

goFDOne = NEWOBJECT("frmFDOne")
goFDOne.Visible = .T.
goFDOne.Show

goFDTwo = NEWOBJECT("frmFDTwo")
goFDTwo .Visible = .T.
goFDTwo .Show

goFDatePicker = NEWOBJECT("frmFDatePicker")

Read Events

Close all
Clear All

RETURN

**************************************************

DEFINE CLASS frmFDOne AS Form
    Caption = "Dates"
    ShowTips = .T.
    Top = 24
    Left = 24
    Height = 120
    Width = 270
    BorderStyle = 2
    DataSession = 2
    
    goObject = .NULL.
    giTop = 150
    giLeft = 150
    
    ADD OBJECT lblRClick as Label WITH ;
        Top = 12, Left = 12, AutoSize = .T., Caption = "Rightclick on any textbox to call the datepicker"
    
    ADD OBJECT lblD1 as Label WITH ;
        Top = 36, ;
        Left = 12, ;
        Caption = "Date 1"

    ADD OBJECT lblD2 as Label WITH ;
        Top = 72, ;
        Left = 12, ;
        Caption = "Date 2"
        
    ADD OBJECT lblDay1 as Label WITH ;
        Top = 36, Left = 174, Caption = ""

    ADD OBJECT lblDay2 as Label WITH ;
        Top = 72, Left = 174, Caption = ""

    ADD OBJECT txtD1 as TextBox WITH ;
        Top = 36, ;
        Left = 60, ;
        ReadOnly = .T., ;
        ControlSource = "csrDates.dDateOne"
        
        PROCEDURE txtD1.Refresh()
            ThisForm.lblDay1.Caption = CDOW(This.Value)
        
        ENDPROC 
        
        PROCEDURE txtD1.RightClick()
            ThisForm.goObject = This
            goFDatePicker.Top  = ThisForm.giTop
            goFDatePicker.Left = ThisForm.giLeft
            goFDatePicker.goCallingForm = goFDOne
            
            IF EMPTY(This.Value)
                WITH goFDatePicker
                    .spnYear.Value = YEAR(DATE())
                    .spnMonth.Value = MONTH(DATE())
                    .spnDay.Value = DAY(DATE())
                ENDWITH
            ELSE 
                WITH goFDatePicker
                    .spnYear.Value = YEAR(This.Value)
                    .spnMonth.Value = MONTH(This.Value)
                    .spnDay.Value = DAY(This.Value)
                ENDWITH
            ENDIF 
            
            goFDatePicker.Show(1)

        ENDPROC 
    
    ADD OBJECT txtD2 as TextBox WITH ;
        Top = 72, ;
        Left = 60, ;
        ReadOnly = .T., ;
        ControlSource = "csrDates.dDateTwo"

        PROCEDURE txtD2.Refresh()
            ThisForm.lblDay2.Caption = CDOW(This.Value)
        
        ENDPROC 
        
        PROCEDURE txtD2.RightClick()
            ThisForm.goObject = This
            goFDatePicker.Top  = ThisForm.giTop
            goFDatePicker.Left = ThisForm.giLeft
            goFDatePicker.goCallingForm = goFDOne

            IF EMPTY(This.Value)
                WITH goFDatePicker
                    .spnYear.Value = YEAR(DATE())
                    .spnMonth.Value = MONTH(DATE())
                    .spnDay.Value = DAY(DATE())
                ENDWITH
            ELSE 
                WITH goFDatePicker
                    .spnYear.Value = YEAR(This.Value)
                    .spnMonth.Value = MONTH(This.Value)
                    .spnDay.Value = DAY(This.Value)
                ENDWITH
            ENDIF 

            goFDatePicker.Show(1)

        ENDPROC 

    PROCEDURE Load
        SET DATE French
        SET CENTURY ON 
        
        CREATE CURSOR csrDates (dDateOne D , dDateTwo D)
        INSERT INTO csrDates VALUES (DATE() - 15, DATE() + 124)

    ENDPROC 
    
    PROCEDURE Destroy
        CLOSE ALL
        Clear Events

    ENDPROC
ENDDEFINE

*********************************************

DEFINE CLASS frmFDTwo AS Form
    Caption = "Dates"
    ShowTips = .T.
    Top = 48
    Left = 360
    Height = 120
    Width = 270
    BorderStyle = 2
    DataSession = 2

    goObject = .NULL.
    giTop = 180
    giLeft = 180
    
    ADD OBJECT lblRClick as Label WITH ;
        Top = 12, Left = 12, AutoSize = .T., Caption = "Rightclick on any textbox to call the datepicker"
    
    ADD OBJECT lblD1 as Label WITH ;
        Top = 36, ;
        Left = 12, ;
        Caption = "Date 1"

    ADD OBJECT lblD2 as Label WITH ;
        Top = 72, ;
        Left = 12, ;
        Caption = "Date 2"
        
    ADD OBJECT lblDay1 as Label WITH ;
        Top = 36, Left = 174, Caption = ""

    ADD OBJECT lblDay2 as Label WITH ;
        Top = 72, Left = 174, Caption = ""

    ADD OBJECT txtD1 as TextBox WITH ;
        Top = 36, ;
        Left = 60, ;
        ReadOnly = .T., ;
        ControlSource = "csrDates.dDateOne"
        
        PROCEDURE txtD1.Refresh()
            ThisForm.lblDay1.Caption = CDOW(This.Value)
        
        ENDPROC 
        
        PROCEDURE txtD1.RightClick()
            ThisForm.goObject = This
            goFDatePicker.Top  = ThisForm.giTop
            goFDatePicker.Left = ThisForm.giLeft
            goFDatePicker.goCallingForm = goFDTwo
    
            IF EMPTY(This.Value)
                WITH goFDatePicker
                    .spnYear.Value = YEAR(DATE())
                    .spnMonth.Value = MONTH(DATE())
                    .spnDay.Value = DAY(DATE())
                ENDWITH
            ELSE 
                WITH goFDatePicker
                    .spnYear.Value = YEAR(This.Value)
                    .spnMonth.Value = MONTH(This.Value)
                    .spnDay.Value = DAY(This.Value)
                ENDWITH
            ENDIF 

            goFDatePicker.Show(1)

        ENDPROC 
    
    ADD OBJECT txtD2 as TextBox WITH ;
        Top = 72, ;
        Left = 60, ;
        ReadOnly = .T., ;
        ControlSource = "csrDates.dDateTwo"

        PROCEDURE txtD2.Refresh()
            ThisForm.lblDay2.Caption = CDOW(This.Value)
        
        ENDPROC 
        
        PROCEDURE txtD2.RightClick()
            ThisForm.goObject = This
            goFDatePicker.Top  = ThisForm.giTop
            goFDatePicker.Left = ThisForm.giLeft
            goFDatePicker.goCallingForm = goFDTwo
            
            IF EMPTY(This.Value)
                WITH goFDatePicker
                    .spnYear.Value = YEAR(DATE())
                    .spnMonth.Value = MONTH(DATE())
                    .spnDay.Value = DAY(DATE())
                ENDWITH
            ELSE 
                WITH goFDatePicker
                    .spnYear.Value = YEAR(This.Value)
                    .spnMonth.Value = MONTH(This.Value)
                    .spnDay.Value = DAY(This.Value)
                ENDWITH
            ENDIF 

            goFDatePicker.Show(1)

        ENDPROC 

    PROCEDURE Load
        SET DATE French
        SET CENTURY ON 
        
        CREATE CURSOR csrDates (dDateOne D , dDateTwo D)
        INSERT INTO csrDates VALUES (DATE() - 5, DATE() + 54)

    ENDPROC 
    
    PROCEDURE Destroy
        CLOSE ALL
        Clear Events

    ENDPROC
ENDDEFINE

*********************************************
DEFINE CLASS frmFDatePicker AS Form
    Caption = "DatePicker"
    ShowTips = .T.
    Top = 150
    Left = 150
    Height = 150
    Width = 240
    BorderStyle = 2
    MaxButton = .F.
    MinButton = .F.
    Closable = .F.
    
    goCallingForm = .NULL.
    
    ADD OBJECT lblDay as Label WITH Top = 24, Left = 36, Caption = "Day"
    
    ADD OBJECT lblMonth as Label WITH Top = 24, Left = 90, Caption = "Month"

    ADD OBJECT lblYear as Label WITH Top = 24, Left = 144, Caption = "Year"

    ADD OBJECT spnDay as Spinner WITH ;
        Top = 48, Left = 36, Width = 48, Value = DAY(DATE()), SpinnerLowValue = 1, SpinnerHighValue = 31, KeyboardLowValue = 1, KeyboardHighValue = 31
        
    ADD OBJECT spnMonth as Spinner WITH ;
        Top = 48, Left = 90, Width = 48, Value = MONTH(DATE()), SpinnerLowValue = 1, SpinnerHighValue = 12, KeyboardLowValue = 1, KeyboardHighValue = 12

    ADD OBJECT spnYear as Spinner WITH ;
        Top = 48, Left = 144, Width = 60, Value = YEAR(DATE()), SpinnerLowValue = 1900, SpinnerHighValue = 2050, KeyboardLowValue = 1900, KeyboardHighValue = 2050

    ADD object cmdReturnDate as CommandButton WITH ;
        Top = 90, Left = 12, Height = 48, width = ThisForm.Width - 24, Caption = "Return date"
    
        PROCEDURE cmdReturnDate.Click()
        
            LOCAL ldDate as Date, liYear as Integer, liMonth as Integer, liDay as Integer 

            If VarType(Thisform.goCallingForm) = "O" AND VARTYPE(ThisForm.goCallingForm.goObject) = "O"

                liYear = ThisForm.spnYear.Value
                liMonth = ThisForm.spnMonth.Value
                liDay = ThisForm.spnDay.Value

                ldDate = DATE(liYear, liMonth, liDay)
                
                IF EMPTY(ldDate)
                
                    = MESSAGEBOX("Please check the date", 16, "Checking Date", 3000)    
                
                ELSE 
                    WITH ThisForm.goCallingForm   
                        .goObject.Value = ldDate
                        .goObject = .NULL.
                        .Refresh()
                    ENDWITH 

                    ThisForm.Hide()
                
                ENDIF 
            ENDIF 

        ENDPROC 
        
        PROCEDURE Moved()
            WITH This.goCallingForm
                .giLeft = This.Left
                .giTop = This.Top
            ENDWITH 
        ENDPROC 
ENDDEFINE

*********************************************

MarK
 
Last edited:
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top