User Tools

Site Tools


making_the_transition_to_the_abc_templates.htm
Navigation:  How To's and Troubleshooting > How to… >====== Making the Transition to the ABC Templates ====== Previous pageReturn to chapter overviewNext page

NewC7.jpg

This FAQ documents development issues that are necessary for Clarion developers familiar with the procedure based Clarion templates who are considering the use of the Clarion ABC template chain.

You now have a vastly improved development tool at your disposal: Clarion, with its Application Builder Class (ABC) Templates and ABC Library. These tools write Object-Oriented (OOP) code for you, using the same template interface that you've grown accustomed to in earlier versions of the Clarion templates. This article provides answers to the most common questions about making the move to ABC/OOP.

So, the first question you'll probably ask yourself (after doing the lessons 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.

Like all generalities, this one has a grain of truth at its core. The fact is that, like all new concepts, it will certainly take some work to really “get” the OOP concepts firmly in place, but it really is not as difficult as it's commonly made out to be. It's said, “OOP only takes one minute to understand, but that one minute might not come for a couple of weeks.” It just takes a bit of study and a bit of working with it for you to get to the essential “Ah Ha! That's what OOP is all about” bolt of enlightenment.

The biggest difference between writing OOP versus Procedural code is in how you think about the code you write. As one experienced developer is fond of pointing out, in Procedural code you normally think, “How can I perform this task on this thing?” while with OOP code the thought process should be, “I am a thing. How should I perform this task?” These are very different questions representing very different viewpoints.

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, SoftVelocity has two articles in the Programmer's Guide (this book is on your Clarion CD in the C6PG.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, that's certainly true. The ABC templates only generate a single line of code (GlobalResponse = ThisWindow.Run()) into a generated PROCEDURE. All the code to accomplish the functionality of the PROCEDURE is contained either in the ABC Library, or in overridden methods of the ABC Library. These overridden methods are specifically generated for you by the ABC Templates to implement the functionality you request when you fill in the template prompts.

For all the various types of procedures, the ABC template generated code gives you the same functionality the Clarion procedural templates give 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.

This is both true and untrue. True, there are some new things to consider when you write your embed code, but quite often you can write your code just as you did before. In other words, where in the Clarion templates you might write a couple of lines of code into the EVENT:Accepted embed point of a control to set up some variables and call a procedure, or to enable/disable other controls on the same window, or to check the value entered by the user, or ' In ABC you do exactly the same thing–no change at all. For the most part, you can write your event handling embed code in ABC just as you did with the Clarion templates.

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.

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:

1.Any implicit variables you use are in scope only within that one method. Using the “same” implicit variable in another embed (in another method) now creates a separate instance of that implicit variable unique to that method.

For example, in the Clarion templates 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).

2.In the Clarion templates you might have placed an OMIT statement in one embed and its terminator in another embed to “work around” template generated functionality that you wanted to override. This is very dangerous to do in the ABC templates, because you'll probably OMIT much more code than you intended to, breaking your application in ways that may not be obvious.

For example, in the Clarion templates 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 methontentsod, 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 gives you a tool to edit your embedded source: the Embeditor (in the Application Generator, RIGHT-CLICK and select Source from the popup menu). The Embeditor was specifically designed to show you all the possible embed points in your PROCEDURE within the context of template generated code. It is important to note here that the Embeditor does not show all the code that WILL be generated for your procedure, but all the code that COULD BE generated. Seeing your code in context makes it much easier to understand the new scoping issues.

What's with these new Embed Priorities?

The ABC Templates contain fewer named embed points than the Clarion templates do, 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.

The ABC Templates have a new naming convention for the embed points which uses the names of the ABC Library method you're overriding when you place code into the embed point. These may at first seem unfamiliar since they are different than the names used in the Clarion templates. The easy way to learn the new embed points and their priorities in relation to the Clarion template embed points is to:

·Choose Tools C6H0013.jpg Application Options and from the Action for Legacy Embeds droplist, select Show all and generate all (you can do this while still in your app).

·Use the Embeds dialog as you always have to write your embedded source.

·Reset the Action for Legacy Embeds to Show filled and generate all (to highlight the difference between the embed points by labeling the Legacy embeds as such in the Embeditor).

·Use the Embeditor to edit your source and move your code from the Legacy embeds to the appropriate new embed point (immediately above or below the Legacy embed).

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:

