Announcement

Collapse
No announcement yet.

get&set the caret position in the textbox

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

  • get&set the caret position in the textbox

    Hello.
    I `ve started studiing PB a month ago (when the visual programing cource was started). I am writting a program that solves quadratic equation.
    My program should control user`s input (user can input only numbers).
    I use CONTROL GET TEXT to get the text from the control. Then I check it for non-number characters (when %EN_CHANGE takes place) and delete wrong characters. And if something was changed in the text (with my check procedure) i replece the text in the textbox with the correct one using CONTROL SET TEXT. And here is a probem:
    The carriage in the textbox is MOVED TO THE START of the text every time I use CONTROL SET TEXT. In my opinion, this thing not handy for a user. So I want to know how can I set carriage position and get it.
    (I see the problem solution in saving the current position of the carriage and its restoring after the text is changed(with CONTROL SET TEXT)).

    (If your know the way to change the text in the text box, that does not change the carriage position, please, also tell me).
    Last edited by Ivan Utkin Vladimirovich; 18 Oct 2009, 06:58 AM.

  • #2
    You need to use the %EM_GETSEL message to get the current position and %EM_SETSEL message to set it afterwards.

    Something like:

    CONTROL GET TEXT CB.HNDL, CB.CTL TO strText
    CONTROL SEND CBHNDL, CB.CTL %EM_GETSEL, VARPTR(x), VARPTR(y)
    'x and y now hold the first and last position of the selected text.
    'if they are the same, there is no selected text and they indicate the caret 'position.

    ' process your text and modify x and y if necessary to set the new caret 'position
    ....

    CONTROL SET TEXT CB.HNDL, CB.CTL, strText
    'now reset the selection
    CONTROL SEND CBHNDL, CB.CTL %EM_SETSEL, VARPTR(x), VARPTR(y)

    Comment


    • #3
      You might also consider a couple of alternative methods of controlling the user's input..
      e.g use this style for the TextBox..
      %ES_NUMBER
      "Allow only digits ("0123456789") instead of characters. Although Windows does not consider the negation symbol (-) or period symbol (.) to be digits, subclassing a TextBox that does not use %ES_NUMBER and rejecting "unwanted" keystrokes is common practice.."

      There is a discussion in this thread about using subclassing to trap non-numeric input.. http://www.powerbasic.com/support/pb...ad.php?t=41696

      Another option is to check the user's input with the Verify function as shown in this sample code.
      Code:
      #COMPILE EXE
      #DIM ALL
      #INCLUDE "WIN32API.INC"
       
      %BTN_Test      = 102
      %LBL_LABEL1    = 101
      %TXT_TEXTBOX1  = 100
      '------------------
       
      CALLBACK FUNCTION DlgProc()
       LOCAL sTest$, x&
        SELECT CASE AS LONG CB.MSG
       
          CASE %WM_COMMAND
            SELECT CASE AS LONG CB.CTL
              CASE %IDOK
                IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                  CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX1 TO sTest
                  MSGBOX "sTest = "+stest, ,"Result"
                END IF
       
              CASE %TXT_TEXTBOX1
                IF CB.CTLMSG = %EN_UPDATE THEN
                  CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX1 TO sTest
                  x = VERIFY (sTest , "-+,.1234567890")
                  IF x > 0 THEN
                    WinBeep 800, 50
                    sTest = REMOVE$(sTest, MID$(sTest, x, 1))
                    CONTROL SET TEXT CB.HNDL, %TXT_TEXTBOX1, sTest
                    CONTROL SEND CB.HNDL, %TXT_TEXTBOX1, %EM_SETSEL, x-1, x-1
                  END IF
                END IF
       
            END SELECT
          CASE %WM_SYSCOMMAND
            IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN
              DIALOG END CB.HNDL
            END IF
       
        END SELECT
      END FUNCTION
      '------------------/DlgProc
       
      FUNCTION PBMAIN()
       LOCAL hDlg  AS DWORD
       DIALOG FONT "ARIAL",10,0,0
        DIALOG NEW 0, "Numeric Input Test", , , 200, 120, %WS_CAPTION OR %WS_SYSMENU, TO hDlg
        CONTROL ADD LABEL,  hDlg, %LBL_LABEL1, "-+,.1234567890 allowed", 50, 25, 120, 20
        CONTROL ADD BUTTON,  hDlg, %IDOK, "Test", 75, 60, 50, 15
        CONTROL ADD TEXTBOX, hDlg, %TXT_TEXTBOX1, "", 45, 90, 100, 13
       
        DIALOG SHOW MODAL hDlg, CALL DlgProc
       
      END FUNCTION
      '------------------/PbMain
      Last edited by Dave Biggs; 18 Oct 2009, 09:10 AM. Reason: fix error in ..%EM_SETSEL, x, x
      Rgds, Dave

      Comment


      • #4
        To Stuart McLachlan
        Thanks it is the thing I was looking for.

        Everything started to work fine after some changes (in bold)
        >CONTROL SEND CBHNDL, CB.CTL,%EM_GETSEL, VARPTR(x), VARPTR(y)

        >CONTROL SEND CBHNDL, CB.CTL, %EM_SETSEL, x,y
        (As I understood %EM_SETSEL don`t need (and even don`t want to get) parameters sent byref).
        Last edited by Ivan Utkin Vladimirovich; 18 Oct 2009, 11:58 AM. Reason: I found that control there was no commas after both CB.CTL

        Comment


        • #5
          Originally posted by Ivan Utkin Vladimirovich View Post

          >CONTROL SEND CBHNDL, CB.CTL, %EM_SETSEL, x,y
          (As I understood %EM_SETSEL don`t need (and even don`t want to get) parameters sent byref).
          That's what you get when you post aircode at night when you are worn out after a hard day sailing. I just cut and pasted the first line and changes the GET to SET without thinking

          Comment


          • #6
            I `ve started studiing PB a month ago (when the visual programing cource was started).
            First time I have ever heard of a PowerBASIC product being used in a formal training course.

            I am writting a program that solves quadratic equation
            OTOH, this is NOT something new. Writing a program to find the roots of a quadratic equation was my first assignment in the first and only programming class I ever took. (October, 1967).

            I still have that program. If you get stuck, just drop me a line and I'll see if I can find someone who can dup the 80-column punch cards.
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment


            • #7
              input with number "5"

              hello dear powerbasic users

              I am quite new here at the forum and would like to learn more about ddt and input (key) handling for users. I am not very familiar with ddt, I want to work for the future with sdk window creations and more. powerbasic I am using since nearly two, three weeks closer, but it's a hard job to see all little details how to build new popup windows of this great coding language I know by my father over twenty years

              => now I would like to fix this problem (for another example calls "calculator" I am working with ) how to get by button click the result in the textbox. I want to show after clicking the result of my number "5" into textbox. how to do that ?

              I have used the input example from above (dave biggs). this is a good example I can learn from

              my code part :

              Code:
              #COMPILE EXE
              #DIM ALL
              #INCLUDE "WIN32API.INC"
              
              %IDOK1 = 104
              %BTN_Test      = 102
              %LBL_LABEL1    = 101
              %TXT_TEXTBOX1  = 100
              %TXT_TEXTBOX2  = 103
              %result  = 104
              %number = 105
              '------------------
              
              CALLBACK FUNCTION DlgProc()
               LOCAL sTest AS STRING '
               LOCAL x AS LONG 'sTest$, x&
               'LOCAL tTest$
               LOCAL tTest AS STRING
               LOCAL p AS STRING
               LOCAL s AS STRING
               p = "hello: " +sTest+tTest
              
                SELECT CASE AS LONG CB.MSG
              
                  CASE %WM_COMMAND
                    SELECT CASE AS LONG CB.CTL
                      CASE %IDOK
                        IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                          CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX1 TO sTest
                          MSGBOX "sTest = "+stest, ,"Result"
                        END IF
              
                      IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                          CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX2 TO tTest
                          MSGBOX "my tTest = "+ttest, ,"second Result"
                        END IF
              
                      IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                          CONTROL GET TEXT CB.HNDL, %result TO s
                          MSGBOX "my result = " + p + "0. Result: "
                        END IF
              
              
                      CASE %TXT_TEXTBOX1
                        IF CB.CTLMSG = %EN_UPDATE THEN
                          CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX1 TO sTest
                          x = VERIFY (sTest , "-+,.1234567890")
                          IF x > 0 THEN
                            WinBeep 800, 50
                            sTest = REMOVE$(sTest, MID$(sTest, x, 1))
                            CONTROL SET TEXT CB.HNDL, %TXT_TEXTBOX1, sTest
                            CONTROL SEND CB.HNDL, %TXT_TEXTBOX1, %EM_SETSEL, x-1, x-1
                          END IF
                         END IF
                       
                                                          
                      CASE %TXT_TEXTBOX2
                        IF CB.CTLMSG = %EN_UPDATE THEN
                          CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX2 TO tTest
                          x = VERIFY (tTest , "-+,.01234567890")
                          IF x > 0 THEN
                            WinBeep 800, 50
                            tTest = REMOVE$(tTest, MID$(tTest, x, 1))
                            CONTROL SET TEXT CB.HNDL, %TXT_TEXTBOX2, tTest
                            CONTROL SEND CB.HNDL, %TXT_TEXTBOX2, %EM_SETSEL, x-1, x-1
                          END IF
                        END IF
                       
                         
                       CASE %result
                         MSGBOX "one plus one: " + p
                       
                       CASE %number
                         MSGBOX "shows: number 5"
                             
              
                    END SELECT
              
                  CASE %WM_SYSCOMMAND
                    IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN
                      DIALOG END CB.HNDL
                    END IF
              
                END SELECT
              END FUNCTION
              '------------------/DlgProc
              
              FUNCTION PBMAIN()
               LOCAL hDlg  AS DWORD
               DIALOG FONT "ARIAL",10,0,0
                DIALOG NEW 0, "Numeric Input Test", , , 240, 160, %WS_CAPTION OR %WS_SYSMENU, TO hDlg
                CONTROL ADD LABEL,  hDlg, %LBL_LABEL1, "-+,.1234567890 allowed", 50, 25, 120, 20
                CONTROL ADD BUTTON,  hDlg, %IDOK, "Test", 75, 60, 50, 15
                CONTROL ADD BUTTON,  hDlg, %result, "result", 25, 60, 50, 15
                CONTROL ADD BUTTON,  hDlg, %number, "<5>", 165, 60, 25, 25
                CONTROL ADD TEXTBOX, hDlg, %TXT_TEXTBOX1, "", 45, 90, 100, 13
                CONTROL ADD TEXTBOX, hDlg, %TXT_TEXTBOX2, "", 75, 120, 120, 13
              
                DIALOG SHOW MODAL hDlg, CALL DlgProc
              
              END FUNCTION
              '------------------/PbMain
              if anybody can help would be very nice. thank you !

              servus, frank

              Comment


              • #8
                There seems to be a couple things that you need to address. You've defined all your variables as local which means that every time your callback function is entered, the variables are created again so all numbers end up as zero and all strings are null. In the CASE %result section, the message box will only ever display "one plus one: hello: " because the other strings that get added to p are null. You set those variables when an EN_UPDATE occurs on your text boxes but then the program exits the callback function and those variables are erased. If you want to keep them around you need to make them STATIC. However, it is probably easier to just get the data from the text boxes when you need it rather than using static variables. Under CASE %result, do CONTROL GET TEXT to get the values currently in the text box and that to p before doing the MSGBOX.

                You also have three IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN lines under the CASE %IDOK. You will get three messages boxes every time you hit the OK button. It looks like you probably moved the CASE %result and CASE %number statements from in front of two of those IF blocks.

                I think you are asking how to put a number 5 into a text box when the user clicks the <5> button and that is done by sending a message to the text box. You need to add an ASCIIZ string variable (LOCAL zText AS ASCIIZ * 2) and under the CASE %number add this code:

                Code:
                zText = "5"
                CONTROL SEND CB.HNDL, %TEXT_TEXTBOX1, %EM_REPLACESEL, %TRUE, VARPTR(zText)
                If you don't have %TRUE defined it can be set to any value other than zero if you want undo to work or set to zero if you don't want undo to remove the 5.

                If you simply want to replace all the text in the text box then you can use CONTROL SET TEXT instead.
                Jeff Blakeney

                Comment


                • #9
                  fixed my number 5 example

                  dear jeff, hi all other guys.

                  although it took some month to grasp all new stuff with powerbasic here's very fast my fixed version of my personal "input with number 5" calculation example with textboxes and result / test button . Use numbers (5,10) and then the result or/and test button. for me this was a little step to understand more about ddt and powerbasic, not more

                  frank's numeric input test "5":

                  Code:
                  '--------------> modified example for numeric input with numbers by frank brübach, 19.mai.2010 :) > -----
                  '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  
                  #COMPILE EXE
                  #DIM ALL
                  #INCLUDE "WIN32API.INC"
                  
                  '---------------------
                  %IDOK1 = 100
                  %BTN_Test      = 101
                  %LBL_LABEL1    = 102
                  %LBL_LABEL2    = 103
                  %TXT_TEXTBOX1  = 104
                  %TXT_TEXTBOX2  = 105
                  %TXT_TEXTBOX3  = 106
                  %result        = 107
                  %number        = 108
                  %number2       = 109
                  '---------------------
                  
                  CALLBACK FUNCTION DlgProc()
                   LOCAL sTest AS STRING '
                   LOCAL vTest AS STRING
                   LOCAL x AS LONG, l AS LONG, b AS LONG, f AS LONG
                   LOCAL v AS STRING
                   LOCAL tTest AS STRING
                   LOCAL p AS STRING
                   LOCAL s AS STRING
                   LOCAL zText AS ASCIIZ * 2
                   LOCAL zText2 AS ASCIIZ * 4
                  
                    SELECT CASE AS LONG CB.MSG
                  
                      CASE %WM_COMMAND
                        SELECT CASE AS LONG CB.CTL
                          CASE %IDOK
                            IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                              CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX1 TO sTest
                              MSGBOX "sTest = "+stest, ,"Result"
                              l = VAL(stest)
                            END IF
                  
                          IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                              CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX2 TO tTest
                              MSGBOX "my tTest = "+ttest, ,"second Result"
                              b = VAL(stest)
                              f = l + b
                              MSGBOX "result of Addition is: " + STR$(f)
                            END IF
                  
                          IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                              CONTROL GET TEXT CB.HNDL, %result TO s
                            END IF
                  
                          CASE %TXT_TEXTBOX1
                            IF CB.CTLMSG = %EN_UPDATE THEN
                              CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX1 TO sTest
                              x = VERIFY (sTest , "-+,.1234567890")
                              IF x > 0 THEN
                                WinBeep 800, 50
                                sTest = REMOVE$(sTest, MID$(sTest, x, 1))
                                CONTROL SET TEXT CB.HNDL, %TXT_TEXTBOX1, sTest
                                CONTROL SEND CB.HNDL, %TXT_TEXTBOX1, %EM_SETSEL, x-1, x-1
                              END IF
                             END IF
                  
                          CASE %TXT_TEXTBOX2
                            IF CB.CTLMSG = %EN_UPDATE THEN
                              CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX2 TO tTest
                              x = VERIFY (tTest , "-+,.01234567890")
                              IF x > 0 THEN
                                WinBeep 800, 50
                                tTest = REMOVE$(tTest, MID$(tTest, x, 1))
                                CONTROL SET TEXT CB.HNDL, %TXT_TEXTBOX2, tTest
                                CONTROL SEND CB.HNDL, %TXT_TEXTBOX2, %EM_SETSEL, x-1, x-1
                              END IF
                            END IF
                  
                  '~~~~~~~ my new input :) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                           CASE %result
                            IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                              CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX1 TO sTest
                              CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX2 TO tTest
                              CONTROL GET TEXT CB.HNDL, %TXT_TEXTBOX3 TO vTest
                                           l = VAL(stest)
                                           b = VAL(ttest)
                                           f = l + b
                              CONTROL SET TEXT CB.HNDL, %TXT_TEXTBOX3, STR$(f)
                             MSGBOX "addition calculation 5 + 10 is: " + STR$(f)
                            END IF
                  '~~~~~~~~ my new input :) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  
                           CASE %number
                               zText = "5"
                               CONTROL SEND CB.HNDL, %TXT_TEXTBOX1, %EM_REPLACESEL, %TRUE,VARPTR(zText)
                               MSGBOX "shows: number 5"
                  
                           CASE %number2
                               zText2 = "10"
                               CONTROL SEND CB.HNDL, %TXT_TEXTBOX2, %EM_REPLACESEL, %TRUE,VARPTR(zText2)
                               MSGBOX "shows: number 10"
                        END SELECT
                  
                      CASE %WM_SYSCOMMAND
                        IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN
                          DIALOG END CB.HNDL
                        END IF
                  
                    END SELECT
                  END FUNCTION
                  '------------------/DlgProc -------------------------------------
                  
                  FUNCTION PBMAIN()
                   LOCAL hDlg  AS DWORD
                   DIALOG FONT "ARIAL",10,0,0
                    DIALOG NEW 0, "Frank's new Numeric Input Test", , , 240, 160, %WS_CAPTION OR %WS_SYSMENU, TO hDlg
                    CONTROL ADD LABEL,  hDlg, %LBL_LABEL1, "info: -+,.1234567890 allowed", 50, 25, 140, 20
                    CONTROL ADD LABEL,  hDlg, %LBL_LABEL2, "info2: push numbers, test and result button..", 50, 35, 160, 20
                    CONTROL ADD BUTTON,  hDlg, %IDOK, "test", 85, 60, 50, 15
                    CONTROL ADD BUTTON,  hDlg, %result, "result", 25, 60, 50, 15
                    CONTROL ADD BUTTON,  hDlg, %number, "<5>", 165, 60, 25, 25
                    CONTROL ADD BUTTON,  hDlg, %number2, "<10>", 195, 60, 25, 25
                    CONTROL ADD TEXTBOX, hDlg, %TXT_TEXTBOX1, "", 45, 90, 100, 13
                    CONTROL ADD TEXTBOX, hDlg, %TXT_TEXTBOX2, "", 75, 120, 120, 13
                    CONTROL ADD TEXTBOX, hDlg, %TXT_TEXTBOX3, "", 75, 140, 120, 13
                    
                    DIALOG SHOW MODAL hDlg, CALL DlgProc
                  
                  END FUNCTION
                  '------------------/PbMain end -------------------------------------
                  thanks, nice evening, frank
                  Attached Files

                  Comment

                  Working...
                  X