Clarion ABC Templates
Making the Transition to the ABC Templates So, the first question you'll probably ask yourself (after doing the tutorials in Getting Started and Learning Clarion to become familiar with the new features) is: "How can I leverage what I already know to get up to speed with Clarion ABC as fast as possible?" That's the overall question that this informal article answers. You'll probably be surprised at how much is still the same, how many resources are at your disposal, and how much more power Clarion has put in your hands with the change to OOP technology.
For those of you who don't write embedded code (or very little) and mostly let the templates handle all the coding, the answer to the question is: you're already leveraged, you already know it--just keep on working with Clarion as you always have. You may notice a reduction in the size of your EXEs and an increase in your applications' performance, but you don't really care how we achieve that, now do you! This article will be the most benefit to those of you who do a substantial amount of coding for yourselves in embed points. I've heard that OOP is really hard to learn. For example, a Procedural coding thought might be, "How do I make a window refresh when I want it to?" while the corresponding OOP thought should be, "I am a window. How do I refresh myself when necessary?" You need to change your perspective from an external (doing things to objects) to an internal (each object does its own thing) viewpoint. To help you learn the basic theoretical concepts of OOP, TopSpeed has two articles in the Programmer's Guide (this book is on your Clarion CD in the C5-PG.PDF file): "Easing into OOP" and "Object Oriented Programming." These two articles both explain the fundamental concepts of OOP theory and how they are implemented in the Clarion Language. The Language Reference documentation of the CLASS structure and its related components also covers this same ground in a more formal manner.
OOP, once you've learned the meaning behind all the "buzzwords," is actually pretty simple--it's just not very easy at first. The OOP concepts, while simple, are fundamentally different from Procedural coding concepts. That very difference is what makes OOP seem difficult at first, but it is also that basic difference that gives OOP its power. The result is worth the effort required to attain it. I've heard that the ABC generated code looks very different. Yes, For all the various types of procedures, the ABC template generated code gives you the same functionality the 2.003 templates gave you (often more, and with more efficient execution). You can easily see this just by looking at the similarity in the template prompts in the Application Generator. This means that you can simply continue to choose the functionality your PROCEDURE should perform from the ABC Template prompts just as you did before--without changing the familiar way of working you're already accustomed to!
I've heard that writing embed code is very different in ABC. We've added a new feature to the Clarion language specifically to enable you to keep coding your event handling embeds the same way: new scoping rules. In Clarion, PROCEDURE local variables and ROUTINEs are visible and available for use anywhere within that PROCEDURE and any overridden method of a CLASS declared within that PROCEDURE. This means you can still use local variables and call your ROUTINEs in your embed code exactly as you always have, despite the fact that they are actually in separate procedures. There's no difference here between Clarion 2.003 and Clarion 4 or 5.
So what are the new considerations to bear in mind? Here's the biggest one: Realize that your embed code is now being placed in a completely separate procedure--an ABC "method" (procedure) specifically overridden by the templates for the individual PROCEDURE you are creating.
There are a couple of implications to this that might not be obvious:
For example, in Clarion 2.003 if you assigned a value to X# in EVENT:Accepted for a BUTTON control, then tested the value of X# in EVENT:CloseWindow to see if the BUTTON was pressed, you would be referencing the same X# implicit variable in both statements and your code would work as expected. However, in Clarion ABC generated code, EVENT:Accepted is handled by the ThisWindow.TakeAccepted method and EVENT:CloseWindow is handled by the ThisWindow.TakeWindowEvent method. Since these methods are two separate procedures, you would end up with two different X# implicit variables (one in each method), and your code would definitely NOT work because the value of X# in ThisWindow.TakeWindowEvent would always be zero.
Therefore, where you once might have used implicit variables across multiple embed points, you should now explicitly declare local variables. The hidden benefit to this is that by explicitly declaring local variables you are letting the compiler catch any spelling mistakes you might have made in your code (a common problem when using implicit variables).
For example, in Clarion 2.003 if you placed an OMIT in the "EVENT:Accepted -- Before Generated Code" embed point for a control and its terminator in the "EVENT:Accepted After Generated Code" embed point for the same control, you would simply be omitting template generated code for that one control. However, in Clarion ABC generated code, you would be omitting all the code (generated and embed code) for a number of controls along with the call to the PARENT. TakeAccepted method to handle all the standard EVENT:Accepted functionality.
Therefore, when you want to override any standard Template functionality in ABC, just override the appropriate method, issuing a RETURN before the call to the PARENT method, and do not use OMIT. The hidden benefit here is that your ABC generated OOP code is much more flexible and efficient, and you'll probably have less need to override standard template generated functionality.
What resources do I have to help me learn to convert my code to ABC ? Clarion 5 has an application converter to convert your 2.003 applications to use the Clarion ABC Templates. This converter has two modes: Automatic and Manual. When you operate the converter in Manual mode you have an interactive teaching tool to help you learn all the new ABC ways of coding and it operates on the code that you wrote! In addition to the Application Converter, the "Late Breaking News" portion of on-line Help has a section called "Converting CW 2.x Applications to CLARION ABC." This topic contains a table listing a number of common Clarion 2.003 coding practices and their ABC equivalents. What resources do I have to help me learn to convert my code to ABC ? Clarion 5 has an application converter to convert your 2.003 applications to use the Clarion ABC Templates. This converter has two modes: Automatic and Manual. When you operate the converter in Manual mode you have an interactive teaching tool to help you learn all the new ABC ways of coding and it operates on the code that you wrote! In addition to the Application Converter, the "Late Breaking News" portion of on-line Help has a section called "Converting CW 2.x Applications to CLARION ABC." This topic contains a table listing a number of common Clarion 2.003 coding practices and their ABC equivalents. What's with these new Embed Priorities ? The ABC Templates contain fewer named embed points than the 2.003 templates did, so at first it may look like we've removed some capability. However, the new Embed Priorities allow each named embed point up to 10,000 logical embed points within the generated code. This can be pretty confusing until you use the Embeditor to edit your embedded source. Once you can see exactly where the embed point priorities lie in context, you will be able to clearly see where you need to place your code. The priority numbers themselves do not matter--what matters is where the embed point priority lies within the surrounding generated code, and that's why we gave you the Embeditor.
Working this way, you'll find that you're still being productive while you are learning the new ABC embeds, and learning the new ABC Library methods at the same time!
Using this process, you will quickly learn the ABC equivalents for your more commonly used embed points, such as these:
Yeah, but I heard that writing File Handling code is very different in ABC. Here's a table of the ABC methods to use in place of the common Clarion language statements:
Another common file handling situation is the simple file processing LOOP. In 2.003, you would write code like this: SET(key,key) LOOP NEXT(File) IF ERRORCODE() THEN BREAK. !Break at end of file !Check range limits here !Process the record here END And here is the equivalent ABC code: SaveState = Access:File.SaveFile() SET(key,key) LOOP UNTIL Access:File.Next() !Check range limits here !Process the record here END Access:File.RestoreFile(SaveState) !Undo the "bookmark" (SaveState must be a USHORT) As you can see, this is all pretty straightforward--only a couple of minor changes to learn. Another common code construct is getting a record from a file. In 2.003, you might write code like this: IF File::used = 0 CheckOpen(File) END File::used += 1 CLEAR(FIL:record) Fil:Code = 123 GET(File,FIL:CodeKey) IF ERRORCODE() THEN CLEAR(FIL:Record). File::Used -= 1 IF File::used = 0 CLOSE(file) END And here is the equivalent ABC code: Relate:File.Open() !This handles all error conditions CLEAR(FIL:record) FIL:Code = 123 Access:File.Fetch(FIL:CodeKey) !Fetch clears the record on errors Relate:File.Close() And of course, the file Open and Close method calls can be generated for you if you just add the file to the procedure's File Schematic. The ABC Library is smart enough to only open a file if it really needs to, making your program more efficient. Using Clarion's ABC Library methods you write less code to accomplish the same (or more) functionality. How do I learn about all these new ABC methods ? Method names have specific meaning in the ABC Library to indicate the type of functionality each method provides. These names are consistently used by all the classes:
Knowing these consistent naming conventions will make it much easier to understand what an object's methods do, whether you've read the Application Handbook about that specific type of object or not! In addition to the Application Handbook, Clarion also has a Class Viewer to show you the ABC Library properties and methods in a tree view. On any Classes tab, just press the button labeled "Application Builder Class Viewer" to view the ABC Library structure. The Class Viewer graphically shows you how the ABC Library classes are derived--which class inherits properties and methods from which Parent class.
The ABC Template set contains two Code Templates, which will help you learn more about using the ABC Library: CallABCMethod and SetABCProperty. These were specifically created to "walk you through" writing ABC Library code in any executable code embed point. These two Code Templates will write your method calls and object property assignments for you! So how do I figure out which ABC method to use ? Here is a standard process you can use to accomplish any task using the ABC Templates and Library: 1) Determine if the ABC Templates can perform the task. If the ABC Templates will perform the task for you, you're done. If they won't, continue on to Step 2. 2) Identify the ABC Object (and its CLASS) that manages the behavior you need to change.
Once you've identified the candidate objects and CLASSes, continue on to Step 3. 3) Determine if the object/CLASS has a property that you can set to accomplish the task. If setting a property performs the task for you, you're done. If not, continue on to Step 4. 4) Determine if a method of the object/CLASS already does the task. If calling an existing method performs the task for you, you're done. If no method already does the task, continue on to Step 5. 5) Determine which method you can modify to accomplish the task, then override it. If the modified/overridden method is VIRTUAL, you're done. You do not need to call VIRTUAL methods yourself since the other methods of the CLASS call them for you as part of their normal operations (as in the above example). If the method is not VIRTUAL or you need to call it outside the normal sequence of events, then you just use a similar process to determine where to call the method: find the method that manages the behavior and embed your call in an embed point of that method. Following these steps, you can accomplish any programming task in the most efficient manner, by always working at the highest level of abstraction possible in Clarion--that is, do as little "work" yourself as possible to accomplish the greatest effect. OK, the theory looks good, but how about some real examples ? Sure. Here're a few: Task: I want a Browse list to display in descending key order. 1) The Browsebox Control Template's documentation in the Application Handbook tells you that it supports extra sort fields in addition to key fields. If you do not specify a key in the File Schematic, the Browse will sort just by the fields you name as Additional Sort Fields. Therefore, just list the key fields in Additional Sort Fields with a leading minus sign and a comma between each field (such as: -CUS:LastName,-CUS:FirstName). You're done at Step One! Task: I want to print a report, skipping the print preview if the user has elected not to preview. 2) Opening the Embeditor for the report, you see two objects that appear to be likely candidates to control this behavior: Previewer/PrintPreviewClass and ThisWindow/ReportManager. PrintPreviewClass is pretty obvious. ReportManager is also likely because you can see it has a method called AskPreview (so it might have something to do with the preview functionality). You go on to Step Three. 3) The Application Handbook documents all the public properties for each class. Checking the properties for PrintPreviewClass, you see that there is no property that appears to control whether the print preview executes or not. However, when you check the properties for ReportManager you see a SkipPreview property that does exactly what you need. Therefore, to conditionally suppress print preview based on a user setting in a control file you can simply: IF NOT CTL:PrintPreview THEN ThisWindow.SkipPreview = TRUE. Task: I want to let the end-user dynamically filter a browse list at runtime. 2) In the Embeditor, you see that the only likely candidate object/CLASS is BRW1/BrowseClass, because it controls the browse list, then go on to Step Three. 3) None of the BrowseClass properties listed in the Application Handbook appear to help for this task. BrowseClass is derived from the ViewManager, which means it inherits all the ViewManager properties and methods, so you check the ViewManager properties also. None of them apply either, so you go on to Step Four. 4) The Application Handbook documents the BrowseClass methods in addition to its properties. You don't immediately see any that might apply, so you check the inherited ViewManager methods, also. That's where you find the ViewManager's SetFilter method, which appears to be exactly what you need for this task. Therefore, you see that to change the browse filter you can execute code like this: if NewFilter BRW1.SetFilter('CUS:LastName[1] = ''' & NewFilter & '''') else BRW1.SetFilter('') end ThisWindow.Reset(1) Task: I want the user to be able to copy an existing record when adding a new record.
CopyFlag BYTE IF CopyFlag = TRUE !Check the flag's value SuppressClear = TRUE !Set the PrimeRecord parameter value CopyFlag = FALSE !Reset the flag END You're almost done, but not quite. In order for the user to signal when they want to copy a record, you need to add a "Copy" BUTTON control to the Browse window. Then, in EVENT:Accepted for your ?Copy BUTTON, you place the following code to set the CopyFlag and initiate adding the copied record: CopyFlag = TRUE !Set the flag and then trigger POST(EVENT:Accepted,?Insert) ! the Insert button's code to execute as normal When the user presses your Copy button, CopyFlag is set to TRUE and then the normal Insert button code sequence occurs, but your overridden BRW1.PrimeRecord method will execute instead of the ABC Library's standard method. You're done at Step Five! Task: I want to add my new "Copy" button to the Browse's popup menu.
BRW1.Popup.AddItemMimic('Copy',?Copy) !Call a PopupClass method through the ! Browse object's PopupClass reference ! property So where does this one line of code need to go? Since the Popup property must already exist, it must come sometime after the BRW1 object has been initialized. And, since you just want to add this to the popup menu and not dynamically enable/disable it, this code needs to happen on the way into the procedure, before the user can do anything on the window. In the Embeditor, you can see that the BRW1.Init method is called in the ThisWindow.Init method, and you already know that ThisWindow.Init is always the first method called in any procedure with a window. Therefore, the best embed point to place this one line of code would be one near the end of the ThisWindow.Init method. You're done at Step Four! Task: I want to call a Form directly from the menu (without a Browse) to add records. This task actually implies the need to do three things:
While exploring in the Embeditor you notice that the very beginning of ThisWindow.Init is where the value of the GlobalRequest variable (which tells the Form procedure what file action to perform) is obtained. You know you need to deal with this issue, so in the very first embed point available in ThisWindow.Init (immediately following the CODE statement) you add: GlobalRequest = InsertRecord !Set Form procedure to insert records mode Having dealt with the first issue, you go on to Step Three.
Access:FileName.PrimeAutoInc() !Auto-increment key fields Access:FileName.PrimeRecord(TRUE) !Init other fields (suppressing clear) Now, when you call this Form procedure directly from a menu (without an intermediate Browse) it will automatically be in Insert mode and will correctly handle auto-incrementing keys and setting up all the initial values you declared in the Data Dictionary. You're done at Step Five! Task: I want to allow the end user to pause/resume report generation.
Task: I want total fields on one tab and the BrowseBox which they total on another.
BRW1.ActiveInvisible = TRUE !Set the browse to always active So where does this one line of code need to go? Since the ActiveInvisible property must already exist, it must come sometime after the BRW1 object has been initialized. And, this property needs to be set on the way into the procedure, before the user can see the window so the totals will be calculated and displayed correctly. In the Embeditor, you can see that the BRW1.Init method is called in the ThisWindow.Init method, and you already know that ThisWindow.Init is always the first method called in any procedure with a window. Therefore, the best embed point to place this one line of code would be near the end of the ThisWindow.Init method. You're done at Step Three!
As you can see, this 5-step process leads you to the earliest possible solution to any programming task. Are there any non-TopSpeed Clarion OOP Learning Resources?
Between these external resources, the information presented in this article, and all the Clarion documentation (both printed and electronic), you have a tremendous amount of information to help you learn how to use Clarion's ABC Templates and Library. Keep studying and working with it and you will get to that essential "Ah Ha! That's what ABC/OOP is all about" bolt of enlightenment--probably sooner than you might think. When you do, watch out! You'll not only own a copy of this Clarion "Formula 1 class" development tool, but you'll be driving it like a World-Class competitor--at TopSpeed! |