Clarion template embed Clarion Win32 ABC equivalent
Initialize the procedure WindowManager Method Executable Code Section,
Init() - Priority: ~6500
After Opening the Window WindowManager Method Executable Code Section,
Init() - Priority: ~8030
Beginning of procedure, After Opening Files WindowManager Method Executable Code Section,
Init() - Priority: ~7600
Preparing to Process the Window WindowManager Method Executable Code Section,
Ask() - Priority: FIRST
Before Closing the Window WindowManager Method Executable Code Section,
Kill() - Priority: ~7300
End of procedure, Before Closing Files WindowManager Method Executable Code Section,
Kill() - Priority: ~5600
Format an element of the Browse Queue Browser Method Executable Code Section,
SetQueueRecord() - Priority: ~5500
Before Printing detail section Process Manager Method Executable Code Section,
TakeRecord() - Priority: FIRST
Activity for each record (Process template) Process Manager Method Executable Code Section,
TakeRecord() - Priority: LAST
Browser, Double Click Handler Browser Method Executable Code Section,
TakeKey() - Priority: FIRST
IF RECORDS(SELF.ListQueue) AND KEYCODE() = MouseLeft2!Place your code here (you must write the !surrounding IF structure, too)END
Browser, no records found Browser Method Executable Code Section,
ResetQueue(BYTE ResetMode) - Priority: LAST
IF NOT RECORDS(SELF.ListQueue)!Place your code here (you must write the !surrounding IF structure, too)END

Yeah, but I heard that writing File Handling code is very different in ABC.

OK, here's where there really is a fundamental difference. Since the ABC Templates generate their code using the ABC Library, you'll want to write your embedded code to use the ABC Library methods so that there's no possibility that your embedded code will “mess up” anything the template generated code is counting on. Naturally, this is going to be easier to do than you might think.

Here's a table of the ABC methods to use in place of the common Clarion language statements:

Clarion template code Clarion Win32 ABC Library equivalent
OPEN(File) Relate:File.Open() !This ensures all related files are opened,
SHARE(File) Relate:File.Open() !as well as the named file, so Referential
CheckOpen(File) Relate:File.Open() !Integrity constraints can be enforced.
CLOSE(File) Relate:File.Close() !This ensures all related files are closed.
ADD(File) Access:File.Insert() !These ABC methods all do error handling
IF ERRORCODE THEN STOP(ERROR()). !so the error check is unnecessary. Insert!also handles autoinc and data validation.
PUT(File) Relate:File.Update() !The Relate: object !enforces RI constraints
IF ERRORCODE THEN STOP(ERROR()). !in Update() and Delete() methods.
DELETE(File) Relate:File.Delete(0) !Parameter suppresses !the default confirm !dialog when 0.
IF ERRORCODE THEN STOP(ERROR()).

Another common file handling situation is the simple file processing LOOP. In the Clarion template embeds, 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() !Tell ABC to “bookmark” where it's at (just in case)

SET(key,key)              !Note there's no change here

LOOP

 IF Access:File.Next()<;>Level:Benign THEN BREAK.

 !Breaks when it tries to read past end of file

 !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 the Clarion template embeds, 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 Data / Tables Pad. 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?

The easiest way to become familiar with the ABC Library overall is to read the ABC Library Reference –specifically those sections which present an Overview of each Class. It's not necessary (at first) to read about every single method, just use the Overview to get an idea of what each Class is all about and what you can do with them. Then read the descriptions of the methods that look like they'll be immediately useful to you.

Method names have specific meaning in the ABC Library to indicate the type of functionality each method provides. All the classes consistently use these names:

AddItem Adds an item to its object's datastore. The item may be a field, a key, a sort order, a range limit, another object, etc.–anything the object needs to do its job.
Ask[Information] Interacts with the end user to get the Information.
Fetch Retrieves data (usually from a file).
GetItem Returns the value of the named item.
Init Does whatever is required to initialize the object.
Kill Does whatever is required to shut down the object, including freeing any memory allocated during its lifetime.
Reset[what or how] Resets the object and its controls. This includes reloading data, resetting sort orders, redrawing window controls, etc.
SetItem Sets the value of the named item, or makes the named item active so that other object methods can operate on the active item.
TakeItem “Takes” the item from another method or object and continues processing it. The item may be a window event (Accepted, Rejected, OpenWindow, CloseWindow, Resize, etc.), a record, an error condition, etc.
Throw[Item] “Throws” the item to another object or method for handling. The item is usually an error condition.
TryAction Makes one attempt to carry out the Action. A return value of zero (0 or Level:Benign) indicates success; any other value indicates failure.

Knowing these consistent naming conventions will make it much easier to understand what an object's methods do, whether you've read the ABC Library Reference about that specific type of object or not!

In addition to the ABC Library Reference, 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.

The ABC Templates do many things for you that the Clarion templates do not. See the ReadMe file for a list of the new template features (the Template Guide contains complete ABC Template documentation).

If the ABC Templates will perform the task for you, you're done. If they won't, continue on to Step 2.

.1.Identify the ABC Object (and its CLASS) that manages the behavior you need to change.

