Announcement

Collapse
No announcement yet.

Mapping Text Boxes to a UDT - How?

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

  • Mapping Text Boxes to a UDT - How?

    Hi everyone,
    What I would like to do is to map the text buffer of a text/combo box to a member of a udt.
    The reason is pretty ordinary, I would like to avoid lots of "control set text" and "control get text" expressions.
    If this is possible, then to change the contents of a data entry screen would simply involve fetching the appropriate record and refreshing the dialog.
    I am in the middle of designing a database with 20 or more text/combo boxes and mapping them directly to a udt will simplify everything enormously.
    The answer might be a custom control, but I have fruitlessly searched Poffs and the forums for something similar to no avail.
    I am not asking for someone to do the work for me, but a few pointers (ptrs?) would be handy.
    Best Regards
    Gary Barnes
    The Control Key

    If you are not part of the solution
    then you are either a gas, solid, plasma or some other form of matter.

  • #2
    Not possible. A 'set text' of some sort would be required even on a custom control.
    Adam Drake
    Drake Software

    Comment


    • #3
      Hi Adam,
      Thanks for your response.
      My research leads me to the same conclusion.
      I'll just have to intercept text change events and update that way I suppose.
      Cheers
      Gary Barnes
      The Control Key

      If you are not part of the solution
      then you are either a gas, solid, plasma or some other form of matter.

      Comment


      • #4
        Acceptable Solution

        Hi,
        For those that may be interested in my solution.
        I have elected to trap the Control Message in the dialog callback procedure.
        Simple stuff, but maybe it could be a useful technique for someone else.

        Code:
            SELECT CASE CBCTLMSG
                   CASE %EN_UPDATE
                        CONTROL GET TEXT CBHNDL, CBCTL TO temp
                        SELECT CASE CBCTL
                               CASE %CERTIFICATE : item.certificate = temp
                        END SELECT
                   CASE %CBN_SELCHANGE
                        COMBOBOX GET TEXT CBHNDL, CBCTL TO temp
                        SELECT CASE CBCTL
                               CASE %IDC_Decision : item.decision = temp
                        END SELECT
            END SELECT
        And so on for all of the members of the UDT.
        I think that this thread might be done with.

        I realized that the use of the fragment above isn't properly explained, so if you will allow.
        The purpose of the code is to automatically update the members of a UDT with form data contained in various text and combo boxes.
        When the callback function is executed, the code above examines the control message, determines it origins and updates the appropriate member of the UDT.
        In effect it automatically updates the UDT on the fly.
        I thought that it was neat because what I have done in previous programs is to set up a sequence of control get text commands when a dialog box was closed. This solution seems less clunky for want of a better way to put it.


        Regards
        Last edited by Gary Barnes; 15 Feb 2008, 10:30 AM. Reason: Further Clarification
        Gary Barnes
        The Control Key

        If you are not part of the solution
        then you are either a gas, solid, plasma or some other form of matter.

        Comment


        • #5
          Originally posted by Gary Barnes View Post
          Hi everyone,
          I would like to avoid lots of "control set text" and "control get text" expressions.
          If this is possible,
          Yes, it is possible.
          I'm doing this way
          Code:
          '--------------------------------------------------
          ' These MACROses must run inside callback function
          '--------------------------------------------------
          ' Read TEXTBOX/LABEL/etc content
          MACRO FUNCTION GetTxt (id)
             MACROTEMP t
             LOCAL t AS STRING
             CONTROL GET TEXT CBHNDL, id TO t
          END MACRO = t
          
          ' Update TEXTBOX/LABEL
          MACRO PutTxt(id,t) = CONTROL SET TEXT CBHNDL, id, t
          
          ' Append a new line into multiline TEXTBOX
          MACRO AppTxt (id, t)
             MACROTEMP T2
             LOCAL T2 AS STRING
             CONTROL GET TEXT CBHNDL, id TO T2
             T2 = T2 & T & $CRLF
             CONTROL SET TEXT CBHNDL, id, T2
          END MACRO
          
          ' Get CHECKBOX status
          MACRO FUNCTION GetChk (id)
             MACROTEMP t
             LOCAL t AS LONG
             CONTROL GET CHECK CBHNDL, id TO t
          END MACRO = t

          Comment


          • #6
            Thanks Aslan,
            That is also a possible solution.
            Regards
            Gary Barnes
            The Control Key

            If you are not part of the solution
            then you are either a gas, solid, plasma or some other form of matter.

            Comment


            • #7
              > would like to avoid lots of "control set text" and "control get text" expressions.

              Your immediate problem is solved, but any particular reason for avoiding these statements?

              Besides, that's what you did anyway.... you are just doing them in the EN_UPDATE.

              BTW re your design... it's really not necessary to update your UDT on each EN_UPDATE (as far as I can tell). (insufficent code posted).

              If you are not using that UDT until the user clicks "Do it" then you are just wasting cycles by doing it on every keystroke. Instead, when the user clicks "Do it" THEN you build your UDT by doing CONTROL GET TEXT for each applicable control... basically, the controls themselves serve as "temp" variables for you.

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

              Comment


              • #8
                Hi MCM,
                Sorry for the delay in responding to your post.
                It was just an idea that I wanted to follow up because it would be quite interesting if it could be made to work.
                I am using only one CONTROL GET TEXT which is minimal enough for my taste.
                I have a procedure with similar intent designed to automatically load the combo boxes and text boxes when the dialog is created.
                I suppose that I could update the UDT when a list box loses focus and this will waste fewer cycles
                Overall I can add text boxes and other controls with minimal extra code changes.
                In any case I am not trying to avoid any statements, I even use Global Variables and Goto's where appropriate.
                I program in FORTH every now and it awakens an obsession with minimal code.
                It is surprisingly easy to write PB code in a Forth like way, sometimes having a stack to spare can be handy.
                Don't you find it annoying creating single use variables in a procedure?

                Anyway thanks for your interest Mr Mattias.

                Regards
                Gary Barnes
                The Control Key

                If you are not part of the solution
                then you are either a gas, solid, plasma or some other form of matter.

                Comment


                • #9
                  I use arrays of text boxes

                  Gary,

                  In cases where I have forms with lots of text boxes that may also be linked to a database or file records, what I do is create an array of text boxes, i.e., an array of DWORDs for the HWND of textboxes created in CreateWindowEx() statements. Oftentimes I put the x,y,cbWidth,cbHeight data for each control in another two dimensional array. Then of course I can run all the text box creation code through a For loop to create textboxes all over the form. Of course I also need an incrementing counter for the ctrl id of each control.

                  In terms of obtaining the necessary notification of when a user modifies data in any particular text box (of course, one needs to know this so that persistant storage can be modified, i.e., 'saved'), there are essentially two ways of doing this. First, if each control is subclassed, in the subclass procedure (which of course receives both WM_CHAR and WM_KEYDOWN messages), you can obtain the identity of the particular textbox that received the keystroke, and save that info into some sort of boolean byte array riding alongside for later modifications to the database or file.

                  The second way is similiar as textboxes send that notification message to their parent when a keystroke occurs. In that way you can also save the data to a byte array of booleans.

                  When a user finally clicks a 'Submit' button (or trap WM_CLOSE messages), you can iterate through your byte array of blnDataEntered() variables to see which data in which textboxes the user has modified. In this way all GetWindowText() SetWindowText() code is actually done in loops. Its a fairly complex setup I know, but it works. One can also use the sledge hammer approach of operating individually on each text box, but the way I described is somewhat more elegant. I probably at some point in the distant past developed the technique by looking at piles of redundant textbox access code and said to myself "Couldn't this be done in loops?"

                  If I've lost you in my rather brief description, I could elaborate further.
                  Fred
                  "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                  Comment


                  • #10
                    (of course, one needs to know this so that persistant storage can be modified, i.e., 'saved'),
                    My point is, "persistent" storage in addition to the content of the controls is not needed if nothing is done with that data until the user performs the "Do It" action.
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      Couldn't you use the control id (minus a constant) to give you the index of the appropriate text in a member array within your UDT?

                      Code:
                       
                          '  get text from text controls
                          case %WM_SOMETHINGORANOTHER
                              control get text cbhndl, cbctl to myudt.texts( cbctl - k )
                      I'm sure that you can get the control class without much difficulty & add a select statement to deal with the other control classes.

                      Just bluffing - I haven't tried it.

                      Comment


                      • #12
                        Less : the new More

                        This is what I meant - but don't try it with PBFORMS!:
                        (the point being that you never have to rewrite the GETUM button handler. Just design your form and set up an equate value for each control)

                        Code:
                        #COMPILE EXE
                        #DIM ALL
                        
                        #PBFORMS BEGIN INCLUDES
                        #IF NOT %DEF(%WINAPI)
                            #INCLUDE "WIN32API.INC"
                        #ENDIF
                        
                        %IDD_DIALOG1   =  101
                        %IDC           = 1000
                        %IDCCOUNT      =    7
                        %IDC_GETUM_BN  = 2001
                        %IDC_SHOWUM_BN = 2002
                        %IDC_LABEL1    = 2007
                        %IDC_LABEL2    = 2008
                        %IDC_LABEL3    = 2009
                        %IDC_LABEL4    = 2010
                        %IDC_LABEL5    = 2011
                        %IDC_LABEL6    = 2012
                        %IDC_LABEL7    = 2014
                        
                        %firstthing    = 1
                        %secondthing   = 2
                        %thirdthing    = 3
                        %fourththing   = 4
                        %fifththing    = 5
                        %sixthing      = 6
                        %sevenththing  = 7
                        
                        
                        DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
                        DECLARE FUNCTION SampleComboBox(BYVAL hDlg AS DWORD, BYVAL lID AS LONG, BYVAL lCount AS LONG) AS LONG
                        DECLARE FUNCTION SampleListBox(BYVAL hDlg AS DWORD, BYVAL lID AS LONG, BYVAL lCount AS LONG) AS LONG
                        DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                        
                        TYPE mytype
                            ctldata(%IDCCOUNT) AS STRING * 64
                        END TYPE
                        
                        FUNCTION PBMAIN()
                            ShowDIALOG1 %HWND_DESKTOP
                        END FUNCTION
                        
                        CALLBACK FUNCTION ShowDIALOG1Proc()
                            LOCAL  szClassName AS ASCIZ * 64
                            LOCAL i AS LONG
                            LOCAL s AS STRING
                            STATIC MyUDT AS mytype
                            
                            
                            SELECT CASE AS LONG CBMSG
                                CASE %WM_INITDIALOG
                        
                                CASE %WM_NCACTIVATE
                                    STATIC hWndSaveFocus AS DWORD
                                    IF ISFALSE CBWPARAM THEN
                                        hWndSaveFocus = GetFocus()
                                    ELSEIF hWndSaveFocus THEN
                                        SetFocus(hWndSaveFocus)
                                        hWndSaveFocus = 0
                                    END IF
                        
                                CASE %WM_COMMAND
                                    SELECT CASE AS LONG CBCTL
                        
                                        CASE %IDC_GETUM_BN
                                            IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                                FOR i = 1 TO %IDCCOUNT
                                                    getclassname ( getdlgitem(CBHNDL, %IDC + i), BYVAL VARPTR(szClassName), SIZEOF(szclassname))
                                                    SELECT CASE szClassName
                                                        CASE "Edit"
                                                            CONTROL GET TEXT CBHNDL, %IDC + i TO s
                                                        CASE "ListBox"
                                                            LISTBOX GET TEXT CBHNDL, %IDC + i TO s
                                                        CASE "ComboBox"
                                                            COMBOBOX GET TEXT CBHNDL, %IDC + i TO s
                                                            IF s = "" THEN CONTROL GET TEXT CBHNDL, %IDC + i TO s
                                                    END SELECT
                                                    MyUDT.ctldata(i) =  s
                                                NEXT
                                            END IF
                        
                                        CASE %IDC_SHOWUM_BN
                                            IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                                BEEP
                                                FOR i = 1 TO %IDCCOUNT
                                                    s = s + TRIM$(MyUDT.ctldata(i)) + $CRLF
                                                NEXT
                                                ? s
                                            END IF
                                    END SELECT
                            END SELECT
                        END FUNCTION
                        
                        FUNCTION SampleComboBox(BYVAL hDlg AS DWORD, BYVAL lID AS LONG, BYVAL lCount AS LONG) AS LONG
                            LOCAL i AS LONG
                        
                            CONTROL SEND hDlg, lID, %CB_SETEXTENDEDUI, %TRUE, 0
                        
                            FOR i = 1 TO lCount
                                COMBOBOX ADD hDlg, lID, USING$("Test Item #", i)
                            NEXT i
                        END FUNCTION
                        
                        FUNCTION SampleListBox(BYVAL hDlg AS DWORD, BYVAL lID AS LONG, BYVAL lCount AS LONG) AS LONG
                            LOCAL i AS LONG
                        
                            FOR i = 1 TO lCount
                                LISTBOX ADD hDlg, lID, USING$("Test Item #", i)
                            NEXT i
                        END FUNCTION
                        
                        FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                            LOCAL lRslt AS LONG
                        
                            LOCAL hDlg  AS DWORD
                        
                            DIALOG NEW hParent, "Less is more!", 70, 70, 217, 233, %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME OR %WS_SYSMENU OR _
                                %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT _
                                OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                            CONTROL ADD TEXTBOX,  hDlg, %IDC + %firstthing, "", 70, 10, 140, 15
                            CONTROL ADD TEXTBOX,  hDlg, %IDC + %secondthing, "", 70, 30, 140, 15
                            CONTROL ADD LISTBOX,  hDlg, %IDC + %thirdthing, , 70, 50, 140, 45
                            CONTROL ADD COMBOBOX, hDlg, %IDC + %fourththing, , 70, 100, 140, 25
                            CONTROL ADD TEXTBOX,  hDlg, %IDC + %fifththing, "", 70, 130, 140, 25
                            CONTROL ADD TEXTBOX,  hDlg, %IDC + %sixthing, "", 70, 160, 140, 15
                            CONTROL ADD TEXTBOX,  hDlg, %IDC + %sevenththing, "", 70, 180, 140, 15
                            CONTROL ADD LABEL,    hDlg, %IDC_label7, "Seventh Thing", 5, 185, 65, 15
                            CONTROL ADD BUTTON,   hDlg, %IDC_GETUM_BN, "Get Um", 170, 210, 40, 15
                            CONTROL ADD BUTTON,   hDlg, %IDC_SHOWUM_BN, "Show Um", 10, 210, 40, 15
                            CONTROL ADD LABEL,    hDlg, %IDC_LABEL1, "First Thing", 5, 15, 65, 15
                            CONTROL ADD LABEL,    hDlg, %IDC_LABEL2, "Second Thing", 5, 35, 65, 15
                            CONTROL ADD LABEL,    hDlg, %IDC_LABEL3, "Third Thing", 5, 55, 65, 15
                            CONTROL ADD LABEL,    hDlg, %IDC_LABEL4, "Fourth Thing", 5, 105, 65, 15
                            CONTROL ADD LABEL,    hDlg, %IDC_LABEL5, "Fifth Thing", 5, 135, 65, 15
                            CONTROL ADD LABEL,    hDlg, %IDC_LABEL6, "Sixth thing", 5, 165, 65, 15
                        
                            SampleListBox  hDlg, %IDC + %thirdthing, 30
                            SampleComboBox hDlg, %IDC + %fourththing, 30
                        
                            DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
                        
                            FUNCTION = lRslt
                        END FUNCTION
                        Last edited by Chris Holbrook; 24 Feb 2008, 05:59 AM.

                        Comment


                        • #13
                          ... your byte array of blnDataEntered() variables to see which data in which textboxes the user has modified.
                          Who needs a 'changed array?" Let Windows keep track of it for you.....
                          Code:
                          %ID_EDIT_CONTROL_FIRST    = n
                          %ID_EDIT_CONTROL_SECOND   = %ID_EDIT_CONTROL_FIRST + 1
                          %ID_EDIT_CONTROL_THIRD    = %ID_EDIT_CONTROL_FIRST + 2
                          ....
                          %ID_EDIT_CONTROL LAST = last above 
                          
                          
                          
                            SELECT CASE CBMSG
                                 CASE %WM_COMMAND
                                     SELECT CASE CBCTL 
                                       CASE %ID_DO_IT
                                           FOR iCtrl = %EDIT_CONTROL_FIRST TO %EDIT_CONTROL_LAST
                                              CONTROL SEND CBHNDL, iCtrl, %EM_GETMODIFY, %NULL, %NULL TO bChanged
                                              IF ISTRUE bChanged THEN
                                                 CONTROL GET TEXT CBHNDL, ictrl TO S
                                                 SELECT CASE iCtrl
                                                    CASE %ID_EDIT_CONTROL_FIRST
                                                       TYPE SET MyUDt.First = S   ' or LSET, YMMV 
                                                
                                                    CASE %ID_EDIT_CONTROL_SECOND
                                                       TYPE SET MyUDt.Second = S
                           
                                                    CASE %ID_EDIT_CONTROL_THIRD
                                                      TYPE SET MyUDt.Third = S
                                                  ....
                                                  END SELECT
                                                  CONTROL SEND CBHNDL, CBCTL, _
                                                         %EM_SETMODIFY, %FALSE, %NULL ' reset modify flag.
                          
                                               END IF
                                              
                                           NEXT
                                           MSGBOX "myUDt updated for everything which has changed and changed flag reset"
                                  ......
                          MCM
                          Michael Mattias
                          Tal Systems (retired)
                          Port Washington WI USA
                          [email protected]
                          http://www.talsystems.com

                          Comment


                          • #14
                            Bad TV

                            Nothing good on TV last night so here's my doodling from last night from about midnight to 2AM.

                            Program creates 40 text boxes and 40 labels on a form plus one command button - the labels and edit controls all done in a loop. During that process all the text boxes are subclassed. This kills two birds with one stone. First, it makes it easy to do tab - enter key navigation between edit controls. Second, when a char key press comes through it sets on of my byte variables in a 40 byte storage area allocated during WM_CREATE. This is HeapAlloc() memory accessed with a byte pointer and stored at offset zero in cbWndExtra bytes.

                            When you click the 'SUBMIT'' button another window is opened and the booleans in the 40 byte cbWndExtra bytes are displayed. Also, a text file is opened in this latter form's WM_PAINT and the contents of the text boxes as well as their 'altered' state printed.

                            There are certainly lots of ways to do this and this is the technique I use in my 'production' apps. All in all I'd say the program isn't too bad for an app with 81 controls on it and only around 200 lines of code.

                            Code:
                            #Compile Exe
                            #Include "Win32api.inc"
                            %IDC_SUBMIT = 2050
                            Global fnOldEditProc As Dword
                            
                            
                            Type WndEventArgs
                              wParam               As Long
                              lParam               As Long
                              hWnd                 As Dword
                              hInst                As Dword
                            End Type
                            
                            
                            Function fnOutputProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
                              If wMsg=%WM_PAINT Then
                                 Local lpPaint As PAINTSTRUCT
                                 Local szLocalBuffer As Asciiz*32
                                 Local hMainWindow As Dword
                                 Local pBytes As Byte Ptr
                                 Local strText As String
                                 Register i As Long
                                 Local hDC As Long
                                 Local fp As Long
                                 fp=Freefile
                                 Open "Output.txt" For Append As #fp
                                 hMainWindow=GetWindowLong(hWnd,0)
                                 pBytes=GetWindowLong(hMainWindow,0)
                                 hDC=BeginPaint(hWnd,lpPaint)
                                 Print #fp,"Edit #        Contents       Edited?"
                                 Print #fp,"===================================="
                                 For i=1 To 40
                                   strText="edit " & Str$(i)
                                   If @pBytes[i-1] Then
                                      strText=strText+"  True"
                                   Else
                                      strText=strText+"  False"
                                   End If
                                   If i<=20 Then
                                      Call TextOut(hDC,10,20*i,Byval Strptr(strText),Len(strText))
                                   Else
                                      Call TextOut(hDC,225,20*i-400,Byval Strptr(strText),Len(strText))
                                   End If
                                   Call GetWindowText(GetDlgItem(hMainWindow,i+2000),szLocalBuffer,32)
                                   Print #fp, i, szLocalBuffer, @pBytes[i-1]
                                 Next i
                                 Close #fp
                                 Call EndPaint(hWnd,lpPaint)
                              End If
                            
                            
                              fnOutputProc=DefWindowProc(hWnd,wMsg,wParam,lParam)
                            End Function
                            
                            
                            Function fnEditSubClassProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
                              If wMsg=%WM_CHAR Then
                                 Local hParent As Dword
                                 Local iCtrl As Long
                                 Select Case As Long Lowrd(wParam)
                                   Case %VK_TAB, %VK_RETURN
                                     Local hNext As Dword
                                     hParent=GetParent(hWnd)
                                     iCtrl=GetDlgCtrlID(hWnd)
                                     If iCtrl<2040 Then
                                        Incr iCtrl
                                     Else
                                        iCtrl=2001
                                     End If
                                     hNext=GetDlgItem(hParent,iCtrl)
                                     Call SetFocus(hNext)
                                   Case Else
                                     Local pBytes As Byte Ptr
                                     hParent=GetParent(hWnd)
                                     iCtrl=GetDlgCtrlID(hWnd)
                                     pBytes=GetWindowLong(hParent,0)
                                     @pBytes[iCtrl-2001]=%TRUE
                                 End Select
                              End If
                            
                              fnEditSubClassProc=CallWindowProc(fnOldEditProc,hWnd,wMsg,wParam,lParam)
                            End Function
                            
                            
                            Function fnWndProc_OnCreate(Wea As WndEventArgs) As Long
                              Local lpCreateStruct As CREATESTRUCT Ptr
                              Local hEdit,hLabel,hBtn As Dword
                              Local szTmpBuffer As Asciiz*16
                              Local szClass As Asciiz *16
                              Local pBytes As Byte Ptr
                              Local wcx As WNDCLASSEX
                              Local hHeap As Dword
                              Register i As Long
                            
                              lpCreateStruct=Wea.lParam
                              [email protected]
                              hHeap=GetProcessHeap()
                              pBytes=HeapAlloc(hHeap,%HEAP_ZERO_MEMORY,40)
                              Call SetWindowLong(Wea.hWnd,0,pBytes)
                              If pBytes Then
                                 For i=1 To 40
                                   szTmpBuffer="label"+Trim$(Str$(i))
                                   If i<=20 Then
                                      hEdit=CreateWindowEx(%WS_EX_CLIENTEDGE,"edit","",%WS_CHILD Or %WS_VISIBLE,80,i*25,100,20,Wea.hWnd,2000+i,Wea.hInst,Byval %NULL)
                                      hLabel=CreateWindowEx(0,"static",szTmpBuffer,%WS_CHILD Or %WS_VISIBLE,10,i*25,60,20,Wea.hWnd,-1,Wea.hInst,Byval %NULL)
                                   Else
                                      hEdit=CreateWindowEx(%WS_EX_CLIENTEDGE,"edit","",%WS_CHILD Or %WS_VISIBLE,320,i*25-500,100,20,Wea.hWnd,2000+i,Wea.hInst,Byval %NULL)
                                      hLabel=CreateWindowEx(0,"static",szTmpBuffer,%WS_CHILD Or %WS_VISIBLE,240,i*25-500,60,20,Wea.hWnd,-1,Wea.hInst,Byval %NULL)
                                   End If
                                   szTmpBuffer="Edit #"+Trim$(Str$(i))
                                   Call SetWindowText(hEdit,szTmpBuffer)
                                   fnOldEditProc=SetWindowLong(hEdit,%GWL_WNDPROC,CodePtr(fnEditSubClassProc))
                                 Next i
                                 hBtn=CreateWindowEx(0,"button","Submit",%WS_CHILD Or %WS_VISIBLE,40,545,350,25,Wea.hWnd,%IDC_SUBMIT,Wea.hInst,Byval %NULL)
                                 szClass="Output Screen"
                                 wcx.cbSize=SizeOf(wcx)
                                 wcx.style=%CS_HREDRAW Or %CS_VREDRAW
                                 wcx.lpfnWndProc=CodePtr(fnOutputProc)
                                 wcx.cbClsExtra=0
                                 wcx.cbWndExtra=4
                                 wcx.hInstance=Wea.hInst
                                 wcx.hIcon=LoadIcon(%NULL, ByVal %IDI_APPLICATION)
                                 wcx.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW)
                                 wcx.hbrBackground=GetStockObject(%WHITE_BRUSH)
                                 wcx.lpszMenuName=%NULL
                                 wcx.lpszClassName=VarPtr(szClass)
                                 Call RegisterClassEx(wcx)
                              Else
                                 Local iReturn As Long
                                 iReturn=MsgBox("Couldn't Allocate Memory!",%MB_ICONERROR,"Bad News!")
                                 fnWndProc_OnCreate=-1
                                 Exit Function
                              End If
                            
                              fnWndProc_OnCreate=0
                            End Function
                            
                            
                            Function fnWndProc_OnCommand(Wea As WndEventArgs) As Long
                              If Lowrd(Wea.wParam)=%IDC_SUBMIT And Hiwrd(Wea.wParam)=%BN_CLICKED Then
                                 Local hOutput As Dword
                                 hOutput= _
                                 CreateWindowEx _
                                 ( _
                                   0, _
                                   "Output Screen", _
                                   "Bytes Set From Text Box Input", _
                                   %WS_OVERLAPPEDWINDOW, _
                                   700,50,400,480, _
                                   0, _
                                   0, _
                                   GetModuleHandle(""), _
                                   Byval %NULL _
                                 )
                                 Call SetWindowLong(hOutput,0,Wea.hWnd)
                                 Call ShowWindow(hOutput,%SW_SHOWNORMAL)
                              End If
                            
                              fnWndProc_OnCommand=0
                            End Function
                            
                            
                            Function fnWndProc_OnDestroy(Wea As WndEventArgs) As Long
                              Local pBytes As Byte Ptr
                            
                              pBytes=GetWindowLong(Wea.hWnd,0)
                              Call HeapFree(GetProcessHeap(),%NULL,pBytes)
                              Call PostQuitMessage(0)
                            
                              fnWndProc_OnDestroy=0
                            End Function
                            
                            
                            Function fnWndProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
                              Local Wea As WndEventArgs
                            
                              Select Case As Long wMsg
                                Case %WM_CREATE
                                  Wea.hWnd=hWnd : Wea.wParam=wParam : Wea.lParam=lParam
                                  fnWndProc=fnWndProc_OnCreate(Wea)
                                  Exit Function
                                Case %WM_COMMAND
                                  Wea.hWnd=hWnd : Wea.wParam=wParam : Wea.lParam=lParam
                                  fnWndProc=fnWndProc_OnCommand(Wea)
                                  Exit Function
                                Case %WM_DESTROY
                                  Call PostQuitMessage(0)
                                  fnWndProc=fnWndProc_OnDestroy(Wea)
                                  Exit Function
                              End Select
                            
                              fnWndProc=DefWindowProc(hWnd,wMsg,wParam,lParam)
                            End Function
                            
                            
                            Function WinMain(ByVal hIns As Long,ByVal hPrev As Long,ByVal lpCL As Asciiz Ptr,ByVal iShow As Long) As Long
                              Local winclass As WndClassEx
                              Local szAppName As Asciiz*16
                              Local Msg As tagMsg
                              Local hWnd As Dword
                            
                              szAppName="CtrlArry"
                              winclass.cbSize=SizeOf(winclass)
                              winclass.style=%CS_HREDRAW Or %CS_VREDRAW
                              winclass.lpfnWndProc=CodePtr(fnWndProc)
                              winclass.cbClsExtra=0
                              winclass.cbWndExtra=4
                              winclass.hInstance=hIns
                              winclass.hIcon=LoadIcon(%NULL, ByVal %IDI_APPLICATION)
                              winclass.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW)
                              winclass.hbrBackground=%COLOR_BTNFACE+1
                              winclass.lpszMenuName=%NULL
                              winclass.lpszClassName=VarPtr(szAppName)
                              Call RegisterClassEx(winclass)
                              hWnd=CreateWindow(szAppName,"Control Array Demo",%WS_OVERLAPPEDWINDOW,200,100,450,625,0,0,hIns,ByVal 0)
                              Call ShowWindow(hWnd,iShow)
                              While GetMessage(Msg,%NULL,0,0)
                                TranslateMessage Msg
                                DispatchMessage Msg
                              Wend
                            
                              Function=msg.wParam
                            End Function
                            I'll admit - not much in the way of comments! The control IDs are set in the loop that creates them starting at 2001 to 2040. When a key is pressed the hWnd of the specific control receiving the key press will come through in the subclass. At that point the GetDlgCtrlID() and GetDlgItem() Api functions can obtain the identity of the text box where the action occurred. Then focus can be set to the next text box in the sequence or the @pBytes[ctrlID - 1] boolean toggeled.
                            Fred
                            "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                            Comment


                            • #15
                              Originally posted by Fred Harris View Post
                              Nothing good on TV...
                              There never is. Throw it away. If life is a yard long, how many inches is TV worth?

                              Originally posted by Fred Harris View Post
                              Program creates 40 text boxes and 40 labels on a form...the program isn't too bad for an app with 81 controls on it and only around 200 lines of code.
                              I read this and thought - I wonder how many lines using DDT? The answer is 80, and for my money, it needs less documentation. I'm not anti SDK in the least, BTW.

                              Code:
                              #COMPILE EXE
                              #DIM ALL
                              
                              #IF NOT %DEF(%WINAPI)
                                  #INCLUDE "WIN32API.INC"
                              #ENDIF
                              %IDD_DIALOG1   =  101
                              %IDC           = 1000
                              %IDCCOUNT      =   40
                              %IDC_GETUM_BN  = 2001
                              %IDC_SHOWUM_BN = 2002
                              
                              '-----------------------------------------------------------------------
                              TYPE mytype   ' to store the text from each control in a single UDT array
                                  ctldata(%IDCCOUNT) AS STRING * 64
                              END TYPE
                              '------------------------------------------------------------------------
                              CALLBACK FUNCTION ShowDIALOG1Proc()
                                  LOCAL  szClassName AS ASCIZ * 64
                                  LOCAL i, x, y AS LONG
                                  LOCAL s AS STRING
                                  STATIC MyUDT AS mytype
                              
                                  SELECT CASE AS LONG CBMSG
                                      CASE %WM_INITDIALOG
                                          FOR i = 0 TO %IDCCOUNT - 1
                                              IF i > 19 THEN x = 180 ELSE x = 20
                                              y = ((i MOD 20) * 15) + 10
                                              CONTROL ADD LABEL, CBHNDL, %idc + %IDCCOUNT + i + 1, TRIM$(STR$(i+1)),x - 10, y, 8, 12
                                              CONTROL ADD TEXTBOX,  CBHNDL, %IDC + i + 1, "", x, y, 140, 12
                                          NEXT
                                      CASE %WM_NCACTIVATE
                                          STATIC hWndSaveFocus AS DWORD
                                          IF ISFALSE CBWPARAM THEN
                                              hWndSaveFocus = GetFocus()
                                          ELSEIF hWndSaveFocus THEN
                                              SetFocus(hWndSaveFocus)
                                              hWndSaveFocus = 0
                                          END IF
                              
                                      CASE %WM_COMMAND
                                          SELECT CASE AS LONG CBCTL
                              
                                              CASE %IDC_GETUM_BN
                                                  IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                                      FOR i = 1 TO %IDCCOUNT
                                                          CONTROL GET TEXT CBHNDL, %IDC + i TO MyUDT.ctldata(i)
                                                      NEXT
                                                  END IF
                              
                                              CASE %IDC_SHOWUM_BN
                                                  IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                                      BEEP
                                                      FOR i = 1 TO %IDCCOUNT
                                                          s = s + TRIM$(MyUDT.ctldata(i)) + $CRLF
                                                      NEXT
                                                      ? s
                                                  END IF
                                          END SELECT
                                  END SELECT
                              END FUNCTION
                              '---------------------------------------------------------------------
                              FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                                  LOCAL lRslt AS LONG
                                  LOCAL hDlg  AS DWORD
                              
                                  DIALOG NEW hParent, "MULTEXT", 10, 10, 335, 335, %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME OR %WS_SYSMENU OR _
                                      %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT _
                                      OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                                  CONTROL ADD BUTTON,   hDlg, %IDC_GETUM_BN, "Get Um", 10, 315, 40, 15
                                  CONTROL ADD BUTTON,   hDlg, %IDC_SHOWUM_BN, "Show Um", 70, 315, 40, 15
                                  DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
                              
                                  FUNCTION = lRslt
                              END FUNCTION
                              '---------------------------------------------------------------------
                              FUNCTION PBMAIN()
                                  ShowDIALOG1 %HWND_DESKTOP
                              END FUNCTION

                              Comment


                              • #16
                                Nice example Chris! What does this code do? Restore focus to a particular text box?

                                Code:
                                CASE %WM_NCACTIVATE
                                            STATIC hWndSaveFocus AS DWORD
                                            IF ISFALSE CBWPARAM THEN
                                                hWndSaveFocus = GetFocus()
                                            ELSEIF hWndSaveFocus THEN
                                                SetFocus(hWndSaveFocus)
                                                hWndSaveFocus = 0
                                            END IF
                                Fred
                                "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                                Comment


                                • #17
                                  Fred, I usually delete that bit of code. It's created by PB Forms every time, the purpose being to reclaim the focus after switching from another application. It is a bit contentious, there have been questions raised - all a bit over my head.

                                  Come to think, if you take it out, that makes 70 lines of code! bet I could get it down too. DDT must have sold a lot of compilers!

                                  Comment

                                  Working...
                                  X