Announcement

Collapse
No announcement yet.

Mapping Text Boxes to a UDT - How?

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

  • Chris Holbrook
    replied
    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!

    Leave a comment:


  • Fred Harris
    replied
    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

    Leave a comment:


  • Chris Holbrook
    replied
    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

    Leave a comment:


  • Fred Harris
    replied
    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.

    Leave a comment:


  • Michael Mattias
    replied
    ... 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, [B]%EM_GETMODIFY[/B], %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, _
                                   [B]%EM_SETMODIFY[/B], %FALSE, %NULL ' reset modify flag.
    
                         END IF
                        
                     NEXT
                     MSGBOX "myUDt updated for everything which has changed and changed flag reset"
            ......
    MCM

    Leave a comment:


  • Chris Holbrook
    replied
    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.

    Leave a comment:


  • Chris Holbrook
    replied
    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.

    Leave a comment:


  • Michael Mattias
    replied
    (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.

    Leave a comment:


  • Fred Harris
    replied
    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.

    Leave a comment:


  • Gary Barnes
    replied
    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

    Leave a comment:


  • Michael Mattias
    replied
    > 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

    Leave a comment:


  • Gary Barnes
    replied
    Thanks Aslan,
    That is also a possible solution.
    Regards

    Leave a comment:


  • Aslan Babakhanov
    replied
    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

    Leave a comment:


  • Gary Barnes
    replied
    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

    Leave a comment:


  • Gary Barnes
    replied
    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

    Leave a comment:


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

    Leave a comment:


  • Gary Barnes
    started a topic Mapping Text Boxes to a UDT - How?

    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
Working...
X