Quite often there are several candidate objects in a single PROCEDURE that might control the behavior you need to change. Therefore, you may need to identify several objects/classes to look at in the following steps. The easiest way to identify candidate objects is to look in the Embeditor. Each object you see in your PROCEDURE is derived from the ABC Library. The object's Parent CLASS name (in parentheses following “CLASS”) should give you an idea of the type of behavior the object controls. The most common objects and their corresponding classes are:

Object Parent CLASS
ThisWindow WindowManager
BRWn BrowseClass
ThisProcess ProcessClass
ThisWindow ReportManager (in Report procedures)
ThisReport ProcessClass (in Report procedures)

Once you've identified the candidate objects and CLASSes, continue on to Step 3.

.1.Determine if the object/CLASS has a property that you can set to accomplish the task.

The ABC Library Reference and the Class Viewer are the best sources for this information. Remember that a derived class inherits all the properties of its parent class.

If setting a property performs the task for you, you're done. If not, continue on to Step 4.

.1.Determine if a method of the object/CLASS already does the task.

Again, the ABC Library Reference and the Class Viewer are the best sources for this information. Remember that a derived class inherits all the methods of its parent class.

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.

.1.Determine which method you can modify to accomplish the task, then override it.

Follow the same process as in Step 4 to identify the method that comes closest to performing the task you need to accomplish. To override a method, place your code in the embed points for that method. You can use other ABC properties and methods in your code to do what you need.

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 Template Guide tells you that it supports extra sort fields in addition to key fields. If you do not specify a key in the Data /Tables Pad, 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.

1.The Report Template's documentation in the Template Guide shows no template settings to conditionally toggle preview (it's either always on or always off), so you go on to Step Two.

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 ABC Library Reference 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.

Where do you put this one line of code? Since this property is in the ThisWindow object it cannot execute until the ThisWindow object has been initialized (following the PARENT.Init call in ThisWindow.Init). And, since the purpose of this task is to “shortstop” the Print Preview, it must execute before the Previewer object is called to display the finished report (before the PARENT.AskPreview call in ThisWindow.AskPreview). These two requirements limit you to probably only a few hundred embed points within your report procedure's logic, but the best place to just “set it and forget it” is the end of the ThisWindow.Init method. You're done at Step Three!

Task: I want to let the end-user dynamically filter a browse list at runtime.

.2.The BrowseBox Control Template's documentation in the Template Guide doesn't show any template settings for a dynamic filter, so you go on to Step Two.

.3.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.

.4.None of the BrowseClass properties listed in the ABC Library Reference 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.

.5.The ABC Library Reference 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 !If the user entered a letter

BRW1.SetFilter('CUS:LastName[1] = ' &amp; NewFilter &amp; ) ELSE !Limit to names starting with the 1 letter in NewFilter BRW1.SetFilter() !Reset to no filter

END

ThisWindow.Reset(1) !Force-Refresh the window display

But where to put this code? Since you want the end user to enter the data to filter on, you obviously need an ENTRY control the user can type into, and that ENTRY control's USE variable is obviously the NewFilter variable (a STRING(1) in this example code) you want to use in the SetFilter method. Therefore, the only logical choice for where to place this code is in the EVENT:Accepted embed point for the NewFilter ENTRY control.You're done at Step Four!

Task: I want the user to be able to copy an existing record when adding a new record.

This task actually means that you want to provide a “Copy” button that does everything the “Insert” button does (like auto-increment) but gives the user some “starting point” data in the update Form based on the currently highlighted record in the Browse list.

.2.Neither the BrowseBox nor the BrowseUpdateButtons documentation in the Template Guide shows any template settings for this, so you go on to Step Two.

.3.In the Embeditor, you see that the only likely candidate object/CLASS is BRW1/BrowseClass, because it controls the browse list and calling the update Form, so you go on to Step Three.

.4.None of the BrowseClass or inherited ViewManager properties listed in the ABC Library Reference appear to help for this task, so you go on to Step Four.

.5.You look at the BrowseClass methods and don't see any that might apply, so you check the inherited ViewManager methods, also. That's where you find the ViewManager's PrimeRecord method, which takes a parameter that appears to be exactly what you need for this task. However, this method is VIRTUAL–automatically called by the base classes–so you don't need to call it, so you go on to Step Five.

.6.Opening the Embeditor for the Browse procedure, you find the BRW1.PrimeRecord method. You can see that it takes a parameter called SuppressClear which defaults to FALSE (zero). Therefore, you know that you can just assign TRUE (one) to the SuppressClear parameter before it is passed on to PARENT.PrimeRecord to suppress clearing the rest of the fields in the record (after auto-incrementing any necessary fields). However, if you just do a simple assignment statement, you will be overriding this functionality for every insert. Therefore, you need to declare a local flag variable to the Browse procedure to flag whether or not to suppress the clear. Scroll back up to the top of the file and, in any Data Section embed point, add the following code:

