CTRL + F search TEXT controls in Clarion application at runtime

Just want to know if we have ability to search text on a Clarion Window. because if we have multiple textbox controls on a window and we want to search specific control, then instead of manually checking that, Can we search for it?
Thanks.

I am not completely sure I understand you but if you click on the ellipsis (…) button next to the window button you can then see the “code view” of the window and you can certainly do control-F there to search for a given control.

hth

image

edit: or are you talking about at runtime?

Thanks for replying but I am not talking at code level search. I am asking about runtime search. once the exe is generated and we have many controls on some window, but if want to search for some label in that window. we generally do CTRL + F to find text on web browsers to search for a text.

There is no inbuilt feature for this and it’s not something I have done, however I guess it would be possible by looping over the window controls and performing the search on values of properties for that field and perform your search and then do what you like

A very simple example to get you going

  PROGRAM

  MAP
  END

Window              WINDOW('Caption'),AT(,,395,224),GRAY,FONT('Segoe UI',9)
                      BUTTON('&OK'),AT(291,201,41,14),USE(?OkButton),DEFAULT
                      BUTTON('Search'),AT(2,201),USE(?btnSearch)
                      PROMPT('Prompt1'),AT(39,52),USE(?PROMPT1)
                      PROMPT('Prompt2'),AT(166,52),USE(?PROMPT2)
                    END
feq Signed

  CODE
  OPEN(Window)
  ACCEPT
    Case ACCEPTED()
    of ?OkButton
      post(EVENT:CloseWindow)
    of ?btnSearch
      Do Search
    END
    
  END
  CLOSE(Window)
  
Search              ROUTINE
  
  feq     = 0
  LOOP 
    feq = 0{Prop:NextField, feq}
    if feq = 0
      break
    end
    CASE feq{PROP:Type} 
    OF CREATE:prompt
      !value of prop:text will be the prompts text
      if feq{prop:text} = 'Prompt1'
        feq{PROP:Color} = COLOR:Red
      END
  END

I hope that helps.

Mark

1 Like

You can use a LOOP with Prop:NextField to scan all controls and use PROP:Type to find TEXT or ENTRY. The CONTENTS(Feq) function or PROP:Value or PROP:ScreenText to get the value without knowing the USE() variable. With a TEXT you can use PROP:LineCount and PROP:Line,# to scan individual line’s text.

Feq LONG
  CODE
    Feq=0
    LOOP
        FEQ=0{PROP:NextField,FEQ}
        IF ~FEQ THEN BREAK.
        CASE FEQ{PROP:Type}
        OF CREATE:Text
           IF INSTRING('FIND THIS',UPPER(CONTENTS(FEQ)),1) THEN
              SELECT(FEQ)
              Message('The control containing "FIND THIS" has been selected','Find Text')
              BREAK 
           END 
        END
    END
3 Likes

I’m assuming you’re thinking of behavior in a browser
where you can search for any text, which is to say content of entry controls, but also for prompts.

NOTE: in this code, I’m starting at the next control from the one that currently has focus, and wrapping around if necessary. Much like a CTRL+F in an editor.

Notice that while this searches content of controls
It also searches the controls themselves
like the text of a prompt, or a button etc.

How about something like this.

SelectMatchingControl PROCEDURE(STRING xSearchFor)

Controls QUEUE
FEQ        SIGNED
         END 

OrigPtr  
QPtr     LONG 
  CODE
  DO FillControls

  Controls.FEQ = FOCUS()
  GET( Controls, Controls.FEQ )
  QPtr = POINTER( Controls ) + 1

  LOOP 
    IF QPtr > RECORDS( Controls )
       QPtr = 1
    END 

    GET( Controls, QPtr )
    IF   Controls.FEQ = FOCUS() 
       BREAK ! did not find a match
    END 

    IF    INSTRING( SearchFor, Controls.FEQ{PROP:ScreenText}, 1, 1) > 0 |
       OR INSTRING( SearchFor, Controls.FEQ{PROP:Text      }, 1, 1) > 0 |
    THEN 
       SELECT( Controls.FEQ )
       BREAK 
    END 
  END 




FillControls ROUTINE 
  DATA 
