Announcement

Collapse
No announcement yet.

Prevent leading and double spaces in TextBox

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

  • Prevent leading and double spaces in TextBox

    I use this sub to control user input.

    Code:
    SUB String_Format_Input_Control( hDlg AS LONG, CB_CTL AS LONG )
    '
    LOCAL TL1 AS LONG
    LOCAL TL2 AS LONG
    LOCAL TS1 AS STRING
    LOCAL TS2 AS STRING
    '
    DIM Updating_Control_FLAG_ST AS STATIC BYTE
    '
    IF ISFALSE Updating_Control_FLAG_ST THEN
      '
      CONTROL GET TEXT hDlg, CB_CTL TO TS1
      '
      IF TS1 <> "" THEN
        '
        CONTROL SEND hDlg, CB_CTL, %EM_GETSEL, VARPTR( TL1 ), VARPTR( TL2 ) ' Get Selected Positions
        '
        Updating_Control_FLAG_ST = %TRUE
        '
        TS2 = MID$( TS1, TL1, 1 ) ' Character Just Typed
        '
        IF TS2 = $SPC AND ( MID$( TS1, TL1 - 1, 1 ) = $SPC OR MID$( TS1, TL1 + 1, 1 ) = $SPC ) THEN
          '
          WINBEEP 800, 100
          '
          TS1 = LTRIM$( LEFT$( TS1, TL1 - 1 ) + MID$( TS1, TL2 + 1 ))
          '
          DECR TL1
          DECR TL2
          '
        ELSEIF LEFT$( TS1, 1 ) = $SPC THEN
          '
          IF TS1 = $SPC THEN
            '
            WINBEEP 800, 100
            '
          END IF
          '
          TS1 = MID$( TS1, 2 )
          '
          RESET TL1
          RESET TL2
          '
       END IF
       '
       CONTROL SET TEXT hDlg, CB_CTL, TS1
       '
       CONTROL SEND hDlg, CB_CTL, %EM_SETSEL, TL1, TL2 ' Position cursor
       '
       RESET Updating_Control_FLAG_ST
       '
       END IF
       '
    END IF
    '
    END SUB
    And then in the CALLBACK

    Code:
    CASE %WM_COMMAND
    '
    SELECT CASE AS LONG CB.CTL
    '
    CASE id of text boxes
    
    SELECT CASE CB.CTLMSG
    '
    CASE %EN_UPDATE
    
    CALL String_Format_Input_Control( CB.HNDL, CB.CTL )
    With some testing the SUB is called many times over when not needed.

    How do I trigger it only when text has actually changed?

  • #2
    Maybe should have static Updating_Control_FLAG_ST under CASE %EN_UPDATE instead?
    '
    Code:
    CASE %EN_UPDATE
      DIM Updating_Control_FLAG_ST AS STATIC BYTE
      IF Updating_Control_FLAG_ST = 0 THEN ' prevent multiple calls to String_Format_Input_Control(
          Updating_Control_FLAG_ST = 1
          CALL String_Format_Input_Control( CB.HNDL, CB.CTL)
          Updating_Control_FLAG_ST = 0
      END IF
    '

    Comment


    • #3
      Why mess around, do it fast.
      Code:
      ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
      
      FUNCTION block_monospace$(src$)
      
        ' -----------------------------------------------------------
        ' left and right trims each line in a block of CRLF delimited
        ' text replacing tabs with spaces and setting single spacing.
        ' DO NOT USE this function on text that does not use BOTH CR
        ' and LF pairs (ASCII 13,10) as results are undefined !
        ' -----------------------------------------------------------
          #REGISTER NONE
      
          LOCAL pst as DWORD
          LOCAL sln as DWORD
      
          dst$ = src$                         ' work on copy
      
          pst = StrPtr(dst$)
      
          ! mov esi, pst
          ! sub esi, 1
          ! mov edi, pst
      
        trm:                                  ' trim leading tabs and spaces
          ! add esi, 1
          ! cmp BYTE PTR [esi], 32
          ! je trm
          ! cmp BYTE PTR [esi], 9
          ! je trm
          ! sub esi, 1
          ! or ebx, -1                        ' set EBX non zero so it falls through the 1st TEST
      
        ' =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      
        pre:
          ! test ebx, ebx                     ' test for zero AFTER its written.
          ! jz pastit
        stlp:
          ! add esi, 1
          ! movzx ebx, BYTE PTR [esi]
          ! cmp ebx, 9
          ! jne nxt1
          ! mov ebx, 32                       ' replace tabs with spaces
        nxt1:
          ! cmp ebx, 32
          ! jne nxt2
          ! cmp BYTE PTR [esi+1], 32          ' test for next space
          ! je pre
          ! cmp BYTE PTR [esi+1], 9           ' test for next tab
          ! je pre
      
        nxt2:
          ! cmp bl, 13
          ! jne writeit
          ! cmp BYTE PTR [esi-1], 32          ' test for previous space
          ! jne writeit
          ! sub edi, 1                        ' RTRIM trailing space
      
        writeit:
          ! mov [edi], bl                     ' write acceptable character
          ! add edi, 1
      
          ! cmp bl, 10                        ' LTRIM following line
          ! je trm
      
        overit:
          ! test ebx, ebx                     ' test for zero AFTER its written.
          ! jnz stlp
      
        ' =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      
        pastit:
      
          ! sub edi, 1
          ! cmp BYTE PTR [edi-1], 32          ' if last character is a space
          ! jne nxt3
          ! sub edi, 1
        nxt3:
      
          ! sub edi, pst                      ' length in EDI
          ! mov sln, edi
      
          FUNCTION = left$(dst$,sln)
      
      END FUNCTION
      
      ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
      hutch at movsd dot com
      The MASM Forum

      www.masm32.com

      Comment


      • #4
        The STATIC variable inside the SUB does prevent multiple calls whilst it's updating but the problem is that the %EN_UPDATE is triggered when nothing has actually changed.

        Comment


        • #5
          Ok, but you get dubble calls because each keypress triggers %EN_UPDATE and your SUB then does a CONTROL SET TEXT even if correction change never was made. If you prevent multiple calls already under %EN_UPDATE instead, it will fix this problem.

          Also, if you have PBWin 10, you could use SHRINK$ to ensure no leading or multiple spaces. Best to be done on each change, because what happens if user paste text into textbox?

          Edit - SHRINK$ removes leading and trailing spaces too, so no need for TRIM$. Or use Steve's extremely fast asm code.

          Comment


          • #6
            > user paste text into textbox

            Or type space-X-space and delete the X.

            I'm curious why you wouldn't just let the user type whatever, then remove leading/double spaces when they click Ok (or whatever).
            "Not my circus, not my monkeys."

            Comment


            • #7
              Originally posted by Eric Pearson View Post
              > user paste text into textbox

              Or type space-X-space and delete the X.

              I'm curious why you wouldn't just let the user type whatever, then remove leading/double spaces when they click Ok (or whatever).
              SUB wont allow an initial space so that part is all ok.

              I want to keep the user input tidy rather than processing when focus lost when my "save" button pressed.

              Actually it's a problem in another part of my code and the UPDATE is only being called once now.

              Comment


              • #8
                Why mess around, do it fast.
                Fast is insignificant here as the user is typing and cannot possibly "outrun" the processing code. Leaving the code in BASIC makes it more maintainable for the OP. (assuming OP and all future maintainers are not qualified assembly language programmers).

                Maybe you should subclass the control, pick off the space character, and reject (ignore) it if either the position is offset zero (character 1) or if the position is "end of text"

                But I like Eric Pearson's idea better... let the user type whatever the hell he wants and clean it up when he's done.

                MCM

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

                Comment


                • #9
                  > wont allow an initial space

                  Sorry, I meant mid-sentence, like "Hello X World".
                  "Not my circus, not my monkeys."

                  Comment


                  • #10
                    Apart from the BEEP deleting the X removes the extra space.

                    Comment


                    • #11
                      I guess I'll have to stare at the code a while longer.
                      "Not my circus, not my monkeys."

                      Comment


                      • #12
                        Final version in case of use to anyone

                        Code:
                        SUB String_Format_Input_Control( hDlg AS LONG, CB_CTL AS LONG )
                        '
                        LOCAL TL1 AS LONG
                        LOCAL TL2 AS LONG
                        LOCAL TS1 AS STRING
                        '
                        DIM Updating_Control_FLAG_ST AS STATIC BYTE
                        '
                        IF ISFALSE Updating_Control_FLAG_ST THEN
                        '
                        CONTROL GET TEXT hDlg, CB_CTL TO TS1
                        '
                        IF TS1 <> "" THEN
                        '
                        CONTROL SEND hDlg, CB_CTL, %EM_GETSEL, VARPTR( TL1 ), VARPTR( TL2 ) ' Get Selected Positions
                        '
                        Updating_Control_FLAG_ST = %TRUE
                        '
                        ' MID$( TS1, TL1, 1 ) ' Character Just Typed
                        '
                        IF mid$( TS1, TL1,1) = $SPC AND ( MID$( TS1, TL1 - 1, 1 ) = $SPC OR MID$( TS1, TL1 + 1, 1 ) = $SPC ) THEN
                        '
                        TS1 = LTRIM$( LEFT$( TS1, TL1 - 1 ) + MID$( TS1, TL2 + 1 ))
                        '
                        DECR TL1
                        DECR TL2
                        '
                        ELSEIF LEFT$( TS1, 1 ) = $SPC THEN
                        '
                        TS1 = MID$( TS1, 2 )
                        '
                        RESET TL1
                        RESET TL2
                        '
                        END IF
                        '
                        CONTROL SET TEXT hDlg, CB_CTL, TS1
                        '
                        CONTROL SEND hDlg, CB_CTL, %EM_SETSEL, TL1, TL2 ' Position cursor
                        '
                        RESET Updating_Control_FLAG_ST
                        '
                        END IF
                        '
                        END IF
                        '
                        END SUB

                        Comment


                        • #13
                          You still get double calls to SUB String_Format_Input_Control. Insert this at top of SUB String_Format_Input_Control and see:
                          '
                          Code:
                            DIM c AS STATIC BYTE  ' shows 2, 4, 6, etc - should be 1, 2, 3.
                            INCR c
                            DIALOG SET TEXT hDlg, STR$(c)
                          '
                          Try this one instead - added flag to prevent double calls on change or not. Same test as above shows 1, 2, 3.. etc
                          '
                          Code:
                          '====================================================================
                          SUB String_Format_Input_Control( hDlg AS LONG, CB_CTL AS LONG )
                          
                            '----------------------------
                            DIM c AS STATIC BYTE  ' remove this block when pleased with count (1, 2, 3..)
                            INCR c
                            DIALOG SET TEXT hDlg, STR$(c)
                            '----------------------------
                            '
                            LOCAL iWasChanged AS BYTE  ' added flag to prevent double calls
                            LOCAL TL1 AS LONG
                            LOCAL TL2 AS LONG
                            LOCAL TS1 AS STRING
                            '
                            DIM Updating_Control_FLAG_ST AS STATIC BYTE
                            '
                            IF ISFALSE Updating_Control_FLAG_ST THEN
                                '
                                CONTROL GET TEXT hDlg, CB_CTL TO TS1
                                '
                                IF LEN(TS1) THEN  ' <- LEN is faster than string compare
                                    '
                                    CONTROL SEND hDlg, CB_CTL, %EM_GETSEL, VARPTR( TL1 ), VARPTR( TL2 ) ' Get Selected Positions
                                    '
                                    Updating_Control_FLAG_ST = %TRUE
                                    '
                                    ' MID$( TS1, TL1, 1 ) ' Character Just Typed
                                    '
                                    IF MID$( TS1, TL1,1) = $SPC AND ( MID$( TS1, TL1 - 1, 1 ) = $SPC OR MID$( TS1, TL1 + 1, 1 ) = $SPC ) THEN
                                        '
                                        TS1 = LTRIM$( LEFT$( TS1, TL1 - 1 ) + MID$( TS1, TL2 + 1 ))
                                        '
                                        DECR TL1
                                        DECR TL2
                                        iWasChanged = 1
                                        '
                                    ELSEIF LEFT$( TS1, 1 ) = $SPC THEN
                                        '
                                        TS1 = MID$( TS1, 2 )
                                        '
                                        RESET TL1
                                        RESET TL2
                                        iWasChanged = 1
                                        '
                                    END IF
                                    '
                                    IF iWasChanged THEN CONTROL SET TEXT hDlg, CB_CTL, TS1
                                    '
                                    CONTROL SEND hDlg, CB_CTL, %EM_SETSEL, TL1, TL2 ' Position cursor
                                    '
                                    RESET Updating_Control_FLAG_ST
                                    '
                                END IF
                                '
                            END IF
                            '
                          END SUB
                          '

                          Comment

                          Working...
                          X