CopyFlag BYTE     !Declare the flag variable

Then you can place the following code in the BRW1.PrimeRecord method immediately BEFORE the PARENT.PrimeRecord call:

IF CopyFlag = TRUE !Check the flag's value

SuppressClear = TRUE !Set the PrimeRecord parameter value

CopyFlag = FALSE !Reset the flag

END

This overrides the ABC Library's PrimeRecord method with your own, but still calls the ABC Library's method to handle its functionality (so we don't have to re-write its code). Since this is a VIRTUAL method, you don't have to worry about calling it–it's called automatically for you from within the other ABC Library methods.

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.

This task requires that you have a “Copy” button as described above.

..3.The BrowseBox Control Template documentation in the Template Guide doesn't show any template settings for this, so you go on to Step Two.

..4.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.

..5.The BrowseClass documentation in the ABC Library Reference lists a Popup property described as a “browse popup menu reference.” Reading the description of this property you discover that it is a reference to the PopupClass object used by the Browse, so you look at the PopupClass to see if there are any properties that will add an item to the popup menu for you. There are no PopupClass properties, so you go on to Step Four.

..6.You look at the BrowseClass methods and don't see any that might apply, so you check the PopupClass methods, also, since you know the Browse object contains a reference to the PopupClass object. That's where you find the PopupClass's AddItemMimic method, which will add an item to the popup menu to press a BUTTON control. This appears to be exactly what you need for this task. Therefore, you now know that to add the Copy button to the popup menu for this BrowseBox, you can simply execute:

!Call a PopupClass method through the Browse object's PopupClass !reference property
   BRW1.Popup.AddItemMimic('Copy',?Copy)

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: 1) alert the procedure that it will be inserting new records into the database, 2) ensure that any auto-increment keys are properly incremented, and 3) ensure that all other fields in the file are properly initialized to their default initial values.

.2.The Form Template's documentation in the Template Guide doesn't show any template settings for this, so you go on to Step Two.

.3.In the Embeditor, you see the only object in the Form procedure (other than two Toolbar-related objects) is ThisWindow/WindowManager. However, you also have a global object for each of the data files your application accesses. Therefore, a second candidate object/CLASS to look at for this task is Access:FileName/FileManager.

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.

.2.None of the WindowManager properties listed in the ABC Library Reference appear to help for this task, so you check the FileManager properties also. None of these apply either, so you go on to Step Four.

.3.The ABC Library Reference shows two FileManager methods (PrimeRecord and PrimeAutoInc) which appear to be exactly what you need for this task. Now you just need to find where to call them, so you go on to Step Five.

.4.The ABC Library Reference shows a WindowManager method called PrimeFields that looks like the best place from which to call the FileManager methods. In the Embeditor, you write code like this into any embed point in ThisWindow.PrimeFields:

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.

The Clarion ABC Templates have a “Pause Button” Control Template which does exactly this. Simply place this Control Template on the Report's ProgessWindow, and you're done at Step One!

Task: I want total fields on one tab and the BrowseBox which they total on another.

This task implies that the tab which the user sees first is a “summary” tab, and the “detail” Browse list (or multiple lists) which calculates the totals is hidden on another tab. Simply placing the total fields on a separate tab from the hidden Browse means that the total fields display zeroes until the user has gone to the tab containing the Browse list and come back to the tab containing the total fields. The ABC Templates default to only updating a Browse list when it is visible because this achieves better overall performance for the majority of cases. However, in this one case, the Browse list needs to be active despite the fact that it is not visible to the user.

.2.The BrowseBox Control Template documentation in the Template Guide doesn't show any template settings for this, so you go on to Step Two.

.3.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.

.4.The BrowseClass documentation in the ABC Library Reference lists an ActiveInvisible property which, when set to one (1), makes the Browse list active even though it's not visible. Therefore, you now know that you can simply execute:

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 other Clarion OOP Learning Resources?

Yes, there are several:

·Clarion Magazine is located at http://www.clarionmag.com (this requires a subscription) and is published monthly by CoveComm Inc. This “e-zine” features articles of interest to all Clarion developers, including writing OOP code and using the ABC Templates and Library.

·Many Clarion developers are on-line and willing to help others as needed. Your colleagues can be found in the SoftVelocity Internet newsgroups–most notably, comp.lang.clarion (on many news servers) and softvelocity.public.Clarion7 (only on the news.softvelocity.com news server).

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.

making_the_transition_to_the_abc_templates.htm.txt · Last modified: 2021/04/15 15:57 by 127.0.0.1