CurrFEQ SIGNED(0)  
  CODE 
  LOOP 
    CurrFEQ=0{PROP:NextField,CurrFEQ}
    IF CurrFEQ = 0
       BREAK 

    ELSIF CurrFEQ > 0  ! ignore toolbar and menu controls
       Controls.FEQ = CurrFEQ 
       ADD( Controls )
    END 
  END

When I woke up this morning, I realized there was no need for a queue, the code could be written in one pass - duh.

SelectMatchingControl PROCEDURE(STRING xSearchFor)
  
CurrFEQ SIGNED,AUTO
Found   LONG,AUTO 
  CODE
  CurrFEQ = FOCUS()

  LOOP 
           CurrFEQ = 0{PROP:NextField,CurrFEQ}

    IF     CurrFEQ = FOCUS()  THEN BREAK  ! no match as we have wrapped around
    ELSIF  CurrFEQ <= 0       THEN CYCLE  ! < 0 : ignore toolbar, menu controls
                                          ! = 0 : ignore current window as well
    END 

       Found = INSTRING( xSearchFor, CurrFEQ{PROP:ScreenText}, 1, 1) 
    IF Found 
       SELECT( CurrFEQ, Found, Found + LEN(xSearchFor)  - 1 )
       BREAK 
    END 

    IF INSTRING( xSearchFor, CurrFEQ{PROP:Text}, 1, 1) 
       ! could limit this to certain PROP:TYPE
       ! but it would be nice to search text of all sorts of controls
       ! prompts, buttons, checkboxes & radio options etc.
       ! TODO: confirm that prop:text is the correct property for each of those

       SELECT( CurrFEQ )
       BREAK 
    END 
  END

NOTE: due to an issue @jslarve pointed out. I have changed the code to check for CurrFEQ = Focus() prior to chcking CurrFEQ <= 0

1 Like

Would you not want to BREAK if CurrFEQ = 0?

OIC, you’re wrapping.

What if FOCUS() = 0?

or less than zero, which is possible.

Jeff - In response to your observation
I have altered the code above
checking CurrFEQ = FOCUS ()
prior to CurrFEQ <= 0

PROMPT and STRING controls contain text (Prop:ScreenText and Prop:Text) but cannot be Select() and given focus. You could create a Box around to highlight them, or color them.

An an ENTRY the PROP:Text returns the Picture. The earlier search of PROP:ScreenText would scan the CONTENTS() or Prop:Value.

One tip is PROP:Value on PROMPT, BUTTON, OPTION, RADIO, CHECK, TAB, GROUP controls returns the same as PROP:ScreenText and Prop:Text, but without the “&” prefixing the Alt+Key. E.g.
?Cus:Name{PROP:Text}='&Name:' ! has &
?Cus:Name{PROP:Value}='Name:' ! without &

That certainly makes sense.
But IF I write SELECT(?SomePrompt),
won’t the next selectable control be selected, so it would still function as desired.

Another example of scanning controls. I find the Drop LIST hard to see typically being a White Box below the ENTRY control

This procedure finds all the Drop Lists on the Window and does this:

  • Colors the LIST Yellow like a Tooltip (Info Text) so they stand out
  • Increases the Line Height by 1 so more space between
  • Adds a Format with an L(2) Margin so 2 on the Left allows more margin between line and text
DropListPretty       PROCEDURE()
Fld     LONG,AUTO
LstFEQ  LONG,AUTO
  CODE
  Fld=0
  LOOP
    Fld=0{PROP:NextField,Fld}
    IF Fld=0 THEN BREAK.
    CASE Fld{PROP:Type}
    OF   CREATE:List
    OROF CREATE:Combo
   
       LstFEQ = Fld{PROP:ListFEQ}
       IF LstFEQ AND Fld{PROP:Drop}>0 THEN   !Only if Drop List
          LstFEQ{PROP:LineHeight}=1 + LstFEQ{PROP:LineHeight}    ! +1 more line space easier to read
          IF LstFEQ{PROP:Background}=COLOR:None THEN
             LstFEQ{PROP:Background}=COLOR:InfoBackground        !Yellow like tip
             LstFEQ{PROP:FontColor} =COLOR:InfoText              !font color like tip should be black
          END
          IF ~LstFEQ{PROP:FORMAT} THEN
              LstFEQ{PROP:FORMAT}='999L(2)@s255@'    !Margin of 2 else tight to line
          END
       END
    END
  END
  RETURN

1 Like