Announcement

Collapse
No announcement yet.

Trap left click in Superclassed Edit control

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Trap left click in Superclassed Edit control

    What event do I trap in a SuperClassed edit box to keep it from losing focus until it matches a validation if the user clicks in another field?

    Bob Mechler

  • #2
    Wm_killfocus ?
    Fred
    "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

    Comment


    • #3
      Correct. I had two copies of the same include. One didn't have anything in the WM_KILLFOCUS event at all and the other one did. I was compiling in the wrong one. Duh. Sorry.

      Code:
               CASE %WM_KILLFOCUS 
                 Tlen = GetWindowTextLength(CBHNDL) 'get the text length
                 IF Tlen < FieldLen(getdlgctrlid(CBHNDL)) THEN
                   ShowBallonText GetParent(CBHNDL), CBHNDL, "Account field is required"
                   SetFocus CBHNDL
                   EXIT FUNCTION 'stay in field until there is a valid account
                 END IF

      Comment


      • #4
        Or.... you can check entries character by character using EN_CHANGE notification....

        ... this won't 'stay in the field' but if there is a "do it" button you enable/disable based on the user having put something valid in some box, I always liked this particular effect. Button enables/disables 'as you type.'

        Code:
              CASE %ID_FILENAME
                      ' check if the file is avaiable and no worker thread is running already,
                      ' if so enable the start button
                      [b]IF CBCTLMSG = %EN_CHANGE THEN[/b]
                         DIALOG GET USER CBHNDL, %DSU_HTHREAD TO hThread
                         IF ISFALSE hThread THEN    ' no worker thread is running, so we can enable
                                                    ' the 'go' button if this file is valid
                              CONTROL GET TEXT CBHNDL, %ID_FILENAME TO sText
                              IF DIR$ (sText) > "" THEN
                                   CONTROL ENABLE CBHNDL, %ID_START
                              ELSE
                                   CONTROL DISABLE CBHNDL, %ID_START
                              END IF
                         END IF
                      END IF
        Full demo here...
        http://www.powerbasic.com/support/pb...ad.php?t=35619


        MCM
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          Excellent code for a non-superclassed control. I guess I'd use the WM_CHAR event in a superclassed control, wouldn't I or is the %EN_CHANGE event available in a superclassed control, don't know, haven't tried that.

          Bob Mechler

          Comment


          • #6
            I have experiance with this.
            Avoid testing on lost focus and then restore focus.
            It will never work properly icw other controls.
            hellobasic

            Comment


            • #7
              Thanks Edwin. That would explain some things I've started to notice when going from field to field tightly controlling navigation with tests in the vk_up,vk_down, etc and wm_killfocus event. I could force the focus to stay in the control by just not issuing the code section:
              Code:
                             IF CBWPARAM = %VK_UP OR (CBWPARAM = %VK_TAB AND GetAsyncKeyState(%VK_SHIFT)) THEN  
                               SetFocus GetNextDlgTabItem(GetParent(CBHNDL), CBHNDL, -1)
                             ELSE
                               SetFocus GetNextDlgTabItem(GetParent(CBHNDL), CBHNDL, 0)
                             END IF  
                             EXIT FUNCTION
              except in WM_KILLFOCUS. However that was the only way I could figure out how to trap the fact that someone was trying to jump the gun and click in another field with the current field not validated.

              Is is possible to trap the buttonclick before the WM_KILLFOCUS event fires. I remember Visual Foxpro had a validate event ( or ACCESS) that fired prior to the Lost Focus event. That's what I really need here.

              Bob Mechler

              Comment


              • #8
                I think VFP wasn't that good actually but you may had a GUI not being bothered with side effects.

                For tab key you may consider the WM_GETDLGCODE message.
                There is no just before lost focus message.
                There is a WM_MOUSEACTIVATE which may be useful.
                Both these messages are working recursive, first control, then the window receives it (unless prevented and i may be wrong in the order)

                But still, i am sure you'll encounter issues.
                Like two textboxes where the validate decides empty is not good and keeps jumping between these controls (due setfocus())

                Validate should be under a OK button.
                hellobasic

                Comment


                • #9
                  Validate under an OK button would normally be a form validation kind of thing. Very safe.

                  Would there be anything troublesome about sending %BM_CLICK to a validate button control from the %WM_KILLFOCUS event of a superclassed control and let the callback for the button determine where to SetFocus? Either back to the original if the validation fails or the next tabstop.

                  Think I'll try that approach, or I am just being hard-headed?

                  Bob Mechler

                  Comment


                  • #10
                    >or I am just being hard-headed?
                    Hmm.. yes, but you are simply doing what so many had to do before.
                    I had this discusion for hours if not days to explain we are dealing with Windows, not DOS.
                    (It was just before Win95 was out )
                    I wrote some code and worked annoyingly and unpredictable.
                    Though i was using VB3 at that time, i didn't had a hooks and so.
                    Later i tried with PB/DLL 2.0 and discovered it went nowhere.

                    The killfocus and setfocus messages are very low-level and textbox carets will suffer if you aren't doing it right.
                    What other (future) control do you need to take of..?)
                    hellobasic

                    Comment


                    • #11
                      I don't understand the preoccupation with "superclassed"

                      That's really immaterial. Either your "superbutton" sends a WM_COMMAND notification of significant events to its owner or you deliberately (or accidentally?) ate the initiatiing event in your window procedure. Code not shown.

                      MCM
                      Michael Mattias
                      Tal Systems (retired)
                      Port Washington WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        Why superclass?
                        Well,


                        With Control Add "Classname" I can do the following without putting code in a dialog callback under wm_command

                        Navigate using Up,Down,Tab,Shift Tab, and Return and validate the field prior to moving to next or previous control.

                        I can trap Ctrl-F and run another program while the current program is frozen in a loop waiting for a return value from a customized lookup exe that itself has the ability to call another maintenance program and add new items to the lookup.

                        I can validate an ACCOUNT NUMBER or other code by looking it up in a table as part of the validation in the Superclassed control. If it is not found I just clear the field.

                        In one of the superclassed controls I can allow or restrict any set of characters with a different set of allowable characters for each position.

                        I can activate Insert or Overwrite mode in the textbox.

                        I can format and unformat code as I enter or leave the control.

                        In PBMAIN I fill several arrays with Captions, Control Type with switches making the control required or not, buddy lookup buttons and optional description fields as well as the screen it's on, the tab it's on if any, the group it's in, the position, width height, font, color

                        The id of the main superclassed control is used by the arrays and buddy controls are offsets to this control id so that I can update a description control in the superclassed control because I know what it's control id must be.

                        The ultimate reason is that a field for data input needs to behave the same way in all programs it's used in. Every field has field edit rules which used to be repeated (or not) in every program they were used in. This way the SuperClassed control include files nail down the business rules for that field. If they change, we don't have to search for every occurance of the field in use. Just recompile the programs in our main offering.

                        I hope to keep the Dialog callback to handling menu items in WM_COMMAND, WM_DESTROY and WM_NOTIFY, WM_DRAWITEM and that's about it.

                        The programmer then only needs one line of code to add all this functionality to the program.

                        Imagine a Listview superclass that automatically loads data from a pre-defined file relationship and presents a detail modification screen by double clicking on the row and has an incremental search function build in with one line of code.

                        In reviewing POFFS, I noticed many instances where the same functionality was programmed umpteen different ways.

                        In my own code, I was doing the same type of the thing over and over again only every time I did it I made it a little better or added features. This way if I improve how a CUSIP is looked up, verified, that improvement will flow to all the other programs through a recompile.

                        Based on Edwin's advice I've removed any set focus processing in the wm_killfocus event

                        Time to get off my soapbox.

                        The following code is not complete but illustrates a superclassed account number field that does all the things mentioned.

                        Code:
                           GLOBAL F_F1 AS LONG
                        
                           FUNCTION NEditActnrF1Lookup(txtACTNR AS STRING,FileEquate AS LONG) AS STRING
                             BTRVSETUP                                               
                             QF = 5: Q = FileEquate: Q$(Q) = TRIM$(txtACTNR): QNUM = 0: GOSUB 60000
                             IF QSTATUS = 0 THEN  
                               sTxt = F1.ACTNR$         
                             ELSE
                               sTxt = "" 
                             END IF 
                             FUNCTION = sTxt
                           EXIT FUNCTION
                           60000   #INCLUDE "BTRVCALX.INC"
                           END FUNCTION          
                        
                           CALLBACK FUNCTION NEditActnrProc
                              STATIC OldProc AS LONG, OffsetWndExtra AS LONG
                              LOCAL V_NKEYPOS AS LONG,sTXT AS STRING,Txt AS ASCIIZ * %MAX_PATH, zfName AS ASCIIZ * %MAX_PATH
                              LOCAL ValidActnrKeys AS STRING,FieldId as LONG
                              LOCAL ActnrID AS LONG, DescID AS LONG, DescHandle AS LONG
                              DIM  Tlen AS LOCAL LONG
                              ValidActnrKeys$ = " 0123456789" + CHR$(8)
                              ValidActnrKeysAbbrev$ = "Entry must be 7 digits [0-9]"
                              IF CBHNDL = 0 THEN OldProc = CBWPARAM: OffsetWndExtra = CBLPARAM: EXIT FUNCTION
                        
                              'Control Id and Handle of ACTNR
                              ActnrID& = getdlgctrlid(CBHNDL)
                        
                              'Control Id and Handle of Read Only field displaying the F1.ACTNAM
                              DescID& = ActnrID& + scr_NUM_FLD#
                              DescHandle& = GetDlgItem(GetParent(CBHNDL),DescID&)
                              
                              SELECT CASE CBMSG
                                 CASE %WM_GETDLGCODE
                                    FUNCTION = %DLGC_WANTALLKEYS: EXIT FUNCTION
                                 CASE %WM_KEYUP
                                   CONTROL SEND GetParent(CBHNDL),ActnrID&, %EM_GETSEL, 0, 0 TO V_NKEYPOS&     'Used to detect when field is filled           
                                   IF LOWRD(V_NKEYPOS&) = FieldLen(ActnrID&) THEN
                                     GetWindowText CBHNDL, Txt, %MAX_PATH
                                     sTxt = Txt
                                     sTxt = NEditActnrF1Lookup(sTxt,F_F1&) 'Returns the Account or blank if it is not on file
                                     IF LEN(TRIM$(sTxt)) = 0 THEN    
                                      'ShowBallonText GetParent(CBHNDL), CBHNDL, "Account is not on file"
                                       'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_SHOW
                                      ' CONTROL SET TEXT GetParent(CBHNDL),%ER_MSG,"Account is not on file"
                                       'SLEEP 1000                                           
                                       'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_HIDE             
                                       'EXIT FUNCTION ' stay in field until a valid CUSIP is found or the user presses enter with the field empty
                                     END IF
                                     SetWindowText CBHNDL, BYCOPY F1.ACTNR
                        
                                     SetWindowText DescHandle&, BYCOPY F1.ACTNAM  
                                     SetFocus GetNextDlgTabItem(GetParent(CBHNDL), CBHNDL, 0) 'all ok, move to the next field
                                     EXIT FUNCTION
                                   END IF
                                   IF GetWindowTextLength(CBHNDL) = 0 THEN 'handles the case where the field contents become zero during editing
                                     SetWindowText DescHandle&,""
                                   END IF
                                 CASE %WM_KEYDOWN
                                   SELECT CASE CBWPARAM
                                     CASE %VK_UP,%VK_DOWN,%VK_RETURN,%VK_TAB  
                                       Tlen = GetWindowTextLength(CBHNDL) 'get the text length
                                       IF Tlen = FieldLen(ActnrID&) THEN
                                         GetWindowText CBHNDL, Txt, %MAX_PATH
                                         sTxt = Txt
                                         sTxt = NEditActnrF1Lookup(sTxt,F_F1&)  
                                         IF LEN(TRIM$(sTxt)) = 0 THEN  'Field however modified is valid, fill in the description field also   
                                           'ShowBallonText GetParent(CBHNDL), CBHNDL, "Account is not on file"               
                                           'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_SHOW
                                           'CONTROL SET TEXT GetParent(CBHNDL),%ER_MSG,"Account is not on file"
                                           'SLEEP 1000                                           
                                           'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_HIDE             
                                           SetWindowText CBHNDL, ""
                                           SetWindowtext DescHandle&,""               
                                           'EXIT FUNCTION ' stay in field until a valid CUSIP is found or the user presses enter with the field empty
                                         ELSE 'Field however modified is valid, fill in the description field also
                                           SetWindowText CBHNDL, BYCOPY F1.ACTNR
                                           SetWindowText DescHandle&, BYCOPY F1.ACTNAM                      
                                         END IF
                                       ELSE  
                                         'ShowBallonText GetParent(CBHNDL), CBHNDL, "Account field is required"
                                         'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_SHOW
                                         'CONTROL SET TEXT GetParent(CBHNDL),%ER_MSG,"Account field is required"
                                         'SLEEP 1000                                           
                                         'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_HIDE             
                                         'EXIT FUNCTION 'stay in field until there is a valid account 
                                       END IF
                                       IF CBWPARAM = %VK_UP OR (CBWPARAM = %VK_TAB AND GetAsyncKeyState(%VK_SHIFT)) THEN  
                                         SetFocus GetNextDlgTabItem(GetParent(CBHNDL), CBHNDL, -1)
                                       ELSE
                                         SetFocus GetNextDlgTabItem(GetParent(CBHNDL), CBHNDL, 0)
                                       END IF  
                                       EXIT FUNCTION
                                     CASE %VK_F 'find routine
                                       IF GetAsyncKeyState(%VK_CONTROL) THEN
                                         LSET C.INQ = "": LSET C.CSORT = CSORT$
                                         SPARE$ = CPROGID$: LSET C.SPARE = SPARE$: C.LSPARE = LEN(SPARE$)': @pC = C
                                         PU_PROG$ = CPROGID$: LSET C.PU_PROG = PU_PROG$: @pC = C
                                         IF FNSP(CUST_DIR$) THEN
                                           SHELLPROG$ = "PUACCT.EXE "
                                         ELSE
                                           SHELLPROG$ = $STDEXE + "PUACCT.EXE "
                                         END IF
                                         DIALOG DISABLE GetParent(CBHNDL)
                                         Yinstance& = SHELL(SHELLPROG$ + COMMONLINK$)
                                         SLEEP 1000
                                         Zprocessid& = OpenProcess(%PROCESS_QUERY_INFORMATION + %PROCESS_TERMINATE,%False,Yinstance&)
                                         DO
                                           DIALOG DOEVENTS
                                           I& = GetExitCodeProcess(BYVAL Zprocessid&,lpExitCode&)
                                         LOOP WHILE lpExitCode& = %STILL_ACTIVE
                                         DIALOG ENABLE GetParent(CBHNDL)
                                         DIALOG SHOW STATE hdlg,%SW_SHOW
                                         stat = GetCommon(C)
                                         INQACTNR$ = RTRIM$(INQ$)
                                         sTxt = INQACTNR$  'same as if NEditActnrF1Lookup had been called
                                         IF LEN(TRIM$(sTxt)) = 0 THEN 'lookup cancelled go with field contents
                                           GetWindowText CBHNDL, Txt, %MAX_PATH
                                           sTxt = Txt
                                         END IF
                                         sTxt = NEditActnrF1Lookup(sTxt,F_F1&)  
                                         IF LEN(TRIM$(sTxt)) = 0 THEN  'Field however modified is valid, fill in the description field also   
                                           'ShowBallonText GetParent(CBHNDL), CBHNDL, "Account is not on file"               
                                           'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_SHOW
                                           'CONTROL SET TEXT GetParent(CBHNDL),%ER_MSG,"Account is not on file"
                                           'SLEEP 1000                                           
                                           'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_HIDE             
                                           SetWindowText CBHNDL, ""
                                           SetWindowtext DescHandle&,""               
                                           'EXIT FUNCTION ' stay in field until a valid account is found
                                         ELSE 'Field has a valid value from the lookup, fill fields and proceed to the next tab stop
                                           SetWindowText CBHNDL, BYCOPY F1.ACTNR
                                           SetWindowText DescHandle&, BYCOPY F1.ACTNAM                      
                                           SetFocus GetNextDlgTabItem(GetParent(CBHNDL), CBHNDL, 0)
                                           EXIT FUNCTION
                                         END IF
                                       END IF  
                                     CASE %VK_INSERT
                                       IF NOT V_INSOVR THEN
                                         V_INSOVR = -1
                                       SetWindowText GetParent(CBHNDL),"OVR"   
                                       ELSEIF V_INSOVR THEN
                                         V_INSOVR = 0
                                       SetWindowText GetParent(CBHNDL),"INS"   
                                       END IF
                                   END SELECT
                                 CASE %WM_CHAR
                                   IF INSTR(ValidActnrKeys$,CHR$(CBWPARAM)) = 0 THEN
                                     IF CBWPARAM > 32 THEN 
                                       ShowBallonText GetParent(CBHNDL), CBHNDL, ValidActnrKeysAbbrev$
                                       'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_SHOW
                                       'CONTROL SET TEXT GetParent(CBHNDL),%ER_MSG,ValidActnrKeysAbbrev$
                                       'SLEEP 1000                                           
                                       'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_HIDE             
                                     END IF  
                                   END IF  
                                   IF INSTR(ValidActnrKeys$,CHR$(CBWPARAM)) = 0 THEN EXIT FUNCTION
                                   KeyState = GetAsyncKeyState(%VK_OEM_MINUS) OR GetAsyncKeyState(%VK_OEM_PLUS)
                                   IF INSTR("+-",CHR$(CBWPARAM)) > 0 AND KeyState <> &H8001 THEN EXIT FUNCTION
                                   IF V_INSOVR THEN
                                     SendMessage CBHNDL, %EM_GETSEL, 0, 0 TO V_NKEYPOS&     'Used to detect when field is filled           
                                     V_NKEYPOS& = LOWRD(V_NKEYPOS&)
                                     SendMessage CBHNDL, %EM_SETSEL,V_NKEYPOS&,V_NKEYPOS& + 1  'Selects current character
                                     SendMessage CBHNDL, %WM_CLEAR,0,0                       'If nothing to clear doesn't act
                                   END IF
                                 CASE %WM_SETFOCUS
                                   SendMessage CBHNDL, %EM_SETSEL, 0, -1 
                                 CASE %WM_KILLFOCUS 
                        '           Tlen = GetWindowTextLength(CBHNDL) 'get the text length 
                        '           IF Tlen < FieldLen(ActnrID&) AND Tlen > 0 THEN
                        '             ShowBallonText GetParent(CBHNDL), CBHNDL, "WARNING! Account was not found."
                        '           ELSEIF Tlen = 0 THEN
                        '             ShowBallonText GetParent(CBHNDL), CBHNDL, "WARNING! Account is required."                            
                        '           END IF
                                     'SetFocus CBHNDL 
                        '             ShowBallonText GetParent(CBHNDL), CBHNDL, "Account not found"               
                        '             DIALOG GET SIZE GetParent(CBHNDL) TO tot_x&,tot_y&
                        '             DIALOG GET CLIENT GetParent(CBHNDL) TO cli_x&,cli_y&
                        '             DIALOG UNITS GetParent(CBHNDL),tot_x& - cli_x&,tot_y& - cli_y& TO PIXELS non_client_x&,non_client_y&
                        '             DIALOG GET LOC GetParent(CBHNDL) TO MOUSE_X&,MOUSE_Y&
                        '             DIALOG UNITS GetParent(CBHNDL), MOUSE_X&,MOUSE_Y& TO PIXELS P_MOUSE_X&,P_MOUSE_Y&
                        '             CONTROL GET LOC GetParent(CBHNDL),ActnrID& TO TV_X&,TV_Y&
                        '             DIALOG UNITS GetParent(CBHNDL), TV_X&,TV_Y& TO PIXELS P_TV_X&,P_TV_Y&
                        '             SetCursorPos P_MOUSE_X& + P_TV_X& + 10, P_MOUSE_Y& + P_TV_Y& + non_client_y& + 9             
                        '             EXIT FUNCTION 'stay in field until there is a valid account
                        '           ELSEIF Tlen = 0 THEN
                        '             ShowBallonText GetParent(CBHNDL), CBHNDL, "Account field is required"               
                        '           END IF
                              END SELECT
                              FUNCTION = CallWindowProc(OldProc, CBHNDL, CBMSG, CBWPARAM, CBLPARAM) 
                                 
                           END FUNCTION
                        
                           CALLBACK FUNCTION NActnrButtonProc
                              STATIC OldProc AS LONG, OffsetWndExtra AS LONG
                              LOCAL Txt AS ASCIIZ * %MAX_PATH, sTxt AS STRING
                              LOCAL ActnrButtonID AS LONG, ActnrID AS LONG, DescID AS LONG
                              LOCAL ActnrHandle AS LONG, DescHandle AS LONG
                              IF CBHNDL = 0 THEN OldProc = CBWPARAM: OffsetWndExtra = CBLPARAM: EXIT FUNCTION
                              ActnrButtonID& = getdlgctrlid(CBHNDL)
                              ActnrID& = ActnrButtonID& - (scr_NUM_FLD# * 2 )
                              DescID& = ActnrButtonID& - scr_NUM_FLD#
                              ActnrHandle& = GetDlgItem(GetParent(CBHNDL),ActnrID&)
                              DescHandle& = GetDlgItem(GetParent(CBHNDL),DescID&)
                              SELECT CASE CBMSG
                                CASE %WM_LBUTTONDOWN
                                   LSET C.INQ = "": LSET C.CSORT = CSORT$
                                   SPARE$ = CPROGID$: LSET C.SPARE = SPARE$: C.LSPARE = LEN(SPARE$)
                                   PU_PROG$ = CPROGID$: LSET C.PU_PROG = PU_PROG$: @pC = C
                                   IF FNSP(CUST_DIR$) THEN
                                     SHELLPROG$ = "PUACCT.EXE "
                                   ELSE
                                     SHELLPROG$ = $STDEXE + "PUACCT.EXE "
                                   END IF
                                   DIALOG DISABLE GetParent(CBHNDL)
                                   Yinstance& = SHELL(SHELLPROG$ + COMMONLINK$)
                                   SLEEP 1000
                                   Zprocessid& = OpenProcess(%PROCESS_QUERY_INFORMATION + %PROCESS_TERMINATE,%False,Yinstance&)
                                   DO
                                     DIALOG DOEVENTS
                                     I& = GetExitCodeProcess(BYVAL Zprocessid&,lpExitCode&)
                                   LOOP WHILE lpExitCode& = %STILL_ACTIVE
                                   DIALOG ENABLE GetParent(CBHNDL)
                                   DIALOG SHOW STATE hdlg,%SW_SHOW
                                   stat = GetCommon(C)
                                   INQACTNR$ = RTRIM$(INQ$)
                                   sTxt = INQACTNR$
                                   IF LEN(TRIM$(sTxt)) = 0 THEN
                                     GetWindowText ActnrHandle&,Txt,%MAX_PATH
                                     sTxt = Txt
                                   END IF      
                                   sTxt = NEditActnrF1Lookup(sTxt,F_F1&)
                                   IF LEN(TRIM$(sTxt)) = 0 THEN  'Field however modified is valid, fill in the description field also   
                                     ShowBallonText GetParent(CBHNDL), ActnrHandle&, "Account is not on file"               
                                     'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_SHOW
                                     'CONTROL SET TEXT GetParent(CBHNDL),%ER_MSG,"Account is not on file"
                                     'SLEEP 1000                                           
                                     'CONTROL SHOW STATE GetParent(CBHNDL),%ER_MSG,%SW_HIDE             
                                     SetWindowText ActnrHandle&, ""
                                     SetWindowtext DescHandle&,""               
                                     EXIT FUNCTION ' stay in field until a valid account is found
                                   ELSE 'Field has a valid value from the lookup, fill fields and proceed to the next tab stop
                                     SetWindowText ActnrHandle&, BYCOPY F1.ACTNR
                                     SetWindowText DescHandle&, BYCOPY F1.ACTNAM 
                                     SetFocus GetNextDlgTabItem(GetParent(CBHNDL),ActnrHandle&, 0)
                                     EXIT FUNCTION
                                   END IF
                              END SELECT
                              FUNCTION = CallWindowProc(OldProc, CBHNDL, CBMSG, CBWPARAM, CBLPARAM)
                           END FUNCTION
                        Some code not shown that does the actual superclass creation. There is code from a lot of people in here. Semen's Superclass creation code is elsewhere. A lot of this has been trial and error.

                        Bob Mechler

                        Bob Mechler

                        Comment


                        • #13
                          With Control Add "Classname" I can do the following without putting code in a dialog callback under wm_command [italics mine. MCM]
                          A-ha! This explains much.

                          I remember when DDT first came out, I thought the control level callbacks ("CONTROL ADD... CALL functionname") would turn out to be the greatest thing since sliced bread and would be really handy to make highly-maintainable code.

                          I gave it a shot, but discovered I felt a lot more comfortable with all the handlers located in one procedure... the dialog procedure. Plus, the initial release of DDT did not offer the 'CONTROL SET USER' features, and I was really used to using all the controls' "DWL_USER" or "GWL_USERDATA" integer, and the only way at that time to store this kind of data and access it in the separate control procedures was via (ugh!) GLOBAL variables.

                          In addition, I had learned Windows programming with PB/DLL before there was such a thing as 'DDT,' so I was used to having all the code for one screen in one procedure.

                          I guess if you start programming Windows' applications using 'DDT' with 'CONTROL SET USER' capability, it's a lot different.

                          MCM
                          Michael Mattias
                          Tal Systems (retired)
                          Port Washington WI USA
                          [email protected]
                          http://www.talsystems.com

                          Comment


                          • #14
                            If it was just me, I'd do it the way you do. I have to deal with 5 other programmers who aren't api programmers. They are application programmers and used to most of the hard stuff being hidden. They like 'Access' (shudder).

                            Also to have most functions and business logic in superclassed controls and include files that only I and one other programmer deal with makes development by the other programmers very quick. We have a standard look and feel, a standard way to open and access files and a standard way to process things. While uninteresting, it gets programs out the door.

                            Bob Mechler

                            Comment


                            • #15
                              .....used to most of the hard stuff being hidden
                              ... a standard look and feel, a standard way to open and access files and a standard way to process things. While uninteresting, it gets programs out the door.
                              Sounds to me like an ideal situation for giving these programmers a little documentation and a header file pointing to a dynamic link library.
                              Michael Mattias
                              Tal Systems (retired)
                              Port Washington WI USA
                              [email protected]
                              http://www.talsystems.com

                              Comment


                              • #16
                                We do some 'on demand' loading and freeing of customer specific dynamic link libraries as well as some load on first use and leave loaded DLL's.

                                If the client id is such and such we load their library and call the functions there instead of the default functions, etc.

                                If I used dll's for the 'hard stuff' I'd need to put all the gui in the DLL, right?

                                Can you have the parameters defined in the main exe and create the GUI entirely in the DLL. Hmmm. This would keep the INCLUDE files from being listed in every EXE.

                                Can a call back function be in a DLL if the Dialog is created in the main exe?

                                Bob Mechler

                                Comment


                                • #17
                                  >Can a call back function be in a DLL if the Dialog is created in the main exe?

                                  Not directly using DDT syntax, since DDT requires the CALL procedurename within the current code module.


                                  But you could go the indirect route...

                                  Code:
                                  DECLARE FUNCTION RealCallBack  LIB "MyDLL.DLL" _
                                      (BYVAL hwnd AS LONG, _
                                       ByVAL usMSG AS LONG, 
                                       BYVAL wParam AS LONG, _ 
                                       BYVAL lParam AS LONG) AS LONG 
                                  
                                  
                                    DIALOG NEW ....
                                  
                                    DIALOG SHOW hDlg.... CALL FunctionHere
                                  
                                  CALLBACK FUNCTION FunctionHere () AS LONG
                                      FUNCTION = RealCallBack (CBHNDL, CBMSG, CBWPARAM, CBLPARAM) 
                                  END FUNCTION
                                  With SDK-style coding, you don't need the extra function since you supply the address, not the name, of the window or dialog procedure.

                                  I'll guess in your window procedure in the DLL, you could just code it as
                                  Code:
                                  CALLBACK FUNCTION  RealCallback  () EXPORT AS LONG 
                                  
                                  END FUNCTION
                                  ... and all your "CBxxxxx" system constants should still work.

                                  (If this is not doable it certainly should be)

                                  MCM
                                  Last edited by Michael Mattias; 1 Aug 2008, 11:52 AM.
                                  Michael Mattias
                                  Tal Systems (retired)
                                  Port Washington WI USA
                                  [email protected]
                                  http://www.talsystems.com

                                  Comment

                                  Working...
                                  X