C10: Editing a Queue on a Hand-coded form

I’m a newbie trying to learn Clarion. I started writing a hand-coded program to learn Clarion code and understand the basics of how a window works. So far I have got everything to work using buttons. Here is my form

Capture

The Search and Replace listbox gets its values from a Queue that is loaded from an INI file.

clsSearchReplaceQ   QUEUE                                   ! Queue structure for search and replace
qSearchString           CSTRING(1024)                       ! Search for this string
qReplaceString          CSTRING(1024)                       ! Replace it with this string
qNo                     SHORT
                    END

qqSearchReplace     clsSearchReplaceQ                       ! Queue containing search and replace strings

The window code includes the following:

                        LIST,AT(17,50,240,60),VSCROLL,FROM(qqSearchReplace),IMM,MSG('Search and Replace data'),|
                            FORMAT('100L(2)|M~Search~C(2)@s40@102L(2)|M~Replace~C(2)@s38@40L(2)|M~No~L(2)'),USE(?qqSearchReplace)
                        ENTRY(@s40),AT(17,115,99,10),USE(qqSearchReplace.qSearchString)
                        ENTRY(@s40),AT(119,115,98,10),USE(qqSearchReplace.qReplaceString)
                        SPIN(@N4),AT(221,115,36,10),USE(qqSearchReplace.qNo),MSG('Use this to edit a particular entry')

What puzzles me is how to know when the user clicks on the LIST, or the ENTRY or SPIN controls are changed.

Fixer.clw (17.8 KB)

I have included the entire fixer.clw code file if the details in this question aren’t sufficient. There is probably code missing from the ACCEPT loop, but I’m really out of my depth at this point.

Any pointers would be most helpful. Thanks in advance

Have you read “ACCEPT” topic and related topics? In short, the snippet is:

ACCEPT
  CASE ACCEPTED()
  OF ?control
    DO Control:Accepted::Routine
  END

  CASE EVENT()
    OF EVENT:NewSelection
    CASE FIELD()
    OF ?list
      DO List:NewSelection:Routine
    END
  END

END
1 Like

What puzzles me is how to know when the user clicks on the LIST, or the ENTRY or SPIN controls are changed.

There are many EVENTS that fire.
May I suggest using a Debuger class, with dbg.PrintEvent(‘’) to learn what’s firing when
I also recommend using DebugViewPP as the OutputDebugString (ODS) viewer.

code review:

Line 8: is commented, so the OMIT doesn’t occur, that said, everything inside of the omit is commented, so just delete the omit and it’s terminator

Line 83: is missing ,TYPE - so it’s an instance too

Lines 99-102 are valid but are in a different style from the rest of the map, i’ts probably better to pick on style and stick with it.

Lines 104-106 : Sleep is never used. and when it was, did you need to declare it ?

Line 109: for clarity prefix the typed queue argument with the implied *
iow: , claNameQ pDirQ) becomes , *claNameQ pDirQ)

Lines 176-180 could be removed by adding ,STD(STD:Close) to line 135

I would code that as Your ACCEPT loop as

ACCEPT
  ! CASE EVENT() 
  !   OF EVENT:OpenWindow 
  ! END 
    CASE ACCEPTED() 
      OF ?FolderButton     ; DO OpenFolderButton
      OF ?EditButton       ; OpenConfigFile()                              ! Allow the user to inspect Fixer.ini
      OF ?OpenFolderButton ; RUN('explorer.exe "' & strBrowseBase & '"',1) ! Show the folder
      OF ?OkButton         ; ProcessAllFiles()                             ! The bulk of the work happens here
      OF ?CloseButton      ; POST(EVENT:CloseWindow)                       ! All done
    END 
END 

OpenFolderButton ROUTINE            
  FILEDIALOG('Choose Project Folder',strBrowseBase,,FILE:Directory+FILE:LongName+FILE:KeepDir)
  IF ~strBrowseBase                    
      strBrowseBase = PATH() & '\'                   
  END
  strBrowseBase = Fix_Path(strBrowseBase)
  SaveConfigFile()
  ?OpenFolderButton{PROP:Text} = strBrowseBase

I created the OpenFolderButton routine, as it was more than just a line or two
, which is distracting from the rest of the accept loop handling.

LIne 193: I’d code I LONG as I LONG,AUTO - bit twidler, just skips the initialation of I = 0

Line 197: I’m not sure that the Display() is needed here

Line 233: I rarely (if ever) use STOP, but possibly is makes sense here.

Lines 239-240 : you have you search/replace hard coded, but you have a queue elsewhere for that
you will eventually want to decide if you’re going to pass the queue to ProcessThisFile, or just use side-effect.

Line 251: has a ,1 document the ,1 or create an equate to make it readable

LInes 258-260: more ,auto

Line 276: n += 1

Line 297: again hard coded,2 vs. your queue

Line 309: remove the ,PRE(ffq) and use dot notations (ex: ffq:name becomes ffq.name)

LInes 292 - 301 - I prefer to vertically align the arguments - I believe it much easier to read.

Line 370: FILE:MaxFileName should be FILE:MaxFilePath

Line 371: STRING(64) is that a documented maximum extension length ?

Line 375: LEN(loc:fileName) is aways FILE:MaxFileName, if you meant that, then consider using SIZE(loc:fileName) which can be evaluated at compile time vs. runtime. My guess is you mean LEN(CLIP( lco:FileName)). You might also want to use a CSTRING

1 Like

Wow! Thank you so much for the complete code review as well as everything else. I am blown away at the generosity of this community.

I still don’t fully understand the difference between STRING and CSTRING. I have never programmed in C, so maybe the subtlety is lost on me. Also, Visual Basic just has “String” and I’m not sure if it uses a null terminator or not.

Hi Don,

A CSTRING ends with a zero byte - so if you declare a CSTRING(20) it can hold up to 19 characters.
Not 20 as there must always be the zero terminator.
CSTRINGs are not padded with spaces by the runtime library.

Clarion STRINGs are different - they carry extra length information outside of the variable itself - so a STRING(20) can hold 20 characters.
A STRING will be auto padded with space characters (ie ASCII 32)
(hence the need for the CLIP command)

Because Clarion STRINGs hold length information externally they don’t need a terminator and can hold any byte value including zero.
That means they can hold binary data (just like BYTE arrays in other languages)

‘Visual Basic’ - well that depends upon what exactly you mean by Visual Basic - ‘Classic Visual Basic’ or VB.NET

1 Like

Thanks for clarifying, especially the bit about CLIP()

I actually meant the VBA you find in Microsoft Office, since I have been doing development in Microsoft Access ever since Access97 was released. AFAIK both VB6 and VB.NET use the same type of strings, but I can’t be sure about VB.NET. I just assumed it to be the case.

Welkom bij VB Computer Shop Online! :rofl:

I have completed the app. Please check it out at