Approach Users Mailing List FAQ (text version) Last updated: 7 Mar 2024 This FAQ contains a summary of answers to Frequently Asked Questions on the Approach Users Mailing List, as well as other material that may be helpful to a wide range of Approach users. This text (.txt) version of the FAQ is available for download at: http://www.johnbrown.com.au/approach/textfaq.htm The Rich Text Format (.rtf) version of the FAQ is available for download at: http://www.johnbrown.com.au/approach/textfaq.htm The web version of the FAQ is at: http://www.johnbrown.com.au/approach/faq.htm Disclaimer: Approach User Support FAQ (text version) and associated documents (Web site, Web FAQ, newsletters and mailing list documents) are provided as is without any expressed or implied warranties. The editor and contributors assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein. ** ** Special thanks to www.XpertSS.Com for their many contributions to this FAQ ** ** [From this point on line wrapping is in the hands of your document viewing application] Contents: The Approach User Support web site How to get the latest edition of the FAQ How to get the Archive of LotusScripts Contributions, comments, corrections, or feedback Lotus support now at http://www.ibm.com/support/ Notices Our collective wisdom so far... The basics ("Stuff you really should know before you read other stuff") - Getting started with joined databases! - Help me design my database! - Designing and problem solving techniques - Looping macros - Record numbering, including auto-incrementing serial numbers - Using Boolean fields - Reinstalling Approach General information - What is Approach? (Is it truly relational?) - How does Approach compare to other DB's? - IBM's Lotus Approach Support web site - Books - Example and commercial Approach applications - Other information sources about Approach - Other information sources about LotusScript - Can I Develop Stand-alone databases (Run-time) using Approach? - Can Approach handle big databases? - Moving or copying databases (.apr/.vew .dbf .dbt files) - Help for MS-Access uses moving to Approach - Getting started with LotusScript Approach/.dbf specifications and overcoming limitations - The latest version and upcoming developments - Versions of Approach for MS-Windows / NT - Versions of Approach for OS/2 - dBase IV limitations - Limitations of Approach - Maximum of 50 joins limitation - .oyz index files - Files and File Types - Maximum of 20 charts per .apr Optimizing databases and minimising the chance of problems - Optimizing the speed of a database - Compressing databases with a macro or script - Reducing ("Compressing") the size of a database file - Why doesn't the .dbf file size decrease when I delete records? - Good practices to reduce that chances of encountering problems - DON'T delete macros, named find/sorts or scripts... - Backing-up your data using a macro Corrupt index (.adx) files - .apx files - Repairing corrupt index (.adx) files - Deleting and recreating index files (.adx) Errors, lockups, crashes, and other problems - General Protection Faults (GPF's) - Repairing corrupt .apr/.vew files (e.g. errors when changing views) - Out of Memory error message - "Record is locked- retry -cancel" error message - "Someone locked this record" errors - "Unable to open ___.dbf file, 5009" errors - "Macro error: Import table has changed" error - Internal Error: Cannot load string 0 - "Could not load infobox dynalink" error - InfoBox, Tools Palette, etc... won't appear - "Page Fault... at 0137:0049eb64" in Approach 96 - Approach 3.02 crashing in design mode and when switching views - "An error has occured in your program" errors - Database being used exclusively error - "Internal Error - Cannot load string - 1035." error message - "GPF in APPREXPR.DLL at 0009:0D2C." error message - Vanishing scripts - "Could not find database [path]\name.mdb" error - "couldn't open database because it is open in another language..." - Globals Sub "Initialize" doesn't always get executed Printing - Printing formatting problems - Printer problems (including GPFs, HP Printers) - Header / Footer problems in v2.1 - MS-Windows 95 printing blank pages (v2 & v3) - Printing field definitions - Printer fonts problems - Pages sizes in v9.6 Dates and times - Calculating elapsed time - Calculating ages from birth dates - Calculating number of weekdays - Finding or calculating dates - 21st Century Dates - Two digit year assumptions (eg 01/01/29) - Date format with 4 digit year (e.g. 1997) - Importing Dates - Dates in report titles - Find the previous weeks records - Y2K / Millennium bug compliance and leap years - Time and Date Schedule (uses SQL and multiple records) Formatting and displaying fields and buttons - Field Formatting (including not / rounding numbers) - Displaying Negative Values In Red (Changing fonts colours using LotusScript) - Leading zeros (eg. 00054628) - Trailing zeros (eg. 1.400) - Display problems (including problems switching to a particular form) - Removing unwanted characters from phone numbers - Radio Buttons Field Label - Make empty fields disappear (... rather than just turn invisible) - Converting numbers to words 34 to thirty-four? - Sliding fields together on mailing labels - Including quotes, symbols and international characters in strings - Phone numbers - How to make a field invisible on a form - Conditionally display a pushbutton - Stopping Approach from using Marlett as the default font Reports and form letters - Deleting the body in summary reports - Tips on layout of Reports / Altering report width - Total page counts on Reports - Form letters (and multi-page reports) - Stopping v96 (and beyond) from entering design mode when switching to a report - Repeating panels in Reports - Creating HTML and text file reports Data entry - Limiting the options in a drop down list using an Alias table - Making keyboard entries into a formula or macro - Limiting the number of characters entered into a text field - Conditional form navigation ( tabs ) - Recovering deleted records - Bypass the misuse of the "Esc"-button when using auto-increment Finds - Automatically finding a 'drop down' list entry - Preserving the found set when switching forms - Finds on multipage forms - Finding records which do not contain *text* - Tricky finds - Including Find criteria on a report - How to pre-fill fields in a form-based find Sorting - Setting default sort order for a database or view - Saving records in their sort order - Sorting memo fields or fields that reference a memo field Calculated fields - IF limitations in v3.0* - Using values from the previous record - Tricky calculations - Generating a random unused PIN number - The Combine() function in calculated and memo fields - Using calculated fields in joins and exports - Calculations on numbers in a text field (eg imperial measurements such as 3'6") Summary fields - Summary fields - Demystifying Summary Functions - Problems with summary panels - Using a summary field to count records which meet certain criteria Repeating panels - Problems with repeating panels - Finds on repeating panels fields - Using an alias to limit the records in a repeating panel Working with other data formats and applications - Exporting numbers - Approach 97 incorrectly exporting numbers via macros - Working with Paradox database files - Accessing Access files (*.mdb) - Accessing .dbf's updated by Access / Paradox - Using index files other than .adx (eg.mdx) - Export of Crosstabs to 1-2-3 - Using Approach and IBM DB2 - SQL and Approach - Using SQL from LotusScript - Using SQL in Approach with non-SQL data sources - Sending email directly from a form - Using the contents of a variable field as an export filename - Exporting summary fields - Using a macro or Script to open documents in other applications - Problems getting TeamMail to work - Export in the Quickbooks export format - The Approach ODBC SQL server driver - ODBC Connection to Oracle database tables - Transferring data to the Clipboard - Accessing information in an Approach database on the web (WWW) - How to lauch your default browser to view a URL contained in a text field Network installation of Approach - Running Approach on a network - Finding the current Network ID - Dealing with different paths to the same data from different computers - Accessing .dbf files using Novell client 4.83 on Windows 2000 Upgrading Approach and/or your operating system - Do you need to upgrade? - Conversion of old .apr's to Approach 96 - Approach and Windows NT - Upgrading ... - Free Approach 3.02 Upgrade - Approach v97 and Windows 98/vME - Running different versions of Approach concurrently - Running applications developed in Approach for MS-Windows on OS/2 versions - Installing the Approach 97 apfixpak - Approach and Windows 2000 - Approach on a Linux server - Dialing phone numbers from within Approach - Approach and Windows XP Building applications and working with .apr's - Automatically opening files - Automatically opening a particular view - Automatic macro on opening/closing View file - Keeping users out of design environment - Database security - Changing security passwords - Stopping people accidentally entering data - Stopping users from deleting records - Stopping Approach from prompting to save an .apr - Running a Macro in a different .apr files - Moving a view from one .apr to another - Starting Approach without displaying the startup banner - User selection of database tables within an .apr - Distributing .dbf database files to users - Scripts are not imported with an .apr Example LotusScripts - Getting the path of a database file - Screen updating during script execution - ConvertNumberToText - CurrencyToWords function - Conditional Automatic Entry - Create a delimited text file from two fields - Disable the action bar, smart icons, status bar and view tabs - Serialized invoice number on billing - Draw rounded rectangles to size (for envelope windows) - Using keydown event to automatically enter or modify a date - Launch multiple Approach applications at start-up - Syntax use of currentview.body.objectname.text - Script Launch at Record Change Event - Check Existing Data and ask for details for new record - Lotus Notes SQL script - Read in the Approach User Section in win.ini - Handling Approach Object Errors - Error trapping and data manipulation script - Creating a dot notation text file - Progress bar - Flashing text - Import a text file (or .dbf) into a DBF - Linked List class (beats 64K limit on arrays) - Fill Field No.1 - Fill Field No.2 - Named Find Event - Named Find Event with selection sort - Named Find Event with a different sort routine - Find the current network ID No.1 - Find the current network ID No.2 - User selection of database tables within an .apr - Pushing selections from one list box to another - Accessing items in a list box - SQL delete - Activating a macro in another APR - Converting Approach form to MS Word Document - Creating a new row in a repeating panel - Copying calculated fields to the clipboard - A button activated script that launches URL contained in a text field - Loading a document into some other application - A "Translate" function in LotusScript - Another "Translate" function in LotusScript - Passing the contents of a field to Google.com - Splitting a text field apart at Tabs - Using Windows 95/98 API to launch another application - Go back to the last thing that the user was using - Go back to the last thing that the user was using (A different response) - "Freezing" the screen while executing a LotusScript - Controlling the window size when opening Approach Unclassified articles - Generating and reading barcodes - Zip codes and Post codes - Recovering deleted records - Turning off screen updates when running a macro - Advise when using memo fields... - Creating a 'Help' file - Storing pictures - Remote dialup access to Approach - Multi-line messagebox - Tips on using the Script Editor - Printing out .apr file properties - Setting the auto-incrementing serial number - Quick access to objects in the script editor - Automatically saving your work How the Approach Users Mailing List works Contributors The Approach Users Mailing List The Topic Off topic and personal messages The List Owner Subscribing, unsubscribing, digests and other options Question and Answer Posts comp.databases Lotus Mail storms Disclaimer Editor ##>: The Approach User Support web site The is the official web site associated with the Approach Users Mailing List and the other related services. Check it out at: http://www.johnbrown.com.au/approach/ ##>: How to get the latest edition of the FAQ The latest version of the FAQ is available at the Approach User Support web site: http://www.johnbrown.com.au/approach/ ##>: How to get the Archive of LotusScripts The Archive of LotusScripts is now incorporated in the FAQ available at: http://www.johnbrown.com.au/approach/ ##>: Contributions, comments, corrections, or feedback If you have any comments, corrections, or feedback, please email me (John Brown) at approach-owner@mailman.anu.edu.au However, new FAQ articles and scripts should be set to the mailing list first so that people have a chance to comment on it before it goes into the FAQ. ##>: Lotus support now at http://www.ibm.com/support/ Our frustrations with http://www.support.lotus.com have finally come to an end! The site has been shut down, and now the official place to get support for Lotus Approach on line is at http://www-3.ibm.com/software/lotus/support/approach/support.html, which at this stage looks as if it is going to take your frustration to new and dizzying hights! I haven't got around to removing/updating my links from the old site yet. I'll try to get around to it soon. In the mean time, if anyone stumbles across an old link and knows where it should be redirected to, feel free to let me know at approach-owner@mailman.anu.edu.au. Thanks! ####> Notices ####> Our collective wisdom so far... ###> The basics ("Stuff you really should know before you read other stuff") #> Getting started with joined databases! Understanding relational (or "Joined") databases is a big area, but is vital to fully utilizing a program such as Approach. It can be a frustrating time with many concepts to learn, as well as all the ins and outs of Approach. DO NOT START by launching into some major project that you expect to be fully functional tomorrow. Start small, using some test data, and test each function before you go onto the next. Read all you can, and spend time carefully planning what databases you need and how they should be joined. Once you have the basic structure of your database set up you can begin entering or importing you actual data. But as I said, start by do some reading. Some books are recommended earlier in the FAQ, but don't forget the Approach manual either. It briefly takes you though the process of setting up joined databases. Looking at the example databases that come with Approach will also help you understand how the different data in different databases is linked together to provide many facilities that are not possible in flat databases. #> Help me design my database! (joins, repeating panels, what data in which database etc...) Apart from simple 'card file' type databases, every piece of major database software you can think works with relational databases; Approach, Paradox, Access etc... In order to use any of these packages efficiently, including Approach, you first need to understand what a relational database is, and how you would divide your data into one. If you don't understand this then you are going to have difficulty using many features of Approach, or any other database software. Questions concerning database design are quite common on the Approach Users Mailing List. However, strictly speaking most of these questions and answers have little or nothing to do with Approach. What the people asking these question lack not so much an understanding of how Approach works, but rather an understanding of what a relational database is and how they work. And as it turns out, I am not going to attempt to explain this! Instead, what I suggest you do is this: Allocate some time and perhaps money, to do some reading or perhaps a short course in relational databases. Some books are suggested above. The Approach manual includes some information, but most people seem to need a more in-depth look at it before they really grasp what is happening. The better this ground work the easier and quicker you will be able to build an efficient database. I won't take all that long, and the benefits are huge. Also have a careful took at the example databases supplied with Approach. Go into design and check out the structure of the database; the design of the various views; and how each aspect works. Its a good idea to also become familiar with all the features of Approach so that you can be aware of what is it ~ and isn't ~ capable of. In particular, getting to know macros and how to loop them is is very handy (see articles 'Looping macros' and 'Conditional form navigation ( tabs )' in this FAQ) As you are doing these things keep some notes about how you might structure your database. When you are ready begin establishing your database one bit at a time with a small amount of test data. When it is fully functioning, or at least developed enough to do all the major functions, import your data, and begin using it! #> Designing and problem solving techniques Try this: Rather than working with you main database, try setting up and testing out things or trying to solve problems on smaller practice databases. This way you minimize the possibility of you loosing valuable data, or disabling your main database when you really need to use it. For example, if your having trouble with an import or export, set up a very simple flat (i.e. no joins) database and view form. Enter some junk data into a couple of records and try exporting it as a text file. If this works, try importing it back in again. When you can do this, expand this test database so that it has two databases that are joined, and the data from both database is displayed on the one form. Then export some data. Add a repeating panel. Export some more. Import some back in. At every stage do only one thing at a time and test it. This way you will easily identify at which point you are getting into trouble. Once you have managed all of this on your test database you should be able to solve the problems on you main database. #> Looping macros (Including sequentially numbering a set of records and making global changes to a set of records) This FAQ demonstrates macros implemented in Approach V3, 96 or 97 or any of the "Millennium Edition 9.x" releases. Macros were implemented differently in prior versions of Approach, so if you used version 1 or 2, you will need to spend some time in the help files / manual of Approach to accomplish a similar result. Broadly speaking, a looping macro (which may consist of several individual macros working together) does the following: * performs a particular operation or operations * moves to the next record * runs the macro again from the top This sequence of steps means that the operation is performed on every record in the current found set. Conditions can be added to the operations so that they are only performed under certain conditions. For example, if you wanted to add a 6 to all of the phone numbers starting with a 5, then your macro would include the statement: SET db.phonenumber to If(Left(db.phonenumber,1)='5', Combine('6', db.phonenumber),db.phonenumber) (where "phonenumber" is a text field) Often it is necessary to have a macro that precedes the looping macro to set up the conditions that the loop needs for its correct operation. (I'll call this a Control macro). This may do things such as: * Go to the required view * Find the set of records to be processed * Position to the first record in the set * Set variable fields to initial values * Then "run" the looping macro * Give the user a message that the operation has completed. The last operation of the looping macro always runs the looping macro again (NOT THE CONTROL MACRO) This is demonstrated below, but first... To carry information from one record to the next you need to use variable fields. For instance, if you want to sequentially number a set of records you need to know what number the previous record was in order to set the number of the current record. The following example demonstrates both the use of a Control Macro and a Variable to sequentially number a set of records: 1) Create a numeric field 'VarIDNumber' to hold the sequential number, and a variable field 'VarID' to use in calculating the sequential numbers. 2) Create a looping macro 'SequentialLoop'. This macro should do the following: * SET VarIDNumber to VarID * SET VarID to VarID + 1 * ENTER (to save the updated record) * RECORDS Next (note this command will exit this macro when it runs out of records in the found set) * RUN SequentialLoop For this macro to work properly it needs the Control Macro created in Step 3) 3) Create a macro 'Sequential numbering' to be the Control Macro. It should do the following: * VIEW switch to the required view (optional) * FIND the required found set (optional) * SET VarID to the required number for the first record * RUN the looping macro 'SequentialLoop' and return to the next statement * MESSAGE "The records have been numbered successfully." (optional) To execute the looping macro, run the 'Sequential Numbering' macro. Note: In V2.1 you need to use three macros (it does exactly the same things as shown above, but it just takes 3 macros to do it. In v2.1 it is easy to end up with loop macros containing several macros): Macro 1: Set the variable field to 1 Run Macro 2 Macro 2: Set the numeric field to variable field Menu Options: Next Record Run Macro 3 Macro 3: Set the variable field to variable field + 1 Run Macro 2 Also see 'Record numbering' in this FAQ. #> Record numbering, including auto-incrementing serial numbers It is often useful to have a unique identifier for each record in a database -- like a customer number or order number, for example. Or to use in joins where other unique fields are not available. For example, you would not want to use a telephone number in a join because the number could change over time. So it would appear useful to just use the record numbers Approach assigns as you add records. You know, those numbers you see in the status bar at the bottom of the Approach screen? But this is not the case. Why? * The record numbers are not part of the database and are not permanently assigned to particular records. * When you sort the records, the record that is #1 changes to the one that is "relatively" the first one in the current database. * When a record is deleted that record's number is not also deleted. * The record numbers are not part of your data, and you do not have access to the record numbers in calculated fields or finds etc. Not even from a script! If you want each record to have a fixed reference number that never changes as long as the record continues to exist, then you need to create a numeric 'serial number' field which automatically increments each time a new record is created. To do this, just create a numeric field using Field Definition. Then select the desired starting number and increment value in 'Options'. If you have existing records with no number in this field, you will want to add a unique number to them using the technique described elsewhere in this FAQ in "Looping Macros". Unfortunately, the auto-incrementing serial numbering options on numeric fields are not accessible from LotusScript, which means that you cannot read or change the next serial number from a script. In other words, if you add a record using a ResultSet in LotusScript, the serial number will not be entered or incremented. In this situation you have two options: 1) you can write your script so it doesn't use a ResultSet and instead adds and updates the record using a view. 2) you can create and use your own auto-incrementing field instead (details of how to do this can be found at http://www.xpertss.com, under 'Maintain auto-serial numbers when creating records with a ResultSet object' in the 'FAQ's - Tips and Techniques' folder). #> Using Boolean fields Boolean fields can contain a true or false value, or can be "empty" (ie contain a "null" value). Therefore if you want all records to have either a true or false value in the Boolean field then you need to specify a default value in Field Definition, and update any existing records using a macro or script, or FillField. Alternatively, when you need to search for false items, search for all of the items with do not contain a true value. This search will return all records in which the Boolean field contains either a false or null value. You can't use a Boolean field in a join, but a way of getting around this is to simply use a numeric field that either contains a '1' or a '0', so use that instead. #> Reinstalling Approach If you are reinstalling Approach to recover from a "one of the library files damaged" error or an unexplained GPF, you may need to uninstall Approach first. When reinstalling Approach it does not replace a file unless it really thinks it needs to. So if a file is corrupt but the installation program does not detect that it is corrupt, then the file may not be replaced - and your problem will remain unless you uninstall it first. ###> General information #> What is Approach? (Is it truly relational?) This article assumes you are familiar with relational database terminology. If you are not, then all you need to know is that Approach is a database application! Approach is a RDBMS (Relational Database Management System) or 'client-side file server' application. It does not have a native database format but operates as a front end to many different data formats (dBase IV by default). It will also operate as a fully functioning front end/client to Client/Server database servers such as Oracle, including the ability to take advantage of Stored Procedures, Triggers, and the like. Approach is more relationally compliant than many other desktop RDBMS's in that it partially supports cascaded updates and deletes, as well as referential integrity constraints. #> How does Approach compare to other DB's? The following is an excellent article comparing six major database packages, including Approach and Access. http://www8.zdnet.com/products/content/cshp/1804/288515.html Articles about how Approach ranks against other databases, as well as handy hints, and how to optimize your productivity with Approach and SmartSuite, are available by searching the following web sites: http://www.pcworld.com http://www.reviewsource.com http://www.pccomputing.com The following is a collection of comments made by different subscribers comparing Approach and Access: Approach is oriented toward the non-programmer both in ease-of-use areas and in terminology. You can get a lot done with just Approach's design tools and a few simple macros, whereas in Access you must get into "basic" programming fairly quickly. Defining fields is an example of the programmerese in Access - it uses technical terms instead of the more simple "numeric 10.2" or "date fixed" terms in Approach. I also like the idea that my data is stored in commonly used formats like dBaseIV as that opens up the data to use with dBase shareware and reporting packages, if I need them. Access stores all your data and views in one file - you lose it and you have "lost the farm". --- As far as Approach vs Access, both have advantages and disadvantages. I find Approach easier to get started with. It also handles data in a safer manner. Your data tables remain separate from your front-end file (the .apr file) which makes them more secure, easier to save, and available for other programs. (The last could also be a disadvantage under some circumstances.) Access has much better third-party support - you'll find 20 or 30 Access titles in Borders or Barnes & Noble, and (maybe) one on Approach. And IBM (the owner of Lotus) does not have the same commitment to desk-top computing and software that Microsoft has. Because your tables are not part of your various .apr files, you can start all over again with new .apr files, and safely destroy the old ones when you want to. You may have noticed that you create calculated fields in Approach - for display in forms and worksheets, and summaries in reports. The calculated fields are in the .apr files, so you might want to write down any neat ones you have developed for use in new .apr files. You can create and use multiple data-entry forms with any single table or any group of tables in one .apr file, and turn around and use some of the same tables, with other tables, in a separate .apr file. For example, the "customer" table can be in the sales-contact database, and also in the Accounts Receivable database, in such a way that the sales people would not see the money records, and the bookkeepers would not see the future sale projections. (Revenue and projections being in separate, related tables.) You can copy views within a .apr file. The only way I have found to copy a view between .apr files is to import the entire source file, and delete the parts I don't want. In doing this I also have to reset the table joins and connections. --- When I evaluated Approach v Access the advice I got was that Approach was easier to learn and much faster to develop in. You can develop a larger app in Access. Approach has limits like 50 joined tables in an apr whereas I think (from memory) Access can handle 100. Anyhow, most Approach users would say that once you get above 20 joins in an apr you should split the app over multiple apr's for performance reasons. For our Company's circumstances Approach seemed the way to go and has turned out a big success. --- I use both Approach and Access. I tend to agree with those that feel that Approach offers a more friendly user interface. I have not come across any tool yet that can compare to Approach in terms of quickly designing and rolling out an app. On the other hand, I have found that I am beginning to push the limits of what I can do with Approach. I was forced recently to develop a billing application in Access, because I just could not get Approach to do what was needed without gobbling up all available memory or generating gpf's. I qualify this by pointing out that I do my Approach development in v3.02 of Approach (16 bit). I cannot speak to the relative merits of Approach 97. Overall, though, I still prefer to use Approach whenever possible. On your second question, there is no "correct" number of .apr files to underlying tables. I find that I use multiple APRs with particular tables, each tailored to the needs of a particular group of users. This flexibility is, IMHO, one of Approach's best features. --- Approach vs Delphi 4?: Comparing the two products is like comparing apples and oranges. Delphi is a very good product if you like Pascal. It's not the easiest product to learn. Each time you perfect a level of understanding it, they come up with something new and better. If you write application for sale then it's one of the good products beside Topspeed. If you write database management programs, you'll find Approach to be one of the best tools... For you and me Approach is better because it takes us maybe two days to knock out a database, in Delphi or Topspeed think of two weeks to two months or more. #> IBM's Lotus Approach Support web site IBM's Lotus Approach Support web site can be found at http://www-3.ibm.com/software/lotus/support/approach/support.html. It includes a downloads FAQ, 'Technotes', Product Information and 'White Papers'. 'Technotes' are technical documents which address particular problems people have had with Approach. It is a good idea to search here first if Approach is giving you an error message. 'White Papers' are "Detailed investigations into how products work, often including coding tips and techniques." #> Books The following books have been recommended in posts to the Approach Users Mailing List: * The manual that come with Approach. Always a good place to start! * Approach 97 for Windows for Dummies by Deborah S. Ray, Eric J. Ray / Paperback / Published 1997. This appears to be the only book that is specifically about v97. However, you may want to check out some of the v96 books first, as they cover most of what you will need to know and the 'dummies' style isn't for everybody. * Mastering Lotus Smart Suite 97 for Windows 95 by Sandra E. Eddy, includes 'reasonable' coverage of v97 apparently. * Teach Yourself Lotus SmartSuite in 24 Hours by Faithe Wempen and published by published by SAMS. Described by one person as a "Wonderful book, .... broken down into 24 lessons." * Using Lotus Approach 96 Special Edition (Que Books) (Described as being particularly good for New Users) NOTE: If you are looking for a v97 book, the v96 books are still worth getting as the differences are minor and when you stumble across a difference you should be able to get the extra information you need from the Approach HELP files. * Using Lotus Approach 3 by Plotkin (Que Books) * Mastering Lotus Approach 96 for Windows 95 by James Powell (Sybex / Lotus Books, ISBN: 0-7821-1773-2) (This is the most highly recommended book, however, some subscribers have commented that IF YOU ALREADY OWN THE EARLIER VERSION (for v3.0*, see above) then check it out carefully before you by this one. They expressed strong disappointment that it has only been minimally from the earlier version, and major aspects of Approach 96 are not covered adequately. It therefore may not be worth the expense.) * Mastering Lotus Approach by James Powell (Sybex / Lotus Books) (This is the most highly recommended book for v3.0*) * Building Databases with Approach 3 by Elaine Marmel ("...seems to be an extended, well documented, tutorial on building a database that is usable in a business environment.") * Approach 3.0 for Dummies * Practical Approach version 3.0 by Siegel (MIS Press) * Introduction to Databases" by James T. Townsend (recommend for business uses who are learning and updated designing databases. It is about databases in general rather than how to use Approach.) #> Example and commercial Approach applications See the 'Archive of Example Database Applications' at the Approach User Support web site: http://www.johnbrown.com.au/approach/examples.htm This includes a few of downloadable databases, as well as links to other such sites. #> Other information sources about Approach * A good way to learn about database structure and what Approach is capable of is to study the example databases that come with Approach. * The Approach User Support links page includes a load of Approach related web sites: http://www.johnbrown.com.au/approach/links.htm * The comp.databases newsgroup contains discussion about many different database applications including Approach. However, I haven't seem any Approach discussion on it for a long time. * de.comp.office-pakete.lotus-smartsuite is an active German language newsgroup which contains discussion about all SmartSuite applications, including Approach. Also see the German language version of this FAQ at: http://smartsuitefaq.vol4u.de The following non-Internet resources are the above web page, but are mentioned here for the benefit of those who don't have web access: * Lotus fax - back service: A blast from the past with was discontinued on November 6, 1998. * Lotus Forums on Compuserve: - GO LOTUSB for volunteer support on Approach - always good advice. - GO PCAPP - the PC Applications forum has a general database section. - GO BORLAND - for help and information on dBASE tips and utilities. - Search Compuserve for forums about DATABASE and you will get a long list of helpful contacts for Paradox, Access, Foxpro, DB2, and other database formats you may be using. * The Approach BBS: Now a mere memory in the history of online services #> Other information sources about LotusScript * A lot of the sources of information about Approach shown above will also include information about LotusScript * Don't forget to have a good look through the examples that come with Approach in templates, saved smartmasters etc... * See the Approach User Support Links page for some helpful web sites: http://www.johnbrown.com.au/approach/links.htm * LotusScript for Dummies (ISBN: 1-56884-638-X) I D G Books * Chapter 8 of "Developing SmartSuite Applications Using LotusScript". This book is on the SmartSuite CD in .pdf format which you read using Adobe Acrobat which is also on the CD, or you can download it from the PSC SmartSuite Developers site in the Resources section ( http://suitedev.psclistens.com/lotus/smtsuite/smtstdev.nsf/?Open) or by searching for the title at http://www.lotus.com. * "60 minute guide" for Notes LotusScript. This book assumes that you an understanding of programming background. * The LotusScript Language Reference, a comprehensive summary of the LotusScript language, presented in A-Z format. The LotusScript Language Reference is available as Help in all Lotus products that support LotusScript. * The LotusScript Programmer's Guide, a general introduction to LotusScript that describes it's basic building blocks and how to put them together to create applications. It is on the SmartSuite CD-ROM in .pdf format, and is also available for download (alone with other documents) from Lotus' SmartSuite Products pages (accessible via the Approach User Support Links page mentioned above). * The 'LotusScript Expression Assistant' is a programming tool available by searching for the title at http://www.lotus.com, which can apparently help you learn LotusScript language faster, and is useful to rethink ideas and which arguments can/must be used. #> Can I Develop Stand-alone databases (Run-time) using Approach? No, there is no way of creating fully stand-alone database applications using Approach. Any user of your application will need an appropriate version of Approach installed in order to use it. MS Access and some other database systems have either a "compiler" to create a runnable program from your design or they have a "run time" module that replaces the need for users to install the full product it was developed with. Some charge extra for this feature and some do not. But, there are currently no run time modules or compilers for Approach and none are under development. Lotus/IBM does not see any demand for this type of capability at all from their large corporate customers. According to Lotus, Approach was designed to be a 'desktop database' or 'front end' to data the user wants to manipulate. The idea is you can take an existing database (dBase, Access, Excel, Foxpro, DB2, Oracle, Paradox, SQL, 123 ...) and create your own little application, leaving the original database intact for others. Or you can develop your own simple database from scratch. You can also develop a more complex application with macros and buttons that give your application the appearance of a full-blown application, and you can distribute it to other users, but everyone who uses it needs their own copy of Approach. Using the "Customizing and Automating Approach" chapter 9 in the user's manual you can secure the system such that your users can't harm the database that you build for them. Pay particular attention to the Preferences, SmartIcons, and Custom Menus sections. You can design your database using custom pull-down menus and various buttons on forms so that all the native controls in Approach can be turned off or hidden from the user. And you can further protect both the data and your application's design by using Team Computing features covered in chapter 10. Also review the procedures for defining basic field settings in the various views you give the user to help the user enter data correctly and protect fields they should not change. FYI, this manual is available in Adobe .PDF format from the Free Downloads area on XpertSS.com. Lotus is often amazed by the complex business applications that are being deployed with Approach! If the cost of multiple user licenses for Approach users is a problem, purchasing site licenses and using IBM' volume purchasing scheme will greatly reduce the costs for businesses. And there are several discount software web sites that often discount older versions of the SmartSuite, making it very affordable. Approach 96 and newer versions also include 'LotusScript' which gives you much the same capabilities of Access Basic. You need some programming skills to write your own scripts, but you can often copy scripts and modify them for your own use. This site and http://www.XpertSS.com contain many examples for your education and use. #> Can Approach handle big databases? Well, it probably depends on what you call big, the design of your database, and what hardware you have. People have reported databases of 3 or 4 million records, although at that size running summary reports and finds may take a while! Nobody has ever reported reaching a maximum number of records limit in Approach. In theory it should be able to handle the maximum number of records you can put in a dBase IV database, which is 4294967296 (4 gig = maximum 32 bit number). In order to maintain the best ratio of speed and stability you may want to consider deleting the .adx files (indexes) on a regular basis (say every week or two). There are some possible complications with this so carefully read "Deleting and recreating index files" first. It has been suggested that the number of joins has a far greater impact on the speed and stability of large databases rather than simply the number of records. One subscriber stated that they found a database having "80,000 records and approximately 20 tables joined" to be unusable slow, and suggested that a database of "100,000 records if there are more than 4 or 5 joins" to be a maximum usable size. Meanwhile somebody else replied saying that they had "databases exceeding an average of 400,000 records up to 2.2 million records and joins exceeding 10 databases with Approach 96 having no problems handling the data. "We have been doing multi field queries in an acceptable time frame and once the smart indexes are created, finds on fields are just as fast on a (database) with 2.2 million records as a find on a field with 400,000 records. Our standard hardware is a P5 166 with 64 meg of ram. On a P6-200 with 64MB RAM, doing a complex search on 4 fields takes 15 sec." #> Moving or copying databases (.apr/.vew .dbf .dbt files) The APR file includes the paths to the files as well as their names. Therefore unless you reproduce the directory structure exactly at the destination, the only reliable way to move or copy at database is using the FILE / SAVE AS menu item from within Approach. If you try and move them using a file manager program then the database may not be able to locate some of its components and OLE links may be lost. However, for some strange reason, Approach returns a "Too many files open at once" error message if you try to use SAVE AS on a database with more than 25 joins. If you are using Win 3.1, this happens regardless of how many files your have specified in your config.sys. #> Help for MS-Access uses moving to Approach If you have been using Access for while, then the first thing need to understand is that good quality professional help is available, and you should make a full recovery in no time at all ;-) Sue Sloan has written a booklet oriented toward telling an Access user how to use Approach. A link to that booklet is in the Free Downloads area on http://www.XpertSS.com. Do a search with the word "access" in the title. #> Getting started with LotusScript Getting started with LotusScript is a bit like driving a car - you do actually have to spend time learning how to do it! The best place to start is the resources listed in article 'Other information sources about LotusScript' The look through the example LotusScripts for ideas, especially if some of them come close to doing what you want a script to do. It is often easier to start playing with someone else's script and getting it going than starting from scratch with your own script (until you become an expert of course!). Some good example scripts to start with are the following, because the authors have included pretty explicit instructions about how to get them going: 'A button activated script that launches URL contained in a text field' 'Passing the contents of a field to Google.com' ###> Approach/.dbf specifications and overcoming limitations #> The latest version and upcoming developments SmartSuite and stand-alone versions of Approach are no longer supported. * Lotus SmartSuite version 9.8 with fixpack version 6.1 applied (9.8.6.1) file version (9.8.902.406) http://archive.org/download/LotusSmartSuite99 #> Versions of Approach for MS-Windows / NT The versions recommended are: * Windows 3.* - v3.02 * Windows 95/98 - v97 (NOT 97a) with the latest apfixpak applied, though you won't go wrong with v9.7 * Windows ME - "ME is a Dog! Avoid at all costs", so just buy a new operating system. It is a bad version of Windows 98, so if you are stuck with it, go with the W98 recommendation. * Windows 2000/NT - v9.7 or V9.8.x ***See below for details * Windows XP Home - Similar to the "ME" version, avoid it for business use. * Windows XP and later - V9.8.x ***See below for details Compatibility: All versions can simultaneously access the same database files (.dbt/.dbf or paradox or other formats), but do not share an index file between v3.02 and any other version because the "SmartIndex" format is not compatible. SmartIndexes are only built for dBase files, which is the default type when creating a new database with Approach. Do not convert a V2.* ".vew" or v3.02 ".apr" file to any newer version than v97 directly. This is discussed further in the article "Upgrading ...". elsewhere in the FAQ. Once converted to v97 and saved in that format, you will no longer be able to use the ".apr" file in v3.02. Once in v97 format, your ".apr" file can be opened and used with all newer versions of Approach and it will remain useable in v97 unless you use a new feature, like the "dialog editor" that was introduced in v9.5. You will get a warning about the conversion so you can avoid this problem. The version of LotusScript was updated also in the v9.5, so your scripts may not run correctly in earlier versions unless you "recompile" them. New ".apr" applications created in v9.5 and newer versions are saved in the new format automatically which makes them no longer work in earlier versions. Version history: v1.* = the first version released by Approach Software of Mountain View. (circa 1992) v2.0 = the last version before it was bought by Lotus. (circa 1993) v2.1 = the first version released by Lotus. View files have .vew file extensions. Developed for MS-Windows 3.1 (16 bit). Despite the new version number it was basically unchanged from v2.0 but contained many fixes for problems in the original release. v3.00 = a substantial new version released in 1994. Completely new macros. View files have .apr file extension. Developed for MS-Windows 3.1 (16 bit). Problems are encountered (even with v3.01 and v3.02) if it is run on Windows NT v4 (see 'Approach and Windows NT') v3.01 = a free bug fix of version 3.00. If you are having any problems with v3.00 or 3.01 then get 3.02 before you bother to post. Everybody is going to tell you to get it anyway! v3.02 = a free bug fix of version 3.01. If you are having any problems with v3.00 or 3.01 then get 3.02 before you bother to post. Everybody is going to tell you to get it anyway! This version will work on all newer versions of Windows except XP. v96 = Sometimes erroneously referred to as v4. A substantial update developed for MS-Windows 95 (32 bit). Introduction of LotusScript, the Find Assistant, etc. It was a terribly buggy release -- avoid it! v97 = Developed for MS-Windows 95 and NT 4.0 but apparently runs fine on NT 3.51 (32 bit) Included in Lotus SmartSuite 97 or stand-alone. This version was given to owners of v96 for free due to the bugs in v96. The first version with bug fix updates available on the web -- the "C" patch (apfixpak.exe) is essential! Features include stored finds (very handy) and "Find/Replace" facility. This runs fine on Windows 95 but slows down considerably in design mode on Windows 98 and later. v97a = v97 with the first apfixpak "A" applied. Apply the latest apfixpak and the version will revert to v97 vME = "Millennium Edition". Release Mid 1998. Mainly a compatibility update for Windows 2000 and a bug fix update with new 'Internet-FastSite' features. It runs faster on Windows 98 compared to Windows 95. Release 9 or 9.0 = refers to vME. Release 9 was buggy and was very slow in design mode due to putting too many things into the Windows registry (a Microsoft recommendation!). Release 9.1 = a free bug fix release of vME in December 1998 which was a service release primarily for corporate customers and was not generally available. It relieved the registry problem found in the 9.0 release. Release 9.5 = July 1999. A major update version released both as a stand-alone product and then as part of SmartSuite Release 9.5 around July, 1999. This version finally overcame the slow down in design mode problem mention since v97 on Windows 98 and later. It had enhanced 'Web functionality and Notes/Domino/DB2 interoperability'. Approach received a true "dialog editor", and the normalize feature of Notes Reporter let you use Approach to do reports on Notes databases better. It uses the v97 .apr file format by default, but if you use the Notes Normazlier or Dialog Editor or create a new .apr file it will convert the file to the newer v9.5 .apr format. Lots of bugs lead to the release of 'A', 'B' and 'C' bug fix patches for the SmartSuite version. Only one patch for the stand-alone product was made available. (Approach v9.5 was the latest stand-alone version) Release 9.6 = November 2000. Certified for Windows 2000. Included a few bug fixes. Only available as part of Smartsuite 9.6. Release 9.6.1 = June 2001 bug fix for v9.6. Release 9.7 = Nov 2001. Certified for Windows XP. Finally fixed printing of crosstabs. Only available as part of Smartsuite 9.7. This release finally fixed the crashing of APR files created in W95 running now in W2000. Release 9.8 = October 2002. In addition to Windows XP compatibility updates and new filters for Microsoft Office file formats, many bugs were fixed including the problems with "expanding" fields in reports -- new reports will work correctly even if you run them in an older version, but old reports remain unfixed. Certified for Windows XP. Only available as part of Smartsuite 9.8. Release 9.8.1 = October 2003. Released only to IBM Passport Advantage customers who purchased SmartSuite v9.8 or a maintenance agreement for SmartSuite v9.8 under this program. Falsely listed as a "fixpack" on the Lotus support web site, it is a full release but contains only compatibility updates and a few bug fixes. Release 9.8.2 = October 2004. Another update labeled a "release". Release 9.8.3 = October 2005. Another update labeled a "release", but with major bugs in the Approach component making it non-functional. A "fixpack" for these problems was posted in December 2005. Release 9.8.4 = October 2006. Another update labeled a "release". Release 9.8.5 Release 9.8.6.1 To determine the fixpack version of an installatiom of Approach 9.8, right-click on the approach.exe file (which may be in C:\Lotus\approach or C:\Program Files (x86)\Lotus\approach), then click "Properties" then "Details" and read the File Version: Fixpack Version / File Version 9.8 / 9.8.209.600 (original) 9.8.1 / 9.8.309.400 9.8.2 / 9.8.410.202 9.8 fix pack 3 (9.8.3) / 9.8.509.2203 9.8 fix pack 3.1 (9.8.3.1) / 9.8.511.1803 9.8 fix pack 4 (9.8.4) / 9.8.607.604 9.8 fix pack 5 (9.8.5) / 9.8.709.1005 9.8 fix pack 6.1 (9.8.6.1) / 9.8.902.406 http://archive.org/download/LotusSmartSuite99 Along with the SmartSuite 9.8.1 release, it was announced by Lotus/IBM that future releases will be available only through the IBM Passport Advantage program. While "retail" versions will be announced and they will be for sale on the IBM web site, they are purchased without any support and will not receive fixpacks. This announcement was not well received on the online forums where owners of SmartSuite 9.8 that were obtained outside of the Passport Advantage program felt betrayed by this change in policy. Note that small companies and individuals do not need to apply to join the Passport Advantage program -- there is an "Express" option that lets you buy the product thru the program directly and get support for only that one product. #> Versions of Approach for OS/2 "Approach for OS/2 Warp 4" was launched in 1998 as part of SmartSuite for OS/2 for Warp 4. It didn't have a version number. It was presumably equivalent to Approach for MS-Windows vME. Approach for OS/2 files are fully compatible with Approach 97 for Windows files (also used by Approach for MS-Windows vME and releases 9.*) and are not converted. Older files will be converted in the same way that v97 would convert them. Later versions: * v1.1 released December 1998. A minor update including some 'Euro Support', Y2K enhancements such as sliding windows, and bug fixes (of course!) * v1.1.1 released July, 1999. A free bug fix update for v1.1. You can download it from http://www-3.ibm.com/software/lotus/support/approach/support.html * v1.5 released December 1999. A minor release update containing more up to date import filters and updated LotusScript(v4.0) * v1.6 released early 2001. It is an upgrade not a bug fix. * v1.7 released Jan 2002. Another costly upgrade. * v 1.7.1 released late 2002. An unannounced bug fix mentioned in some technotes, but only available to those with a Smartsuite support contract. This includes those that have purchased Smartsuite maintenance from Passport Advantage or those that have purchased eCS Upgrade Protection. #> dBase IV limitations Approach can use a number of different database file structures, but uses dBaseIV by default. dBaseIV has the following limitations that you might need to be aware of: * maximum file size = 2 gigabytes (per type .dbf or .dbt file) * maximum records per database = 1,000,000,000 (1 billion) * maximum of 30 open dBaseIV databases on a single computer * maximum number of fields per record = 255 * maximum size of a record = 4000 characters (= all the field-lengths added together) - Text field size equals the size defined in characters - Date field uses 8 characters stored as text YYYYMMDD - Time field uses 8 characters stored as text HHMMSSHH - Boolean field uses 1 character (T, F or blank is stored) - Memo or PicturePlus field uses 10 characters stored as a "record number" in the .DBT file - Numeric field uses characters equal to the size definition plus 1. (Numeric 10.2 stores in 13 characters, 5.3 stores in 9 characters. * maximum length of a text field = 254 characters * maximum number of characters in a dBaseIV memo field is 30,000 characters in releases prior to V9.8, which was fixed in that release to allow up to 65,536 (64KB). Some common error messages when using dBaseIV files: * -1003 when adding a field makes the record too long * -1035 when the .DBT file has reached the 2 gigabyte limit and no more records can be added Information about field names: Approach Field Definition allows up to 32 characters for field names, and it allows alphabetic letters, whole numbers, spaces, commas, periods, and arithmetic signs. If you delete the SmartIndex file (.ADX): * Your field names are truncated to the dBaseIV standard of 10 characters, all capitals, with no blanks or special characters other than the underscore. * Non-allowed characters and blanks will be replaced with the underscore. * A "Time" field name will always end with the characters "TM9" so that Approach will know it is a time field. * PicturePlus field names always end with the characters "PC9" so that Approach will know it is a PicturePlus field. * dBaseIV Field names must be unique, so if you have field names that are the same in the first 10 characters, you will see a series of similar field names which may be difficult to work with. For example, "Customer Name", "Customer Number", "Customer Notice" will become "CUSTOMER_N", "CUSTOMER_2" and "CUSTOMER_3". Information about sharing dBaseIV files: Approach does not create or maintain the native dBaseIV index file for a database. This is important if you plan to also use the database in an application that depends on the presence of this index. Approach PicturePlus fields cannot be viewed in other dBASE applications. #> Limitations of Approach (also see 'dBase IV limitations' in this FAQ) VIEWS: * maximum number of views (ie forms, worksheets, crosstabs, reports,...) per .apr = 100 * maximum of 5 pages per form type view for v96 and later; 1 page per form for v2.1 & v3.0* * maximum of 20 charts per .apr (see 'Maximum of 20 charts per .apr' article) * maximum of 20 crosstabs per .apr * Maximum number of summary panels in a report = 8 * maximum rows displayed in a repeating panel = 30 FORMULAS: * maximum number of characters in a calc field formula or find condition formula is 255 * maximum of 30 imbedded IF's in v3.02 (see 'IF limitations in v3.0*' article) JOINS: * maximum number of joins you can create between unique databases (that will be read-write) in one .APR file is 30. Any database joins you create after that will be read-only, up to a limit of 50 joins. * maximum of 450 characters in all the joined fields per .apr (but no limit to the number of actual joins). * circular joins are not allowed, but you can create an "alias" of a database and join it as appropriate. An "alias" is a "virtual copy" of the selected database. These joins count toward the other limits. * field types not allowed in a join are: Boolean, Memo, PicturePlus, Variable (these types are not displayed in the join dialog) * calculated fields cannot be used in a join unless they reference only fields in one database and constants, and if they are not summary type fields. MISCELLANEOUS: * maximum number of characters in a variable type field of type text is 254 * maximum number of fields used in a sort = 255 * maximum of 340 characters in the text area of a MESSAGE command in a macro. Note that you can type more than 340 characters there, but if you save the .apr file it will crash on opening. * maximum of 160 characters in a text string when using the SET command in a macro. This limit applies to all versions of Approach prior to v9.8 * maximum size of a string variable in LotusScript in v9.1 and earlier = 32,000 characters. In V9.5 and later it is limited only by your computer's available memory. USING APPROACH: * maximum number of concurrent users of a .apr file = 16 * Maximum number of dBase database tables open at once = 29 (Approach produces and error on opening the 30th) #> Maximum of 50 joins limitation There are no plans by Lotus/IBM to increase the number of joins allowed in a single Approach application file, which is currently 50. But I have rarely found that to be a problem in my applications. Here is my "approach" to a complex application with many potential databases being involved (per Sue Sloan): 1) I separate a complex application into multiple Approach files based on the "functions" of the application. For example, I might have a Customer.apr for customer record maintenance, an Invoices.apr for invoicing activities, a PO.apr for purchase orders and a Reports.apr for reporting. This functional split is logical in that most business processes can be divided up this way. And this keeps things simple for maintenance purposes because I can work on one .apr while the users continue to use the others, if necessary. 2) I try to stay under 15 unique databases joined per .apr so that I can still use "SaveAs" to save the application .apr file and databases to a new location. I do not worry so much about the total number of joins (that includes aliases), but I do try to avoid going over 30. 3) I provide navigation between the .apr files with a central menu.apr and macro buttons. I use the OPEN command in a macro to switch between them. If the .apr is already open, the user will be switched to the open file at the place they left it. The user can also switch between .apr files using the "Window" menu at the top of the Approach window. 4) I use local "control" databases (one per user on their workstation) to pass values between the .apr files when necessary. I limit these to one record each by having a field that is defaulted to 'X' and validated as unique and filled in. 5) To avoid having to log in separately to each .apr file, I either use my own login method or have them log in using Team Security to the menu.apr. I record who is logged in using the "control" database record so I can mark "last updated by" fields in the databases. 6) I consolidate databases that are solely for lookup purposes into fewer databases. In them I use a "type" field to filter them for building drop-down lists. I can set a variable-type field to use as the filter for each different type in the database. Or I can access them from LotusScript even if they are not joined in the .apr and build the lists that way. This is not an exhaustive list of ways to make the 50-join limit irrelevant, but the ideas here may help others with similar projects. #> .oyz index files If you find a file with a .OYZ extension/type in the folder or directory where your databases are stored (.DBF extension/type) this indicates that the .ADX (SmartIndex) file for that database is corrupt. Approach has created the .OYZ file to allow access to the database but the results may not be reliable. In fact, since the .OYZ reverts the affected field names to their dBase default length and format, your scripts may not work at all! And you may be asked to "map fields" when opening your .APR file due to the field name changes. To get rid of this problem, you need to delete the .oyz AND then either repair or delete/rebuild the matching .adx file. IMPORTANT: BEFORE YOU DO ANYTHING, make sure you read the following two articles in the FAQ: 'Deleting and recreating index files (.adx)' which outlines this procedure and implications in more detail, and gives more details about .adx index files. 'Repairing corrupt index (.adx) files' which outlines a widely affirmed method of rebuilding a .adx without losing any information. However, there is no guarantee that this procedure will work in every situation. #> Files and File Types File types are: .dbf = a dBase database file containing fixed length fields .dbt = a supplementary dBase database file containing memo fields .adx = ontains Smartindexes and information file created by Approach See FAQ articles 'Repairing corrupt index (.adx) files' and 'Deleting and recreating index files (.adx)' .oyz = a replacement index and information file created by Approach if the .adx becomes corrupt. See article '.oyz index files' .apx = an information file created by Approach when using Paradox database files. See FAQ article '.apx files' .mdx = an index file created by other database applications. See FAQ article 'Using index files other than .adx (eg. mdx)' File named like "Save49c6.apr" or "Savede40.apr" are temporary files Approach creates when saving an apr. Approach normally deletes them when the save is complete. If Approach crashes during a save they can be left behind but it's rare to see them. They aren't .apr files that can be opened by Approach. Attempting to open them will produce an "Internal Error 12345678" error message. You can delete them quite safely, but remember that there presence may indicate that one of your real .apr's was corrupted when your computer hung or crashed part way through a file save. #> Maximum of 20 charts per .apr The following was submitted by CRAVD01@aol.com and describes a method of getting around the maximum of 20 charts per .apr Create a subdirectory called MENU. Under MENU create a database called MENU_1. The database consists of only one field named JOB. Close MENU_1. Create a database called CHARTS_1. The database consists of only one field named JOB. Close CHARTS_1. Open a third database called CHARTS_2. It also contains only one field named JOB. Close CHARTS_2. Now, open MENU_1 and join to CHARTS_1 and to CHARTS_2 on JOB. Then join to your main database file and then to your other database files. Save the Approach file and close. Now, re-open CHARTS_1 and create a worksheet, etc. which will generate the first set of 20 charts from the data in your main database. Now, re-open CHARTS_2 and create a worksheet which will generate 20 more charts from the data in your main database. Now, re-open MENU_1 and create macros to open CHARTS_1 and its associated charts and CHARTS_2 and its associated charts. If you design the MENU_1 menu correctly, the user will not realize that you are jumping from CHARTS_1 to CHARTS_2 to go to various charts. You can continue to add CHARTS_3, CHARTS_4, etc. for an endless number of charts. The following was submitted by CRAVD01@aol.com, and describes a method for getting around the The trick is to be sure that when you go from MENU_1 to CHARTS_1 that you create a form with menu choices that will guide the user to the correct chart. Make the button macros choose which file to go to. If MENU_1, CHARTS_1, CHARTS_2 are in the same subdirectory, when you create macro buttons, select the OPEN command and edit the location of the CHARTS_1.apr as follows: change C:\MENU\CHARTS_1.apr to CHARTS_1.apr. This allows Approach to operate correctly even if you change drives where the programs are saved. If you leave the C:\MENU\.... in place, if you save to D:\ drive and then try to use the macro buttons, the system will tell you that it cannot find the C:\MENU\.... file. ###> Optimizing databases and minimising the chance of problems #> Optimizing the speed of a database Having the latest version of Approach on a suitably fast system with plenty of RAM (many suggest 64 meg), fast disk access, a large permanent swap file (ie. if you are using MS-Windows 3.1*. If you are using MS-Windows 95+ either make sure you have a lot of spare disk space (say 100meg or more) or that your virtual memory is set to 2.5 times the size of your RAM. Also on MS-Windows 95+: setting your file system to "server" instead of "desktop" can help disk access times), and fast disk caching will of course increase the performance of any large database. Defraging your hard disk regularly will help the performance of all of your applications, including Approach database. Also, make sure you regularly compress the databases. You may also what to carefully consider your database design. A badly designed database will perform poorly in any application. For instance, the more joins you have, and the more joined databases shown on any one form, the slower your database will tend to be. One way to speed up a bit database is to split complex .APRs into 2 or 3 smaller less complex ones where each .apr opens fewer tables. Also make sure you don't have a lot of unused forms, reports, macros and scripts cluttering up your database. Databases work slower with 'full record locking' than with 'optimistic record locking'. Minimize your use of color and graphics as these drastically effect the time it takes to update the screen. In order to maintain the best ratio of speed and stability you may want to consider deleting the .adx files (indexes) on a regular basis (say every week or two). There are some possible complications with this so carefully read "Deleting and recreating index files" first. Saving your database using the FILE/SAVE AS menu command using the copy data option achieves much the same thing, although it means that everything get a new file name. Delete excessive windows .tmp files. If this is a regular problem you may want to include the following statement in your autoexec.bat file: "del c:\windows\temp\apr*.tmp" If you are using Approach on a LAN or WAN, also see 'Running Approach on a network' in this FAQ. Wherever possible, use "numeric" data type as compared to "text". Suppose you have a part number that is literally all numbers, containing no alphabet characters, and the number string is 10 digits long. This field could be set up as a "text" field of 10 characters in length, or a "numeric" field of 12.3 (12 digits to the left of the decimal point and 3 to the right of the decimal point) or 10.0 (10 digits to the left of the decimal point and none to the right of the decimal point) characters in length. All of these options will index and sort fine, but by setting up the field as a "numeric" field of 10.0 characters, the index .adx file will be smaller and Sorts and Finds will be faster. Whenever possible, join database files on numeric fields. If numeric field joins are not possible, join database files on text fields with short lengths. Why? Two reasons. The total number of joins in an application is limited by the total of the lengths of all of the joined fields. The maximum limit for the total of the lengths of all of the joined fields is 450 characters. [Where did this number 450 come from? Answer: personal communication from an Approach developer.] Joining fields with shorter lengths will allow more joined database files to be included in the application. The second reason is that fields that are joined are always indexed. The .adx index files get large and inefficient when the joined, indexed, text field is long (over 10-20 characters). This will slow down searches and screen updates. [I am not sure that these details are correct.] Joined fields in different database files must match in terms of data type (such as, numeric or text) and must match in terms of length (maximum number of characters) for optimal and reliable performance. If the length of the joined fields is different, then the joins themselves can become unreliable and can become cross-linked so that the Unjoin function on the join map does not work. Big gains in the speed of Finds can obtained by using SQL queries. (see article 'Using SQL in Approach'). Conversely, doing finds, joins, or sorts on calculated fields may substancially reduce performance. I have no idea why, but some people have reported significant gainsin speed by setting the default sort on the database files so the last record added appears first. In other words reverse the order completely. Conclusions: Design Approach applications for speed by: 1) joining as few databases as possible in an application, 2) using 'optimistic record locking', 3) compressing .dbf files regularly, 4) deleting apr*.tmp files, 5) joining on numeric fields, 6) index on fields with short fieldnames, 7) joining on fields with the same data type and length, 8) consider using SQL queries on big Finds, and avoid doing finds, joins or sorts on calculated fields. Stuart Tucker substantially contributed to the articles 'Optimizing the speed of a database' and 'Deleting and recreating index files (.adx)'. #> Compressing databases with a macro or script First, read article 'Reducing ("Compressing") the size of a database file' in this FAQ. Since compression of database files (Dbase or .dbf type) may need to be done regularly it is a good idea to automate the procedure. You cannot do this with macros in Approach v2.01 and v3.0*, however you can achieve the same result with these versions by using "Recorder" that comes with MS-Windows (look in the main or accessories folders). The key strokes from v3.0* are: ALT T P TAB 5 which takes you to the compression and where you can select the files. (This paragraph was not reviewed by XpertSS.com because those older versions are no longer installed in our offices.) The rest of this articles applies to v96 and later: Here is a couple of examples: If you want to use a macro to compress a particular database then put the following into a macro: Up to v9.1: SendKeys ~%{F}UA{TAB 4}{RIGHT 4}{TAB}dbasename~{TAB 2}~ v9.5 and later versions: SendKeys ~%{F}UA{TAB 4}{RIGHT 3}{TAB}dbasename~{TAB 2}~ ... where dbasename is the name of the database, or at least the minimum number of characters of the name needed to uniquely identify it. The following script will compress one table (i.e. the first table in the list of databases): 'Up to v9.1: Sub CompressTables Sendkeys "~%{F}UA{TAB 4}{RIGHT 4}{TAB 4}~{TAB 2}~",True End Sub 'v9.5 and later versions: Sub CompressTables Sendkeys "~%{F}UA{TAB 4}{RIGHT 3}{TAB 4}~{TAB 2}~",True End Sub For every additional database the you want to compress, insert the one repetition of the following code into the script immediately BEFORE the {TAB 2)~: {TAB 7}{DOWN}{TAB 2}~ So, to compress four databases in v9.5 and later versions of Approach the script would look like: Sub CompressTables Sendkeys "~%{F}UA{TAB 4}{RIGHT 3}{TAB 4}~{TAB 7}{DOWN}{TAB 2}~{TAB 7}{DOWN}{TAB 2}~{TAB 7}{DOWN}{TAB 2}~{TAB 7}{DOWN}{TAB 2}~{TAB 2}~",True End Sub You can find out the number and order of the tables in your APR using FILE/APPROACH/FILE PROPERTIES menu item. If all this is a bit much, then you might want to consider purchasing DBFPack from http://www.XpertSS.com which does it all for you. #> Reducing ("Compressing") the size of a database file You may be able to significantly reduce the file sizes for your database depending on how your application uses your databases. This process is called "compressing" the database. But you may not see any change in the file sizes at all. Consider these two situations: 1) If you do not delete records from your database, there will not be any change in the .dbf or .dbt file size after compressing it. You will see a reduction in the size of the SmartIndex .adx file because all indexes not needed to support the current .APR file's joins will be eliminated. Approach will rebuild them when needed. 2) If you do delete records from your database, the records are only marked as deleted when you do that. They are not actually removed from the .dbf file. Therefore the .dbf is still the same size after you delete records. And any memo or PicturePlus fields are still in the .dbt, but the pointers to them are removed from the deleted record in the .dbf. To actually remove deleted records from the database you need to "compress" the database. This removes the records in the .dbf, the memo and PicturePlus fields in the .dbt, and unnecessary indexes in the .adx file. In v96 and newer releases, you do this in Approach by going to the File menu, User Setup option, Approach Preferences option, and then select the Database tab. Then choose the database file name that you want to compress and click on the "Compress" button. This flags that you want it compressed, but Approach does not actually compress it until you press "OK". If you want to compress several databases files, you need to select and click the "Compress" button for each one and then click "OK". You need to be the only user of a database when you do this. See article 'Compressing databases with a macro or script' in this FAQ to automate this procedure. Once a database is compressed, deleted records cannot be recovered (see article 'Recovering deleted records' in this FAQ). For this reason, it is highly recommended that you create a backup copy of your files before doing this. Are there other reasons for compressing a database? Yes! A compressed database is more efficient in its indexing which speeds up your Finds. And if you don't ever compress a database then it is more likely to develop index errors or corruption. Some report they never compress their databases and they run fine that way for years, however! #> Why doesn't the .dbf file size decrease when I delete records? This is because when you delete a record it is not actually erased from the .dbf file, it is just marked as being deleted and further access to that record is denied. To actually erase a record from the .dbf you need to delete it and then compress the .dbf. (Also see articles 'Reducing ("Compressing") the size of a database file', 'Compressing databases with a macro or script' and 'Recovering deleted records' in this FAQ) #> Good practices to reduce that chances of encountering problems MGood practices to reduce that chances of encountering problems Last updated: 23 February 2007 by XpertSS.com I. BACK UP YOUR FILES Make backups of all of your application's files (.APR, .DBF, .ADX and .DBT and other types of database files you may use) regularly. How often you do this depends on how much work you want to do in reentering data that is not backed up. For some applications, once a week may be sufficient. For other applications, daily may be OK. For "critical" applications, you may want to consider a "mirror" backup method that some server software offers where files are continually backed up as changes are made. Make sure your backup is "good". No one should be using your application during backup operations because the files that are "in use" may not be backed up, depending on your backup method or software. Check the backup to see if it will restore OK by restoring it to another computer or location and opening the APR files. Make sure you have multiple "generations" of backups in case your most recent backup contains a problem you cannot fix. For example, for a daily backup situation, you could have backups for each day of the week and reuse them over the period of a week. At least one backup should be stored off-site just in case your office suffers a disaster and you need to continue operations elsewhere. Online storage facilities are also available that offer security and ease of access to backups. Specific backup and online storage solutions will not be offered in this FAQ. II. CLEAN UP YOUR HARD DRIVES Most Windows applications, like Approach, create temporary work files in your designated temporary file folder. These files are usually of type .TMP or .~MP with a random name. When an application is closed, it should delete all of its temporary files, but this does not happen when the application does not close normally, when Windows itself crashes, or other interruptions occur. The problem is that a folder on your hard drive cannot contain an unlimited number of files. If this limit is reached, things do not work very well. Another problem specific to Approach is that those temporary files may be misinterpreted as current data files, causing various operational errors. So you should regularly go into your systems (all user computers will have these) with all applications closed, find those files and delete them all. Note that holding down the Shift key when you press the Delete key bypasses the recycle bin! o In older versions of Windows, these temporary files were usually in C:\TEMP or C:\WINDOWS\TEMP. o In newer versions of Windows, these temporary files are stored in C:\Documents and Settings\username\Local Settings\Temp Regular use of Scandisk and Defrag utilities will also make sure your hard drives are in good condition. There are software packages that will clean up temporary files and perhaps even keep your "registry" clean, but those will not be offered in this FAQ. III. SAVE YOUR WORK OFTEN WHEN DOING DESIGN WORK When switching between design and browse frequently, get into the habit of periodically saving your work, then closing and reopening your application. This is especially important when modifying field definitions or joins, and when working with macros and scripts. Doing this will ensure that if something does go wrong you will lose the minimal amount of your work, and it also give Approach a chance to release system resources and refresh its links, indexes and graphics and start afresh. Develop a practice of saving your APR file(s) such that you have at least 2-3 copies of the file saved with different names. I use something like Ordersdev001.apr, Orderdev002.apr, etc. for an APR that in production is named simply Orders.apr. During each restart of development per the above paragraph, copy the just closed APR file into another folder and rename the one you are working on. Keeping a log book of changes you are making is also a good practice, and you can note the APR names at the points in which you create them. If you are a bit forgetful about periodically saving your work, then you may want to consider adding the following line to the current script you are working on so that your changes will be automatically saved each time you run the script (don't forget to remove it once you finished developing that script): Current.Window.SaveChanges The only caution about the above is that sometimes Approach appears to delete all of its scripts during testing them. And if you script does not run to completion, this statement will not be run. Therefore it is recommended that you not do this and instead merely use the script editor's File, Save Scripts after each change in them. This has the added advantage of recompiling your scripts and telling you if there are errors in them before you try another run. IV. MINIMIZE PROBLEMS IF YOUR INDEXES ARE CORRUPTED NEED TO BE DELETED When naming fields, long field names are easy to read, but if you ever need to delete your index files (.ADX) you will have a lot of work to do to update all of those names. Deleting the index reverts your field names to the dBase standard which is: o Maximum of 10 characters o Underscore, alphabetic and numeric characters only (no spaces) o Must start with an alphabetic character Therefore if you ever need to re-map the fields names after deleting your .ADX file, they will all match except for "time" type fields. Approach modifies the stored field name for this type so it can distinguish them from "text" fields because there is no "time" field type in dBase. For example, you have a time field named ORDERTIME which will be modified to ORDERTITM9 where the "TM9" tells Approach it is a "time" field. This is also a good reason to not use a field name that ends with "TM9". Instead of deleting index files, it is recommended that you keep a set of those .ADX files that are current to the field definitions in use. Then if your .ADX is corrupted, you merely replace the bad one with your copy and update any serial numbered fields next number value. This will preserve your long field names too! V. BATTERY BACKUP FOR YOUR USER COMPUTERS AND/OR SERVER It is a good idea to have battery backup devices on the power for all of your computers (and monitors) that use Approach as well as your server, if any. This is good for your computer because it is protected from power surges and you will have some time to shut down the computers normally. The main problem with power failures is that any write operation in progress to the hard drive may end badly -- writing out only part of a file or writing over other files! VI. MISCELLANEOUS Never delete a macro or global script. Just rename ones you no longer need to something like zobs1, zobs2, etc and reuse them for new macros or scripts. Deleting them in most releases of Approach will modify the macro/script used in MESSAGE and RUN commands! Don't type field or database names into formulas or text blocks. It is far more reliable to select them from the field name lists provided in field properties or in the Text Object, Insert, Field Value dialog. Apart from the possibility of making spelling mistakes, typing in field names can cause Approach odd behavior. For example, in a text block, a field may suddenly switch to a time format! (which may cause you to behave oddly...!) If Approach starts "acting strange" when in Design mode, you may be experiencing a resource shortage. You should then exit all other Windows applications to free up memory and resources to stabilize things while you save your work. You can use the Windows Explorer to copy the APR file you are working on to another folder before you save the current version, just in case the current version is damaged in some way. Then restart the computer before continuing your development work. #> DON'T delete macros, named find/sorts or scripts... DON'T delete macros, named find/sorts or scripts! Deleting things is a primary cause of .apr file corruptions. Instead, just rename them to "unused1", "unused2" and recycle them when you need a new one. Sue Sloan writes: In A96 and later, three corruptions occur in the apr when you delete a macro. If you aren't doing these things then you won't notice adverse effects: 1. All Run commands in macros that run a LotusScript sub are corrupted. The first one runs a blank and all the others run a different sub. Each time a macro is deleted they are shuffled round again. 2. All Message commands that specify two buttons, where the buttons run macros other that **STOP** and **CONTINUE**, are corrupted. They all run different macros after a macro is deleted. 3. The first time a macro is deleted in an apr all existing and future custom menus are affected. Any macro created subsequent to the first deletion won't run from a custom menu. This is irreversible. This was partially fixed by Lotus in the newest releases of Approach (v9.5), but not 100%, so we are still recommending that you do not delete macros or scripts. #> Backing-up your data using a macro You have two options for doing this. One is a create a macro that exports all of the data that you want to backup to wherever you want it backed up to. However, this won't backup your .apr's. To backup everything including your .apr's create a DOS batch file like the one below (a batch file is a plain text document which has been saved with a .bat file extension instead of a .txt, and which contains DOS commands): cd c:\backup copy c:\mydata\*.dbf c:\backup copy c:\mydata\*.adx c:\backup copy c:\mydata\*.dbt c:\backup ... you will of course have to customise this to the hard drive and file paths of your data and backup location. The run this batch file using the OPEN command in a macro. ###> Corrupt index (.adx) files #> .apx files .apx files are used by Approach when working with Paradox database files. They contain Auto Increment Numbers and OEM or ANSI settings. #> Repairing corrupt index (.adx) files (This widely affirmed procedure was submitted to the Approach Users Mailing list by Jerry Sikes, Unisource Converting, and has been update from later suggestions that he has made.) 1: Get exclusive control of database files. This means that no-one other than yourself has the database open in any application. 2: Create a directory named "Safe", or "Backup" or whatever is meaningful to you. 3: Open each critical database, one at a time, as a new application with Approach. A default form and worksheet will be created. 4: Run a find that gives you only 1 record in the found set. (Use Hide if necessary) This will create a minimal index and 1-record database when you do the next step. 5: Export the "found set" to the safe directory, using the same database name. (Hint when Approach exports to this new directory, it creates a new one record index) 6: Close the new application without saving. (Optional...I do not normally save these since Approach can recreate this at will) 7: Repeat for all targeted tables. The new safe copy indexes store the Long Field Name format that Approach uses, and the starting serial number for fields where that option is used. If you need to "uncorrupt" an index: 1: Get exclusive control of that database's files again. 2: Copy the safe adx file back to the working directory. 3: Reopen your application that uses the database and Approach should immediately launch into a "Smart Index Creation" mode. If not, do a "compress" of the database to force the reindexing. 4: If you are using an old safe copy of the .adx file for a database with auto serial numbers, then you WILL need to manually reset the next serial numbers to the correct values. It is important that you maintain a good revision control method. If you add fields to your working table, update the "safe copy" by exporting the 1 record again. Using an out-of-date index with an updated database structure could damage your data! NOTE: Some people recommend that you compress your databases often as a corruption prevention method. XpertSS.com has not found this to be necessary or advisable unless you delete many records from your database and need to reclaim the space they are using in the files. It is more important to discover and fix the problems that caused the index corruption in the first place. Some things that are helpful are: * Having backup UPS battery devices on your server and all workstations to prevent a power failure from interrupting data transfer over the network or writing incorrectly to your hard drive. * Making sure that your validation rules prevent the "one" side of a join from accidentally becoming a "many" by validating join fields on the "one" side as both filled in and unique. If you use more than one field in a join, add a real field to that database with a modification formula that combines the join fields into one string and validates it as unique. * Be very careful when importing records into databases. The Import Data process ignores your field validation rules and will let you import duplicate values into unique-validated fields. It also invalidates the database index which forces a reindex cycle that will impact user access to that database until the import has finished (locking messages, SmartIndexing messages, etc). TIP: No amount of index backups will help if your database (.dbf and .dbt) becomes corrupted. Making regular backups of the entire set of files on a regular basis and storing them either in a fire-proof safe or off-site is highly recommended. And please, test your backup files to make sure they are OK and will restore when needed! Current technology makes backing up to CD/RW very simple and inexpensive, without resorting to compacted files on unreliable media like tape drives. #> Deleting and recreating index files (.adx) In order to maintain the best ratio of speed and stability, you should consider either deleting the .adx files (indexes) on a regular basis (say every week or two) or compressing the databases. Alternatively, you can use the .adx repair procedure (see 'Repairing corrupt index (.adx) files') which preserves some of the information in the .adx, but may be a more involved depending on the design of your database. Why is database/index maintenance recommended? 1) The SmartIndex files for dBase databases in Approach are built up over time to support your joins and finds. This can result in bloated index files -- sometimes they can be larger than the database (.dbf) file they are supporting! - When an .apr file is opened, Approach will make sure the indexes required for the joined fields in that application are current. - Subsequent "finds" add indexes as needed to support them, and they are not deleted even if the find is never to be done again. 2) You suspect that an .adx file is corrupted. For example, a find gives you invalid results or a repeating panel that should show records does not show them. Deleting the .adx file will get rid of the fault, but perhaps only temporarily if you have an illegal many-to-many join that is causing the problem. 3) Deleting records from your database does not delete them from the .dbf and .dbt files. The space is merely marked as "deleted" and excluded from subsequent display. The only way to reclaim the space is to compress the database. 4) Unnecessarily large database files take more time to transfer over a network, and more time to execute finds and sorts. 5) If another application (say Paradox, or Access, or something) adds or updates records in your database, the Approach index will not be correct. NOTE: It is always a very good idea to do a full back up before doing any maintenance on your databases or indexes! How do I compress a database? Compressing your databases is preferable to deleting the index files because it preserves your long field names and serial numbered field settings. To compress a database, you use the File menu, User Setup, Approach Preferences sequence to display the Approach Preferences dialog. On the Database tab, select a database name, click the Compress button, and repeat for each database you want to compress. Finish with the OK button, which actually starts the compression process. (Also see articles 'Reducing ("Compressing") the size of a database file' and 'Compressing databases with a macro or script' in this FAQ) How do I delete an index (.adx file)? Before you delete the index files, there are some possible complications from doing this that you should be aware of: 1) If your Approach database field names do not adhere to the dBaseIV standards, you will find your field names changed to fit that standard. - The default dBase IV format is a fieldname written in all capital letters, with a maximum fieldname length of 10 characters as a combination of 10 letters, digits, and underscores. - The first character must be a letter. - Punctuation marks, blank spaces, and other special characters are not permitted. - Field names that are similar, such as BILLAMOUNTDUE and BILLAMOUNTPAID will become BILLAMOUN1 and BILLAMOUN2, which can make mapping these names to the originals in your .apr file difficult. 2) The .adx contains what the next number will be when automatically incrementing a serial numbered field. So, if you delete an .adx file for a .dbf that has a numeric field containing an auto - incrementing serial number, then the serial number will be reset to 1. You will therefore need to manually reassign the correct next record number in the field definition options. To delete an .adx file, you should know how to navigate your hard drive or network drive using File Manager or the Windows Explorer. Go to the folder or directory where your database files are stored and you will see sets of files for each database. The set of files will all have the same name with a different type. For dBase files there is always a type .dbf where your records are kept, optionally a type .dbt where memo and PicturePlus fields are kept, and the .adx file. You can simply select and delete the .adx file for the database you are performing maintenance on. Approach will automatically rebuild the indexes when you reopen the application that uses it. Conclusion: If you only use dBase IV format fieldnames and if you do not use any auto-incrementing serial numbers and if you do not manipulate the .dbf file with another application, then you should not suffer any side effects when deleting a .adx. ###> Errors, lockups, crashes, and other problems #> General Protection Faults (GPF's) If you are running v3.00 then upgrade to v3.02. It's free, and it will save somebody posting to the list telling you to upgrade because v3.00 is full of unwanted little surprises! See 'Free Approach 3.02 Upgrade' If it might be something to do with printing then see 'Printer problems (including GPFs, HP Printers)' If it might be something to do with the display then see 'Display problems (including problems switching to a particular form)' Search the IBM's Lotus Approach support web site (http://www-3.ibm.com/software/lotus/support/approach/support.html) for the program involved in the error (eg krnl386.exe, or krnl386.exe module 0001:0ec9) and see what comes up. NOTE: search the Knowledge Base, which is a different thing than just doing a site search - they are different things. Despite what Lotus says, creating reports with more than 8 repeating panels will cause GPFs (still occurs in July 1997 update of Approach 97). So if you have more than 8 that may be your problem. A lot of GPFs are cleared up by repairing or deleting .adx files BUT make sure you see 'Repairing corrupt index (.adx) files' and 'Deleting and recreating index files (.adx)' first, otherwise you may find you create a few other problems as well... Some GPFs may be associated with corrupt .apr/.vew files (eg if it only happens when changing to that particular view). See 'Repairing corrupt .apr/.vew files'. If you get the GPF in Design mode, then try switching 'Show Data' off, especially if you have a lot of calculated fields. If this doesn't work you could try reinstalling Approach, especially if the fault has appeared just after installing some other new software which may have overwritten some .DLL's in the windows/system directory. If at first this doesn't work, try unistalling Approach first, and then reinstalling it from scratch. Otherwise try buying a new computer and then installing Approach ... ;-) just kidding! It might also be worth testing Approach while there is absolutely nothing else running, and if it works introduce other applications and utilities that you normally use to see if the conflict is particular to one of them. GPFs can sometimes be caused by having duplicate copies a DLL's in the Approach, WINDOWS or WINDOWS/SYSTEM directories. Fontmod.dll is a known culprit. If you have a duplicate .dll then Approach's version should be copied into the Windows directory. Other copies should be removed. However, be careful, different version of Approach or other applications may require different versions of that .dll. It is probably best to keep old copies in a temporary directory that is not in the search path (see the autoexec.bat file) until you are sure you don't need then. #> Repairing corrupt .apr/.vew files (e.g. errors when changing views) If your application suddenly becomes unstable while you are working in Design Mode on it, you may see crashes simply changing views, strange views with objects from several views mixed together on them, error messages, etc. At that point, you should NOT save the Approach file yet, if you are even able to do so. Consider the following advice from experience with many unfortunate situations I have encountered over the years. :>( If you have not made many changes since you last saved the Approach file, just close the APR file without saving it and open the prior copy to see if it is OK. Then recreate the changes. But if you have not saved your work and it would take considerable effort to recreate it, or the prior saved copy is similarly damaged, you may want to try to salvage the APR file. Here is how to proceed: * First, make sure you have a backup copy of the .APR file from the last time you saved it. You can use the Windows Explorer to copy that file to another folder for safekeeping and then try saving your current .APR file. Then reboot the computer. This may be all you need to do to relieve any shortages of memory or other system resources. * Open the APR file and see if it works correctly now. If not, try using the File menu, Save As option to another directory to make a new (hopefully error free) version of the .apr and database files. * If you still have problems, and you can get into design mode, try deleting bits of the last changes you made to see if the problem disappears. It would probably be best to start with things such as text blocks. Sometimes deleting entire views, like form letters in particular, will help. If you cannot get to a view without a crash, try turning off "Show Data" under the "View" menu while in design mode before switching to the view. If you reach a stable point, save the APR file and redo your changes from that point. Review your named Find/Sorts for missing conditions which can happen if you use "Query by box". Delete these and create new ones, and fix the macros that are impacted. * If you still haven't managed to fix it, try creating a new .apr with all the exact same databases and joins, then import the old APR into it. Note that scripts are not imported so you would need to copy those over manually. If all else fails, you probably have to simply recreate everything from scratch (using your data (eg .dbf) files of course). But you should never get to this point if you follow good development practices. In particular, you should never save an Approach file over itself without having a backup of it prior to that save. And it is a good practice to use SaveAs often giving the APR file a different name such as myapr_dev01, myapr_dev02, etc. Finally, consider the possibility that the problem or error you are seeing is caused by a corrupt database index. This can cause missing records in repeating panels, Finds that do not find the right records, crashes switching to a view of that database, etc. Try your current APR file with a backup copy of your databases to see if the problem goes away! If so, there are other FAQs on this site that can help you with database and index corruption if you suspect that is the problem. #> Out of Memory error message First, careful read through the article 'Optimizing the speed of a database' for tips on how to get you database running as sleek as possible. Also, remove anything that might be unnecessarily using memory, such as unused forms, worksheets, reports, macros that are no longer needed. Check the manuals for your operating system to make sure your system configuration is making optimum of your memory. For instance, if you are using MS-Windows 3.1 and DOS, check that your EMM386 (probably should be set to NOEMS), and Upper Memory Blocks (UMB) are properly configured and utilized. #> "Record is locked- retry -cancel" error message Sometimes a shared Approach database repeatedly returns a "record is locked- retry -cancel" error message, even though the database has been set to optimistic record locking. This can occur when the link to the network drive where the data and view files are held is down. In this situation you need to exit Approach, reestablish the link to the network drive (usually by rebooting your workstation), and reopening the database in Approach. It will also occur if a user does a search that causes a new index to be created. Everyone else will receive a "locked" message until the indexing is completed. And, of course, if you have a lot of users and they often attempt to work on the same records then they are going to frequently get record locking errors. It can also occur for a variety of other more obscure reasons. Some things that have been suggested to keep these at bay are: * delete excessive apr*.tmp files created by Approach. If this is a regular problem you may want to include the following statement in your autoexec.bat file: "del c:\windows\temp\apr*.tmp" * keep the users system clocks within a minute or so of each other. Locking can only work properly if all PCs are synchronized. For example: 10:00:00 User A locks a record 10:00:01 User B locks another record 9:59:59 User C (whose time is not synchronized) tries to access User A's record, which is not yet locked because it isn't 10:00:00 yet. Ooops. Get the network administrator to set up the network to synchronize the PCs clocks. * try compressing the database, and if all else has failed try deleting and recreating the .adx files. See articles 'Deleting and recreating index files (.adx)' and 'Repairing corrupt index (.adx) files'. * put a blank record as the first record in the database. This record must be devoid of any join relations. ( don't know what this does, but apparently it can help!) #> "Someone locked this record" errors This error generally means that either someone is updating a record, or if a smartindex is being created. If your a single user and this error suddenly starts appearing, there may be something wrong with the database. Try compressing it, if that does work, try deleting the index files (.adx), but make sure you read articles 'Repairing corrupt index (.adx) files' and 'Deleting and recreating index files (.adx)' first. Otherwise, it could be because the clocks in your server and workstation are not synchronized. This can cause Approach to rebuild the smartindexes more often than really necessary, making a clash more likely. Check this before doing anything else. In the end, the faster that a process can run the less likely a clash will occur. So you might want to consider speeding up your network. Processes such as finds, sorts, and reports can be initially sped up by running a comprehensive find on the database tables before users get access to them. This forces Approach to index the database files which speeds up processing. Do this immediately after creating or compressing database files. Other things you can consider are: * making the databases read-only to the users. * create and use a separate copy of the database to run reports #> "Unable to open ___.dbf file, 5009" errors Approach displays this error message upon opening an .APR file if: * The user has mapped the application's database folder to a different drive letter on their network server than the one mapped by the application developer. * The drive letter used by the developer is not mapped to anything on the user's computer. Example 1: A developer puts databases on H:\mydata and shares that folder on the network. User A opens the Windows Explorer and maps the shared "mydata" folder as "R". The user has no F drive assigned. On opening the .APR file, the -5009 error message occurs. Example 2: A developer is working on the server and puts databases into C:\mydata and shares that folder on the network. User A opens the Windows Explorer and maps the shared "mydata" folder as "G". On opening the .APR file, Approach looks for the folder on C and gives the user an opportunity to substitute databases. If the user is allowed to do this substitution and save the .APR file, the developer on the server will get a -5009 error the next time the .APR file is opened if no G drive exists on the server. It is important to an Approach developer whose application will be shared over a network to plan for this situation and insist that the users of the application all map the shared drive to the same letter. Since many computers today have CD drives and perhaps other drives, it is recommended that the shared drive letter be above "F" to avoid conflicts. If you can open the .APR file, go to the FILE / APPROACH FILE PROPERTIES menu and you will see a list of all the files associated with the application and the complete path to them. For dBase databases, only each .dbf file is listed, but the .adx and .dbt files must be in the same folder as their .dbf file. #> "Macro error: Import table has changed" error You have a macro with an Import command that has the incoming file and field mapping predefined in the macro. Suddenly you get a message "Macro error: Import table has changed". In general, the error is telling you that there is no longer a match between the file to import and the target file being imported into. What are the possible reasons for this problem? 1) You changed the definition of a real field or added/deleted a field in the database you are importing into. (This does not include variable or calculated type fields, which are not in any database) 2) You changed the content/format of the file you are importing. 3) You have a corrupt database index (.adx file) on the database you are importing into. (People have reported getting this error and discovering that all their field names have reverted to upper case and have been truncated.) If your situation is caused by a change in the database or incoming file format/definition, you can correct the macro by editing the settings in the Import command. If your situation is caused by a corrupt index file, there are two other articles in the FAQ that can help you: * 'Deleting and recreating index files (.adx)' which outlines this procedure and implications in more detail, and gives more details about .adx index files. * 'Repairing corrupt index (.adx) files' which outlines a widely affirmed method of rebuilding a .adx without loosing any information. However, there is no guarantee that this procedure will work in every situation. #> Internal Error: Cannot load string 0 This error is generated when more than 16 users try to access the same .apr at the same time in v3.0* (v95...?). In order to get around this, duplicate the .apr, and divided your users across the new .apr/s. All the .apr/s can use the same database files. #> "Could not load infobox dynalink" error This may be caused by not having done a network install of Approach on the desktop you are using to link it to the Approach executable on the network. To fix this, reinstall Approach on the desktop, making sure that you do a network install. (also see 'Running Approach on a network' in this FAQ) #> InfoBox, Tools Palette, etc... won't appear This may be because the InfoBox has been moved off the edge of the screen. Carefully have a lot around to see if you can find it. If you can't find it then you may need to manually edit the location of the InfoBox. In v3.0* the infobox location is stored in the APPROACH.INI file in your Windows directory. Set the location to 10,10 then restart Windows. In v96 and later the location is stored in the Windows Registry. This must be edited very carefully. If this does work the you probably need to reinstall Approach. #> "Page Fault... at 0137:0049eb64" in Approach 96 To avoid getting "APPROACH caused an invalid page fault in module APPROACH.EXE at 0137:0049eb64" errors when entering new records in Approach 96, turn off the "In Field" option. #> Approach 3.02 crashing in design mode and when switching views A different times people have reported that this is due to the fontmod.dll file in the Windows System directory being replaced by a new installation of some other program (e.g. Quickbooks). To fix this just replace the new copy of the fontmod.dll file in the Windows System directory with Approach's version found in the Approach directory. #> "An error has occured in your program" errors If you get the following error: "An error has occurred in your program. To keep working anyway, click Ignore and save your work in a new file. To quit this program, click Close. You will lose information you entered since your last Save." ... just follow the instructions. Apparently if you hit Ignore enough times ("A couple of hundred" according to one person?!) Approach generally gets the message and continues on. Just save your work, exit approach, do a cold boot (i.e. turn your computer off and turn it back on), then recommence your work. Often that is all that is required. #> Database being used exclusively error One possibility is to go to the FILE/OPEN dialogue box, select the dBase (.dbf) file format, then click on the SETUP button. You can then set the options regarding database sharing on the network. Make sure you have 'share' or 'vshare' installed. Your autoexec.bat should have a line that looks like: C:\DOS\SHARE /F:8192 OR, the [386Enh] section of your system.ini should contain: device=vshare.386 or device=*vshare If you have a file named APR.V30 in your Approach directory, rename it to something else. It tells Approach that it is a stand-alone version and that it should open all databases exclusively regardless of other settings. If you have a "sdBaseFileSharingMethod=Approach." in your approach.ini file, try replacing it with with "idBaseOptApproach=1". You do have to have a line in your approach.ini that reads "sdBaseFileSharingMethod=DBASE4" or "sdBaseFileSharingMethod=DBASE3" or some other file format. Make sure that all users have this parameter set the same. Of course if all else fails, you can always revert to deleting every mention of Approach on your computer/s and re-install from scratch... #> "Internal Error - Cannot load string - 1035." error message Make sure you are running 3.02 and not 3.0 as this error is related to one of the main bugs in 3.0 to do with the Spell Checker If you are using 3.02 you possibly have a corrupt .dbt file which contains your mem/picture plus fields. If you can, delete the offending .dbt file and restore from back up. Otherwise, their are other solutions available by searching the lotus support knowledgebase at http://www-3.ibm.com/software/lotus/support/approach/support.html #> "GPF in APPREXPR.DLL at 0009:0D2C." error message This is an Approach v3.0* error message indicating a corrupt index (.adx file). Try compressing the database first, otherwise you will need to delete the .adx files. You should probably also check to see if you have any .oyz files and get rid of those as well. NOTE: read articles 'Deleting and recreating index files (.adx)' and 'Repairing corrupt index (.adx) files' before deleting the .adx or .oyz files! For compressing, see article 'Reducing ("Compressing") the size of a database file' #> Vanishing scripts This article was submitted by Paul Bent (Northwind IT Systems): The script editor may become unstable while you're developing and testing code, particularly if its been open when you've been testing forms as dialog and/or stepping through with break points. I've seen very strange things happen including disappearing scripts. This is my bomb proof method for not losing work!! I do these three things every time I make code changes and BEFORE I test them. 1. Press F2 to test compile global code. 2. Press Shift + F2 to test compile object event code. In A9.5, if Shift + F2 does not display a no errors message then close Approach immediately, don't try and save changes. After Approach has closed an Approach message box often appears!! - "Error 160, Unknown class of product object" - OK it and reboot! You see this one quite often if you run macros from scripts and vica versa. 3. Save As to an incremental file name (never save the apr over itself), close and reopen the apr. I run a full unattended backup of my server each night. In the morning I delete all the incremental versions except the last. #> "Could not find database [path]\name.mdb" error An error message "Could not find database [path]\name.mdb" is sometimes encountered when opening 32 bit ODBC data sources. This can happen with the second and subsequent mdb's you try to open. The solution is to select file type ODBC Data Sources each time, followed by the MS Access Driver folder. This will initiate a new "select mdb" procedure and bypass the bug that causes the "could not find..." error. #> "couldn't open database because it is open in another language..." This is a network problem that occurs if different computers accessing your database files on the network have different languages set in the "Regional Settings" section of the Control Panel (accessed from Settings on the Start Menu). If the language is set correctly on all the computers, try changing it so something else, exiting Regional Settings, then, going back in and resetting it back to what you want. Also check the currency and date settings are all the same while you are there, because these can also cause problems. #> Globals Sub "Initialize" doesn't always get executed The has been some disagreement on the list about this. Some people swear it works perfectly all the time, others seemingly have frequent problems. Whatever, here is a summary of what has been said: Paul Bent writes: Initialize should execute when the apr is opened. Say you want to call a logon procedure, check the registry, call API functions to get system parameters (eg short date format) initialize variables etc etc. Not much use if this only happens when the user first clicks a button (say); they could have been working in the apr for any length of time already. It isn't a good idea to put Initialize code in DocumentOpened or OpenWindow events or it will execute every time these events fire instead of just once when the apr opens. To avoid this you need to hard code the apr name in the event script which will cause it to fail if the apr is renamed. However, putting a single comment character in OpenWindow works around the Initialize problem thank goodness! Conversely, David Legge writes: The initialize sub will only run when (just before) the first bit of code gets invoked. I suppose there is no need to run it if no other code ever gets run! If you want a code to run when a doc is opened, (the script equivalent of the Open macro) then place it in the openwindow event of the Documentwindow object in your file. (BTW If you have anything in Sub initialize it will also then run - because the Openwindow event is triggered) The Sub Initialize is also run if you have edited code in the IDE (again only when the next piece of your code is invoked) So placing "documentopen" initialisation in Sub Initialize can confuse you when editing your code. You will find Documentwindow is the last item in your list of views in the Object: list in the IDE. You have to expand yourfile object above the Approach objects to see it. Unlike Paul, I think Initialize is now working correctly! ###> Printing #> Printing formatting problems Also see 'Printer Problems', 'MS-Windows 95 printing blank pages (v2 & v3)', and 'Header / Footer problems in v2.1' in this FAQ If you are missing edges of pages, first check the printer setup in the printers section of the MS-Windows Control Panel. Also, in design check that all of your page boundaries are set correctly. Approach will not use the resident fonts in the printer. #> Printer problems (including GPFs, HP Printers) A simple thing to try is to select the default printer in the printer setup (evening if you are currently using it), and then back to whatever set up you want. This ensures that the current set up is correct. Then, download the latest drivers for your printer. Search your disk drives and remove all old versions of the printer driver before installing the new one. If you are using Approach on a network make sure all the drivers have been removed from the workstations and install the new driver on the server for network printers. If this doesn't fix the problems, search the Lotus technotes for tips and solutions concerning your printer. If that doesn't help, contact the technical support people for your printer to see what they have to offer. Searching for their web site is a good place to start as they probably have FAQs and the latest drivers there. Note: You may get differently results from different versions of Approach at the same time, so for consistency its best to stick to using one version. And just in case your wondering, for everybody that says that Approach doesn't work well with HP printers there is somebody else that says they use a variety of HP printers and never have a problem... Go figure! However, if you are having problems here are some work arounds that have been suggested: * if you are using MS-Windows 3.1 try updating to MS-Windows 3.11 (or later), and make sure you are using the latest drivers. This seems to solve some problems. Similarly with MS-DOS, if you are not using MS-DOS 6.22 then perhaps you should try it (with the latest drivers of course). * if you design a report for a 300dpi printer and then later switch to a 600 dpi you will probably get clipped text. One suggestion is to use a macro to set the printer to 300dpi and then print the report. Otherwise you could simply recreate the report for the 600dpi printer. * you could also try using current drivers for older models. Some suggestions are: if you are using a HP4, try using a HP3 driver; if you are using a HP Laserjet 2100M try using a HP Series II driver from the Windows CD. You never know, it just might work!? #> Header / Footer problems in v2.1 People have experience problems where the top or bottom half of the footer or header line is cut off in v2.1. The easiest way to get rid of this type of problem is to recreate the report from scratch - this is likely to be quicker and easier than spending to much time playing with your current one. 1) set the printer setup to the correct values 2) create a very simple report using all the default values. Just specify a couple of fields from the database the report is based on. 3) immediately insert and set up the footer and header as required. Do a couple of test prints to make sure it is right. 4) finally, set up the report contents the way you want it - insert further fields, do formatting etc... #> MS-Windows 95 printing blank pages (v2 & v3) To stop Approach from printing out a blank page after every printed page in Windows 95, make the following change to your WIN.INI file: Under the [Compatibility] heading change 'Approach=0x0004' ... by putting a ';' in front of it so that it reads ';Approach=0x0004'. Then save and reboot. A side effect of this is that it effects the printing of field definitions and macros. Lotus recommends using either a Win 95 PostScript driver, or an older Win 3.x driver. Look for Document#132676 on the Lotus web site. http://www.lotus.com NOTE: The problem will recur if you reinstall Approach or over write the WIN.INI file with an older version. If this happens then repeat the process #> Printing field definitions Just choose the print option on the Field Definitions screen. However, this won't work if you have the "Approach=0x0004" line commented out in your win.ini file (to prevent v3.02 on Windows 95 printing an extra blank page). To get it to work you will need to remove the semicolon and then reboot for the change to take effect. #> Printer fonts problems Approach will not use the resident fonts in your printer. Having more than 200 fonts installed on your computer can cause invalid font substitutions in Approach. #> Pages sizes in v9.6 v9.6 does not pick up the paper size from the printer. All views change to Letter size unless another size is selected in Page Setup and the file is saved in v9.6. Furthermore, new and duplicated views are default to Letter size. ###> Dates and times #> Calculating elapsed time Time is stored as a number starting at midnight, incrementing in 100'ths of a second. So as long as your time does not start on one day and end on another, you can simply subtract the timeout from the timein and divide by 360000 to get minutes. (100 * 60 * 60) = 360000 The following formulas have been suggested to calculated elapsed time over the 00:00 boundary: Either: ((Trunc(FinishDate) + (Trunc(FinishTime) / 8640000)) - (Trunc(StartDate) + (Trunc(StartTime) / 8640000))) * 24 Or: ((24 * (Date_expire) + time_exp))-((24 * (Date_ent) + time_ent)) #> Calculating ages from birth dates The following formula produces a line of text e.g. "Age: 32 yrs 6 mths". If the PEOPLE.BIRTHDATE is empty them it produces an empty text string i.e.."" If(Isblank(PEOPLE.BIRTHDATE), '', If((Month(Today()) - Month(PEOPLE.BIRTHDATE)) < 0, Combine('Age: ', (Year(Today()) - Year(PEOPLE.BIRTHDATE) - 1), ' yrs ', (12 + Month(Today()) - Month(PEOPLE.BIRTHDATE)), ' mths'), Combine('Age: ', (Year(Today()) - Year(PEOPLE.BIRTHDATE)), ' yrs ', (Month(Today()) - Month(PEOPLE.BIRTHDATE)), ' mths'))) The next formula just returns the ages in years and increments on the exact birthday: If(Month(Today()) < Month(PEOPLE.BIRTHDATE) or Month(Today()) = Month(PEOPLE.BIRTHDATE) and Day(Today()) < Day(PEOPLE.BIRTHDATE), Year(Today()) - Year(PEOPLE.BIRTHDATE) - 1, Year(Today()) - Year(DOB)) The last forumla gives you the persons exact age in days. You can then roughly calculate how many years and months, but since months and years are different lengths the answer is an approximation, give or take a few days: If(isblank(PEOPLE.BIRTHDATE),'',Trunc(((today()- PEOPLE.BIRTHDATE/365.25),0)) #> Calculating number of weekdays The following formula will return the number of weekdays between the dates contained in DB.STARTDATE and DB.ENDDATE: If(Year(DB.STARTDATE) <> Year(DB.ENDDATE),DB.ENDDATE - DB.STARTDATE - (WeekOfYear(DB.ENDDATE) + (Year(DB.ENDDATE) - Year(DB.STARTDATE) - Year(DB.STARTDATE)) * 52 - WeekofYear(DB.STARTDATE)) * 2, DB.ENDDATE-DB.STARTDATE - (WeekofYear(DB.ENDDATE) - WeekofYear(DB.STARTDATE)) *2) Another method use two formula: TotalDaysDiff: EndDate-StartDate NumWorkDays: TotalDaysDiff - (((TotalDaysDiff + DayOfWeek(StartDate) - DayOfWeek(EndDate) + 7) * 2 / 7) - If(DayOfWeek(StartDate) = 1, 0, 1) - If(DayOfWeek(EndDate) = 1, 2, 1)) You may get funny results from these formulae if either the start or end date is a Saturday. You can get around this problem by not working on weekends! You can have the formula automatically subtract any public holidays, if any, by adding the following formula segment for each possible public holiday: -If(START <= '25/12/96' and FINISH >= '25/12/96', 1, 0) where 25/12/96 is a public holiday. Make sure you use the same date format as your database. #> Finding or calculating dates First, make sure your date is in a date field and not a text field. Trying to work with date in text fields is inviting all sorts of problems - that why they invented date fields! You can extract a date from a text field (eg 09/11/2001 or 09-11-2001) using the TextToDate() function. If this doesn't work then try creating your own custom function such as: Date(Left(datefield,2),Middle(datefield,4,2),Right(datefield,4)) (However, TextToDate() will do that on correctly, but you get the idea...) OK, once you have your dates in a date field, use the following to find what you are looking for: Put the range (eg 9/1/1998...9/30/1998) into the desired field in FIND. Try using or adapting the following formulas: For NOT December: IF(month(date_field)<>12) For this month: IF(month(today())=month(date_field)) For December 1996: IF(month(date_field)<>12 AND year(date_field)=1996) For the last 90 days: <=@TODAY()&>=@TODAY()-90 Between two dates: If(DB.Date >= SDate and DB.Date <= EDate) or: <@end_date & >@begin_date 3 business days from now: If(DayOfWeek(Date + 3) = 7 or DayOfWeek(Date + 3) = 7, Date + 5, Date + 3) One year from a date: If(Month("Date Joined") = 2 and Day("Date Joined") = 29, Combine(Month("Date Joined"), '/', Day("Date Joined") - 1, '/', Year("Date Joined") +1),Combine(Month("Date Joined"),'/',Day("Date Joined"),'/',Year("Date Joined") +1)). NOTE: This last calculation assumes that if the Month is 02 and day is 29, then the date a year will be 28. In v96 (and following), To find "This Month" use the Find Assistant and opt for "This Month". #> 21st Century Dates If you enter the full year (e.g. 10/31/2001) you should not encounter problems. However, if you want to enter dates like 10/31/01, and you want to add only future dates you can use the following solution. Create 3 variable fields, all 2 digit numbers: VYear, VMonth, VDay. Display these three fields on your form. Enter the dates using these three fields. Create a calculated field called VEYear containing the formula If(VYear => 95, (If(VYear <= 99, VYear, VYear + 2000)), VYear + 2000. Then create another calculated field called, say, DISPLAYDATE containing the formula: DATE(VMonth,VDay,VEYear). DISPLAYDATE will contain the full 21st century date. #> Two digit year assumptions (eg 01/01/29) To avoid problems caused by 2 digit year formats you should always use full 4 digit year format. But if you do use the two digit format, the Lotus Y2K FAQ (http://www.lotus.com/home.nsf/welcome/y2k) has this to say about the assumptions that Approach uses when dealing with two digit years: "The first two releases of Lotus Approach, 1.x and 2.x, assumed all two digit years fell into the 20th century. With the 3.x release Approach implemented a fixed window approach to two digit dates. The window used 30 as the split. So if the user input a number between 0 and 29 that date would be input as 20xx. If the number is between 30 and 99, the year 19xx would be input. In Approach Millennium, Lotus standardized all the SmartSuite applications on a sliding window. This window defaults to and 80/20 split. Thus, two digit years up to 80 prior than the current year will be assumed to be in the current or previous century. So, if the current year is 98 and the user inputs a date with a year of 25, 1925 will actually be entered. But if the user input 05, 2005 would be entered. Likewise, if the current year were 2010 and the user entered 05, they would still get 2005. But the number 25 now produces the year 2025." #> Date format with 4 digit year (e.g. 1997) This is set in MS-Windows, not in Approach. In MS-Windows 3.1* see International / Regional settings in the Control Panel. In MS-Windows 95 it is in Settings / Control Panel / Regional Settings. #> Importing Dates It was once said that Approach only recognizes date field in mm/dd/yy format, but apparently it handles dd-mm-yy date format OK when importing a .csv file. If possible you should probably export the data from the old application using mm/dd/yy format as it seems to be the most reliable. Try using a dBase export filter if the program has one. If you are not able to do this and are therefore importing dates that are currently stored in a different format then you will need to import them into a text field, and write some macros to convert the data in to mm/dd/yy format. E.g. to convert yyyy-mm-dd to mm/dd/yy a macro would use the formula: TextToDate(Combine(Middle(initial_date,6,2),'/',Middle(initial_date,9,2),'/',Middle(initial_date,3,2))) EXCEL uses a slightly different method of calculating dates than 'industry standard' adopted from 1-2-3. This means that imported EXCEL dates are 366 days out. The easiest way around this is to export the data from EXCEL into dBase file and import it into Approach from there. #> Dates in report titles To include the date range of a found set in the title of the report, use the SMin and SMax functions to create calculated fields that hold the start and end dates for your found set. Then insert these calculated fields into the title of the report. #> Find the previous weeks records For the previous week (Sun - Sat): ('date'= your date field) if(weekofyear(date)=weekofyear(today())-1 and year(date)=year(today())) If the data is only for one year, then you can leave out the 'and' and all that follows. For the last 7 days: (including today) >=@TODAY()&<=@TODAY()+7 Or, if you need to find records produced during the last 7 days: ... starting with and including today's date, use the formula: >=@TODAY()&<=@TODAY()+7 #> Y2K / Millennium bug compliance and leap years While Lotus states that the latest versions of Approach is Y2K ("Year 2000") ready (see http://www.lotus.com/home.nsf/welcome/y2k), this is no guarantee that a particular database application is. For instance, if you use calculations on dates, remember that the leap year formula is: (Y MOD 4 == 0) AND ((Y MOD 400 == 0) OR (Y MOD 100 <> 0)) Also see articles '21st Century Dates' and 'Two digit year assumptions (eg 01/01/29)'. #> Time and Date Schedule (uses SQL and multiple records) If you click on the following link you will download a self-extracting archive that contains the script as well as a brief description and .jpg images of the associated worksheet and form. http://www.johnbrown.com.au/approach/DATESC~1.exe [165KB] The script is a useful example of how to use SQL queries in a script, as well as how to access multiple records within a single script. ###> Formatting and displaying fields and buttons #> Field Formatting (including not / rounding numbers) In the info box, you can select or specify how you want data displayed, by selecting an option in the '#' tab. Note: There is a known problem with form letter views, that the format of the included field sometimes mysteriously changes from "display as entered" to "numeric" which alters the way the data is displayed. It can happen to text fields as well as other types! The only solution is to fix the format and save the APR file, hoping it does not change again before you finish fixing it! This occurs in v97 to v9.5 (I think) To display a combination of formatted a numbers and text when a number has been entered into a field, first make sure the field has been defined with the number of significant digits and decimal places that you require, e.g. if you need to display currency up to $1000 make sure you have defined the field as a NUMBER, with a length of 4.2. When displaying the field, either select or enter the format you require in the Styles / Field Format menu item. E.g. Using a field format of: #,##0.00 " Miles" The following will be displayed: entered displayed 12 12.00 Miles .3 0.30 Miles #,000.## " Miles" The following will be displayed: entered displayed 12 012 Miles .3 000.3 Miles Check the manual and / or the help files for all the rules and options governing the format codes. This does not change the stored data. It only changes the way it appears in the field box you are working on. [For some strange reason, when using above example in v2.1, and v3.0* (v96?), the data is only displayed correctly if there is a space after the first quotation mark. If this space is left out so it reads: #,##0.00 "Miles" it will incorrectly display 12.1 as 1.21 Miles. Strange, but true!] Any information that includes anything other than numbers, or even a number that needs to be stored with leading zeros, must use a text field. E.g. zip / postal codes in many countries, or USA Social Security Numbers which have leading zeros. However, you can still use numeric format to control the display of a text field. #> Displaying Negative Values In Red (Changing fonts colours using LotusScript) In v2.1 and v3.0*: you need to create 2 calculated fields: one that will only display the number if it is negative: If(DB.NUMBER < 0, DB.NUMBER, ''), and the other that will only display the number when it is positive: If(DB.NUMBER >= 0, DB.NUMBER, '') Display these fields on your report or form. Set the Fill Color to transparent on both of them, and the Pen Color to red on the field that will display the negative values. Then use the OBJECT / ALIGNMENT menu item to place one of the fields directly on top of the another. Set the STYLE / FIELD STYLE / LABEL: to be blank, and create a separate text box to label the field if required. In v96: you can either use the same method outlined for v2.1 and v3.0* shown above, or the following LotusScript attached to the field wherever it is displayed: Sub Lostfocus(Source As Fieldbox) If Val(CurrentView.Body.YourFieldName.Text) <= 0 Then currentview.Body.YourFieldName.font.color.setrgb(color_red) Else currentview.Body.YourFieldName.font.color.setrgb(color_black) End If End Sub To change the background colour, use: currentview.Body.YourFieldName.background.color.setrgb(color_red) #> Leading zeros (eg. 00054628) To output data with leading zeros create and output a calculated field containing the formula: Right(Combine('0000000',DB.NUMBER), 7) where '7' is the maximum number of digets, and hence the length of the output string, and 0000000 is a line of zeros of the same length. #> Trailing zeros (eg. 1.400) First check that you have that the field definition is numeric with the right number of decimal places. While in design mode, select the field and then enter the Style/Field Format menu (v2.1, other versons may be different) and either select one of the custom numeric field formats provided, or enter your own. For exporting data, create and export a calculated field containing the formula: NumToText(DB.NUMBER,'####.00') where ####.00 is the output forumla you require. #> Display problems (including problems switching to a particular form) If it is just when switching to a particular view: * make sure all of the objects on the page are completely within the page margins. Go to Design on another view, and under View on the top menu bar turn off "Show Data". Then switch to the view that is causing the problems. -- For report views, you can get an extra page to the right of your report page. To eliminate this page, under Edit on the top menu bar, select "Select All" to highlight all object boundaries. Scan the right margin of the page for anything that extends onto or beyond that right margin and resize it or move it back within the margin. Do not forget to check the footer panel! If your printer allows it, you may change the margins to a smaller value as an alternative solution. -- On Form views, Approach will not let you leave objects outside of the margins. But if you have objects that extend under the right vertical scroll bar in Browse mode, that can cause a redraw loop with some video drivers. The only solutions are to change the video driver, move the objects to the left, or change the video resolution so that those objects are no longer under the scroll bar. -- On Form Letter views, most problems are caused by corrupt text blocks. If you can get to the form letter in design, you can try deleting the text block and adding one back, or delete the entire view and add one back to your application. If you cannot get to that view in design, you can hide it and add a new form letter to your application to replace the bad one. * for v97 and newer versions of Approach, try going into design, switch to view causing the problem, then remove the check mark next to "Hide Page Margins" in the Form Properties Infobox Basics Tab. * you may have to delete that form and recreate it from scratch. First, try creating a new blank form and copying a few objects to it at a time. When recreating the form save the .APR frequently under different files names so that if the problem reoccurs you can tell what caused it, and you can then just go back to the previous version and do something differently. Make sure that you check view switching after copy/paste multiple objects or reordering views. Otherwise, * it could be a video driver problem. See if you can get another driver from the manufacturer of your video card (you can often get these via the web) or try the generic VGA driver supplied with by MS-Windows. * if you have just changed your printer: screen redrawing problems can be caused when the margins for the new printer are wider than those for the printer specified when the view was developed. Try different printer drivers, or recreating the form as described above. * check the video resolution is that same as the computer that the .APR was created on. * try closing down all other programs before running Approach just in case there is a video conflict with other software. * try using video resolution 640 x 480 and see if the problem goes away. This forces Windows to use the basic VGA video driver which is very reliable. If this works and you do not want to run your application this way, you will need either another video card or driver. TIP: Since most newer inexpensive printers require 1/2 inch margins all around, it is a good idea to develop applications with those margins to avoid problems in distribution of your application. #> Removing unwanted characters from phone numbers The following formula removes all '-', '(', '(', and ' ' characters from a phone number. E.g. it turns (123) 4567 8987 into 12345678987 This may be necessary if phone numbers have been imported with these unwanted characters. You can them use Field Format to display the phone number however you want. Translate(Translate(Translate(Translate(contacts.Phone, '-', ''), ')', ''), '(', ''), ' ', '') #> Radio Buttons Field Label Question: When using radio buttons, why can't I maintain the field label, as in getting it to appear above / below / etc. / anywhere in the box? Page 6-12 of my User's Guide shows an example with a field label Type of Customer. But I have been unable to generate a similar example. Answer: They got tricky. What they did to accomplish that is to create a Text Box and type the box label Type of Customer. Then they created their Radio Buttons box (outside of the text box, clicked the right mouse button, chose ARRANGE, BRING TO FRONT, and then dragged the radio buttons on top of the text box they way they wanted it. Play with it a bit and you'll get the results you're looking for. #> Make empty fields disappear (... rather than just turn invisible) It is possible on reports but not on forms. An alternative is to set up a multipage form and have a separate page for each field. On the first page, put a check box for each field set to automatically come on if there is an entry in the field. Then, when you are browsing through the forms, you look at the page if you need to. #> Converting numbers to words 34 to thirty-four? There isn't such a function built into any version of Approach. For Approach v96 there is a LotusScript called ConvertNumberToText in the Archive of Scripts (see section 3. Notices: How to get the Archive of Scripts) which works for numbers up to 999 999 999. If you are using v2.1 or 3.0* you need create another database with the numbers and related text versions of the numbers, and join it into your current database to the field that you want to appear as text. It might look something like this: number text 1 one 2 two .. ... 27 twenty seven #> Sliding fields together on mailing labels If you are having difficulty getting fields to slide together on mailing labels (such as first and seconds names), there are a couple of things you can do to improve the situation. 1) Use calculated type fields Set up a formula that combines the fields in the format you want in a calculated type field. Then put the calculated field on the label view instead of the individual fields. A "full name" could be set up this way, for example: FULL_NAME = Trim(Combine(SALUTATION,if(SALUTATION = '','',' '), FIRST_NAME,' ',Trim(MIDDLE_INI),if(MIDDLE_INI = '','',' '), LAST_NAME)) The above example formula only inserts spaces where they are required by testing to see if a field is "empty" and putting a "null" into the formula when it is empty. A "null" is two single-quotes with no space between them. For a complete label address with an optional second address line, the calculated field and formula would look something like this: CUSTOMER_LABEL = Trim(Combine(FIRST_NAME,' ',SURNAME,Chr(13),If(Isblank(ADDRESS2),Combine(ADDRESS, Chr(13),CITY,' ',STATE,' ',POSTCODE),Combine(ADDRESS,Chr(13),ADDRESS2,Chr(13),CITY,' ',STATE,' ',POSTCODE)))) 2) Use a text object Delete the database fields from the label and create a text object on the label view. Then insert the desired fields into it. In design mode, click inside the text object to put the cursor where you want a field to appear. Never type in the field name! Always use the "Text" option on the top menu bar, and the sub-option "Insert", then "Field Value" to add a field and avoid problems. You can add spaces between the fields and punctuation if needed, and put them on different lines. If a field is empty, Approach will not leave a blank line in its place. Database fields are expressed in the text object as <> where "database" is the name of the database and "field" is the name of the field. Calculated fields have only the field name in the brackets. For example: <> <> <> <>, <> <> or just this: <> #> Including quotes, symbols and international characters in strings There is some information the readme.wri file in the Approach directory about problems with international characters. To include a single quote or any other such difficult symbol in a text string it is sometimes easiest to use the Chr() function. For example to create the text string: 3'6" you would use: "3" & chr(39) & " 6" & chr(34). However, with single and double quotes you can achieve the same thing by simply repeating the quote: eg: "3'' 6""" (where the outermost set of double quotes are the boundaries of the string) but this can get a little confusing to read! You can find all the ASCII codes in old DOS manuals or a freeware utility like ASCIICAT at http://ourworld.compuserve.com/homepages/r_harvey #> Phone numbers If all the phone numbers in your database have uniform formatting eg. (xxx) xxx-xxxx in the USA, then you can store the phone numbers a numeric field and set the field box to display them in the desired format. To do this go into Design mode, click on the numeric phone number field. When the InfoBox appears, click on the '#' tab, and select 'numeric' format type. Then click on 'Edit format' and enter (000) 000-0000 in the format code. If you are importing phone numbers from another application they may be stored as text fields containing both text and numbers eg. "(205) 765-4321". You can either import them into a text field, or use find and replace to remove all the unwanted characters, and then import them into a numeric field. If you have phone numbers in an Approach database in a text field, you can convert them to a new numeric field using Left, Right and Mid functions in a SET command in a looping macro: eg: to convert (205) 765-4321 from a text field (say 'TextPhoneNumber') to numeric format, set the numeric field to: Middle(TextPhoneNumber, 2, 3) * 10000000 + Middle(TextPhoneNumber, 7, 3) * 10000 + Middle(TextPhoneNumber, 11, 4) (also see article 'Looping Macros' in this FAQ) #> How to make a field invisible on a form Set the field to invisible in a script using the following command: currentview.Body.fieldname.Visible=False You could use this in conjunction with an 'if' statement if you need it to be conditional. #> Conditionally display a pushbutton
'The purpose of this script is to allow a pushbutton to be visible when data
'changes in certain fields. In my form the pushbutton is invisible when the
'form is switched to. When data in fields with script attached changes, the
'push button unhides. The pushbutton is clicked and both script and macro run.
'The script attached to the pushbutton, hides the push button again. The macro
'does its actions at the same time.  The idea for this came from the manual
'Approach96, Using LotusScript in Approach page 5-7.
'The purpose of this script is to allow a pushbutton to be visible when data
'changes in certain fields. In my form the pushbutton is invisible when the
'form is switched to. When data in fields with script attached changes, the
'push button unhides. The pushbutton is clicked and both script and macro run.
'The script attached to the pushbutton, hides the push button again. The macro
'does its actions at the same time.  The idea for this came from the manual
'Approach96, Using LotusScript in Approach page 5-7.
'
'Open the script editor and choose Menu...New Sub (F3). Type, MakeInvisible,
'click, Make global sub and OK. In the Script Editor, finish this entry.

Sub MakeInvisible (dis As Display)
        dis.Visible = False
End Sub

'Repeat the process for the next global sub, MakeVisible

Sub MakeVisible(dis As Display)
        dis.Visible=True
End Sub

'These two are your global subs you will call from another script.
'
'Next, on any form you have that has a pushbutton, go to design, properties,
'click on the button and note its object name. Return to the script editor and
'using the object dropdown box, toggle to the correct form, then object. Use
'the Script dropdown box and choose click. The complete the following

Sub Click(Source As Button, X As Long, Y As Long, Flags As Long)
        Dim dis As Display
        Set dis=Source.ObjButton
        MakeInvisible  dis
End Sub

'All thats left is choosing which field(s) you want to monitor. Again in the
'object dropdown, find the object(typically your fieldname), choose change and
'complete the following. Do this for as many fields as you want to cover.

Sub Change(Source As Fieldbox)
        Dim dis As Display
        Set dis=Source.ObjButton
        MakeVisible dis
End Sub

'The lines with Source.ObjButton should read Source.YourButtonName where
'YourButtonName is the objectname you noted earlier for your pushbutton.
'
'What happens? You are passing the argument dis to the sub MakeVisible or
'MakeInvisible and the sub processes the request. Try substituting a fieldbox
'object or any other display class object instaed of the pushbutton and let me
'know how it works.
'
'Written by Jerry Sikes , 1996
'(C) Copyright 1996 by Jerry Sikes
'
'Permission is granted to freely copy this script in electronic form,
'or to print for personal use. It may be use in any Approach database,
'but may not be distributed for profit either by itself or as part of
'a collection or database.
'
'Disclaimer: This script is provided as is without any express or
'implied warranties. The author assumes no responsibility for errors or
'omissions, or for damages resulting from the use of the information contained
'herein, or your own version containing your desires for the usage of the
'script.'
'Open the script editor and choose Menu...New Sub (F3). Type, MakeInvisible,
'click, Make global sub and OK. In the Script Editor, finish this entry.

Sub MakeInvisible (dis As Display)
        dis.Visible = False
End Sub

'Repeat the process for the next global sub, MakeVisible

Sub MakeVisible(dis As Display)
        dis.Visible=True
End Sub

'These two are your global subs you will call from another script.
'
'Next, on any form you have that has a pushbutton, go to design, properties,
'click on the button and note its object name. Return to the script editor and
'using the object dropdown box, toggle to the correct form, then object. Use
'the Script dropdown box and choose click. The complete the following

Sub Click(Source As Button, X As Long, Y As Long, Flags As Long)
        Dim dis As Display
        Set dis=Source.ObjButton
        MakeInvisible  dis
End Sub

'All thats left is choosing which field(s) you want to monitor. Again in the
'object dropdown, find the object(typically your fieldname), choose change and
'complete the following. Do this for as many fields as you want to cover.

Sub Change(Source As Fieldbox)
        Dim dis As Display
        Set dis=Source.ObjButton
        MakeVisible dis
End Sub

'The lines with Source.ObjButton should read Source.YourButtonName where
'YourButtonName is the objectname you noted earlier for your pushbutton.
'
'What happens? You are passing the argument dis to the sub MakeVisible or
'MakeInvisible and the sub processes the request. Try substituting a fieldbox
'object or any other display class object instaed of the pushbutton and let me
'know how it works.
'
'Written by Jerry Sikes , 1996
'(C) Copyright 1996 by Jerry Sikes
'
'Permission is granted to freely copy this script in electronic form,
'or to print for personal use. It may be use in any Approach database,
'but may not be distributed for profit either by itself or as part of
'a collection or database.
'
'Disclaimer: This script is provided as is without any express or
'implied warranties. The author assumes no responsibility for errors or
'omissions, or for damages resulting from the use of the information contained
'herein, or your own version containing your desires for the usage of the
'script.


#> Stopping Approach from using Marlett as the default font

Marlett font may be useful for something but its dammed annoying as a default font, so why does Approach sometimes insist that it is the only font for me?!
  
Well, there are a number of possible causes for this problem:

* your default printer is set to "Generic/Text"
* your default printer is set to a fax, .pdf or some other software driver rather than to an actual printer
* you have a font named "Monotype Sorts" installed on your computer. Remove it!!
* you have a field or default font set to a font or style that is not installed on your computer. This is a particular pain if you accidentally uninstall a font which you have used throughout your .apr's. I speak from personal experience on this one. Months later I was still opening not-often-used .apr's only to find everything was now written in Marlett which is not a language I can readily read!


###> Reports and form letters



#> Deleting the body in summary reports

Use your mouse to drag the bottom line of the body frame up above the top line of the body frame. That way the body disappears and only the summary lines show up on the report.


#> Tips on layout of Reports / Altering report width

The default method of working with a columnar, repeating panel, or summary only type report is to use PowerClick reporting (see Approach Help for more information about it). In a nutshell, this feature works when you are in Design mode and have the View menu option "Show Data" turned on. Columns then become moveable and resizeable with the mouse, but working with individual elements such as the column header can be difficult. 

If you can't get your layout the way you want it using PowerClick, try turning 'Show Data' off (by clicking on it in the View menu). You can now resize and reposition the field boxes and column headings as required.

It is not possible to alternate the background color in the line items of a report (like in a repeating panel). Therefore if you really want to do this you either need to export the data to a program that is capable of it, or create a really big repeating panel! Remember that a repeating panel has a maximum of 30 rows.

A common problem with reports is that a second unwanted page is created to the right of the page you are working on. This is because one or more of your report objects (fields or text blocks) is extending beyond the right margin of your page. To find the offending object(s), turn off the "Show Data" option. Then under Edit, Select All to highlight all the object boundaries. Scan down the right margin and move/resize the object as needed. Remember that the object may be in the header or footer.



#> Total page counts on Reports

There is no automatic function to do this, so basically you have to get your Report to work it out itself. The following two methods have been submitted:

Method 1: using imbedded IF statements:
--------

Create a calculated field with the formula:

if(SCount(Surname) <= 25, 1,if(SCount(Surname) >25 and SCount(Surname)
<= 50,2, If (SCount(Surname)> 50 and SCount(Surname) <= 75,3,4)))

This presumed that the surname field would be on every record and
that their would be a maximum of 25 records to the page and that I would
never have any more than 4 pages worth. You will need to adapt it to your requirements.

Then placed the normal page counter field with this field next
to it. Eg: Page 1 of 4

Note that this formula will only give the correct result for a particular printer type and page layout. If either of these change you will need to check the formula.

Method 2: using 3 calculated fields
--------

Create three calculated fields PCOUNT1, PCOUNT2 and PCOUNT3 using the following formula:

PCOUNT1:

     (SCount(CONTENTS) + 4) / 90

PCOUNT2:

     Trunc(PCOUNT1, 0)

PCOUNT3:
     If(PCOUNT1 > PCOUNT2, PCOUNT2 + 1, PCOUNT2)

Then put the following in a text block in the header or footer of
your report:

Page <<#>> of <>



#> Form letters (and multi-page reports)

The bad news is Approach (up to v97 at least) only supports single page form letters. If this is a problem then do your form letters in WordPRO, or some other word processor, and either have the word processor access the .dbf directly, or export your data from Approach in whatever format your word processor wants. This can be automated by creating a macro which exports the desired fields into a temporary database, and then opens your WordPRO form letter containing the desired embedded merge fields. You can complete the automation by imbedding a Script in the letter which performs the mail merge and perhaps starts it printing. This script would need to automatically execute when the letter is opened.

A work around in Approach is to create your form letter as a Report. Eg. have the heading info in the header panel, the greeting
and opening paragraph in a leading summary panel. Body panels could contain a list of items to be billed, and a trailing summary panel could contain the total and include the "Yours truly," line and space for a signature. If you are keen the opening paragraph could be a calculated field combining various sentences based on flags in the customer record. When using this method for multi-page letters/reports, make sure you do not have a footer panel. Set the properties for both the memo field and the body panel to "expand" using the InfoBox (click on field and press ALT-ENTER). As long as there are no fields beneath the memo field in the panel, the memo field and the panel will expand to span as many pages as is required.

Note: There is a bug in v3.02: A memo field that spans more than one page, can cause weird problems apparently.



#> Stopping v96 (and beyond) from entering design mode when switching to a report

You may not have noticed this, but there is no "Browse Mode" option on Approach reports that contain summary panels. But there is a "Browse" option on reports that are simple listings of records. This "fact" lets your user update the report's records in Browse Mode if the report fields are not read-only!

Back when V3.02 was current, as an enhancement the Lotus developers were asked to make it possible to show totals on reports containing summary panels in Browse mode. Since this was not possible, their "solution" was to switch the user to Design Mode automatically if the user manually switched to a summary report view in Browse mode! Oddly, a macro VIEW switch to a summary report will go to Print Preview mode even if you put BROWSE commands in your macro. 

This behavior is controlled by a new setting starting with V96. Go to the FILE menu USER SETUP, APPROACH PREFERENCES dialog, and uncheck the checkbox next to "Show Report Summaries" on the Display tab. Then save your work and restart Approach. This setting is stored in each .APR file and is not universal to your Approach installation. This will prevent accidental switching to design mode on summary reports!

This setting will affect all the summary reports in the .APR file. 


#> Repeating panels in Reports

A report view can only have one Repeating Panel. A work around involves using a macro to export fields from different databases into one temporary database which is used to create the report.


#> Creating HTML and text file reports

While Approach has features to allow you to save a view as .html or .rtf, by far the best way of creating web and text reports in by using LotusScripts. There is a great example of how to do this on the example databases titled "Writing HTML and text files from Approach". After you've played around with it to see how it works, just press CTRL-K to open the script editor and see the LotusScripts!

Also see the following example LotusScripts in this FAQ:
* Create a delimited text file from two fields
* Creating a dot notation text file


###> Data entry



#> Limiting the options in a drop down list using an Alias table

You can use an Alias database table to limit the list of options in one dropdown list by the option that have selected in another dropdown list. An "Alias" is when Approach opens two connections to the same database table which can then be used in separate joins. 

You can download a working version of the following example at http://www.johnbrown.com.au/approach/state-city.exe

Create a database (in this example called St_City) containing the desired fields (in this example called State, City).

Then create an Alias of the database table (automatically named St_City:2, which the original database table becomes St_City:1. In v97 you create an alias by opening the Join dialog box, selecting the database table, and clicking the ALIAS button). Join the Alias and the original database tables by their City fields.

Then go into design mode, select the State field, make it a Field Box & List and select the 'Create list automatically from field data' option. Then select the City field and similarly make it a Field Box & List and select the 'Create list automatically from field data' option, but before you leave that dialog box click on the OPTIONS button, and select the options such that the dropdown list is created from the City field in the St_City:2, filtered on the State fields in St_City:1 and St_City:2. 

Now go to Browse mode and start entering records. Once you have entered a few Cities in different states, you will find that once you have selected a state, the options in the city list are limited to those previously entered in that state. Pretty neat really!


#> Making keyboard entries into a formula or macro

To do this, link every record in your database to a single record in a specially created database. Fields in this record in the special database can be easily changed by putting the fields on any form, and can be used to input information required by any macro or formula. The method for doing this in Approach v2.1 is as follows:

  1) In your existing database (let's call it EBASE) create a new field called (say) DUMMYLINK, and set the field definition options so that a '1' is automatically entered into DUMMYLINK every time a new record is created. Then enter a '1' into the DUMMYLINK field in all existing records. The end result of this is that every record in EBASE will always have a '1' in the DUMMYLINK field. Once it is set up there is no need for DUMMYLINK to appear on any forms.

  2) Then create a new database (INPUTDBASE), with two fields INPUTDATA, and DUMMYLINK. Create one (and only one) record and enter '1' into the its DUMMYLINK field. Then join INPUTDBASE to EBASE by the DUMMYLINK fields. The data you enter into the INPUTDATA field is now linked to every record in EBASE. 

  3) Put the EBASE:INPUTDBASE field onto any form or forms you commonly use.

  4) Create the macro or formula using the EBASE:INPUTDBASE
field where you want to input data.

e.g. In an phone book database you could enter your current location into the INPUTDATA field. This information could then be used by various formulas to calculate the actual phone numbers you need to dial from there, including any national, or international codes, as well as perhaps giving the time and date at the destination.


#> Limiting the number of characters entered into a text field

In v97, using a text field displayed in a Field Box, the default format settings will cause Approach to limit the number of characters entered to the length of the text field. As soon as the maximum number of characters is exceeded Approach bring up a message box explaining the error. For this to happen, the text field must be displayed in a Field Box, and 'Show data Entry Format' must not checked in the field format (in Design mode, click on the desired text field, then go to the  FIELD OBJECT / OBJECT PROPERTIES / # menu item). Note: if the format is set to 'Display as Entered', then 'Show data Entry Format' will be grayed out and unchecked.

However, Approach will not bring up the message box until you enter the data if the field is displayed in a "Field Box and List" or if 'show data entry format' set.


#> Conditional form navigation ( tabs )

It is possible to attach macros to fields so that they are executed on data change or entering or leave the field. To have a conditional tab out of a field, construct a macro that checks the condition when you tab out of the field, which then in turn executes other macros depending on the outcome of the condition check. These subsequent macros would each contain different navigation commands. Eg the following describes three macros called Macro1, MacroTAB and MacroTAB2:

Macro1: (executed when you tab out of the 'ChristmasCard' field)
   IF(ChristmasCard=TRUE, MacroTAB, MacroTAB2)

MacroTAB: (this takes you to the next field)
   TAB

MacroTAB2: (this skips the next field)
   TAB
   TAB

You can use this technique for all sorts of things, include data checking and standardising the format of data.

Like many tasks, this can also be done with a LotusScript. Create a LostFocus script for the object or field that checks the condition and then use SetFocus to jump to the desired field:
   
   CurrentView.Body.myfieldbox.SetFocus



#> Recovering deleted records

If you have compressed the .dbf file then the records have been erased and cannot be recovered.

If you haven't compressed the database then what you need to do is in some way remove the "deleted" tag from the records. You can't do this within Approach. You can do this in some other database software, or you can get utilities designed for the purpose. One that has been recommended on the mailing list is a small freeware tool called Database Manager, which can be downloaded from http://www.inner-smile.com/ Make sure you read the readme.txt file carefully. You find it has three levels of access, and recovering deleted records requires full access. Unless you speak German you may find the tooltips in the Options dialog box a little hard to read ... A more serious limitation with the current version (v2.1) is that is it not possible to open any dBase IV that has a memo field (*.dbt). To get around this, export the memo field to a temporary database, then delete the memo field in the original database. Use Database Manager to recover the deleted records, then re-create the memo field and import the information back into the memo field from the temporary database. 

Another method to recover delete records is to create an ODBC data source using the MS dBase driver. Select the option to show deleted records. Open the dbf with this driver then export to a new dbf file to recover the deleted records.

It is also possible to recover records by opening the .dbf in a text editor, and replacing the asterisk at the beginning of a deleted record with a space character. However, this is not recommended!


#> Bypass the misuse of the "Esc"-button when using auto-increment

(Created by Johan de Kock in appreciation for the work of Sue Sloan of XpertSS.com)
 
Forms often include a field to pre-number especially documents, e g invoices, etc. The auto-increment default numbering allows each new record to pre-populate with the next available number. When a user however creates a new record, but then press the "Esc"-button before completing the record, the default number is lost, causing "gaps" in the numbering of these records.
 
The purpose of this procedure is to bypass the auto-increment default numbering option, and thus avoid the frustrating misuse of the "Esc"-button, when creating new records (without using scripting, or external means to deactivate the use of the "Esc"-button).
 
I assume that you currently have created one or more forms, in more than one "APR", which use auto-increment default numbering, incrementing all numbers by one, and will proceed with the procedure to replace the current auto-increment default numbering.
 
The first logical step is to list all uses of the auto-increment default numbering, and group these per APR.
 
The second step is to create one field called "Variable Serial Number" per APR of the type "Variable" and the subtype "Number".
 
The third step is to edit the existing macro which takes the user to the specific form:  First ensure that the macro includes the instructions "Records: Last Record" and perhaps "Page To: Specific Page". If these are not yet included, add these lines at the particular logical point. If you have used the instruction "Records: New Record", include these lines before the instruction "Records: New Record". You may also want to include the line "Browse" to ensure that the coming "Set"-command works correctly. Now add the line "Set: Variable Serial Number = Current Number + 1" directly after the line "Records: Last Record" (Current Number refers to the numeric field currently used to number the records.). You have to repeat this for all existing macro's which takes the user to the specific form.
 
The fourth step is optional, but a good help in any problem-solving:  Add the "Variable Serial Number"-field temporarily to the particular form. You may want to change the field's properties to Non printing.
 
The next step is to create the macro "Set Var Serial No + 1_" to each APR:  This macro includes only one command, being "Set: Variable Serial Number = Variable Serial Number + 1". You only need one macro per APR.
 
The next step is to create the macro's "Set Var Serial No + 1 - Form_":  This macro also includes only one command, being "Set: Current Number = Variable Serial Number" (Again Current Number refers to the numeric field currently used to number the records.) (Form refers to any indication to the current form, e g "Inv" for invoices.). You need to create a macro for each "Current Number" used.
 
The next step is to create the macro's "Set Var Serial No + 1 - Form":  The name of the macro is similar to the previous macro, but excluding the underscore (Form again refers to any indication to the current form, e g "Inv" for invoices.). This macro includes only two commands, both being the conditional "Run"-commands. The first "Run"-command will execute the earlier "Set Var Serial No + 1 - Form_"-macro on condition that IsBlank("Current Number") = 'Yes'. The second "Run"-command will execute the earlier "Set Var Serial No + 1_"-macro on condition that "Current Number" = "Variable Serial Number". You again need to create a macro for each "Current Number" used.
 
The next step is to attach the macro's "Set Var Serial No + 1 - Form" to a field on the particular forms:  As you want to ensure that the macro's are executed, and executed as soon as possible, you need to attach each macro to a field which will most definitely be changed by the user. The choice of field to be used, will also determine the timing of the macro. Ensure that the user will be in Browse-mode when the macro is executed. Better not attach the macro to the "Current Number"-field itself. You need to repeat this step for each form being used to create a new record.
 
The next step is to remove the auto-increment default numbering option from each particular field:  Simply go to Field Definition, select the particular "Current Number"-fields, and change to default to "None". Ensure that no other option or procedure will add a default value to any "Current Number"-fields. You need to repeat this step for each "Current Number"-field being used.
 
Now it is time to change to Browse-mode, and test the use of serial numbers in the new records, as well as the bypass for the misuse of the "Esc"-button. Once you are satisfied, you may remove the temporary "Variable Serial Number"-fields from the forms. Should you wish, you can now refine some of the above, e g by resetting serial numbers at specific dates, e g year-ends. Once you are done, go to your home page and Save.



###> Finds



#> Automatically finding a 'drop down' list entry

If you use a "Drop-down list" the list will automatically move to the first entry for the key you press. E.g... if you press an 'L' it will move to the first entry starting with 'L'. If you then press an 'E' it will move to the first entry starting with 'E'. 

If you use a "Field box and List" the list will automatically show the first entry for what you have typed so far. E.g.. as before, if you press an 'L' it will show the first entry starting with 'L'. Then, if you then press an 'E' it will show the first entry starting with 'LE', and so forth. Note: 1) The list won't move down if what you type is already shown on the list. 2) You have to click or TAB onto the entry you want. 3) in v96 and later, there is a check box in the FILE / USER SETUP / APPROACH PREFERENCES / GENERAL menu to 'Expand Drop-down lists automatically'.

Some people have expressed the opinion that allowing users to enter data into a "Field box and List" can lead to corrupt data due to multiple entries, misspellings, incorrect punctuation etc..... There are a couple of ways to avoid this:

   1) determine all the possible entries and enter them into a drop down list.

   2) create a separate database to hold all the values for the drop down list. Have separate Forms for the Users (which just has a drop down list and doesn't allow them to make new entries) and Administrators (using a Field box and List" to make new entries and maintain the data).

In v3.02 and earlier, a "Drop-down list" is called a "Value list", and a "Field box and List" is called a "Text and Value List", but they do the same things.




#> Preserving the found set when switching forms

The basic way of preserving the found set when switching between forms is to make sure that both forms are based on the same database table.

In certain situations you can preserve the found set by including a repeating panel in your forms. Approach will keep the same found set as long as the forms you are switching between are based on database tables which are joined along a route to the main table of your repeating panel. If you don't actually want to use or display the repeating panel you can put it on a second page.


#> Finds on multipage forms

Make a single page form that contains all of the fields that you want to search on. Switch to this search form, do the find, and then switch back to your multipage form. The found set will be preserved as long as search form must also be based on the same database as your original multipage form.


#> Finding records which do not contain *text*

In Find, enter the following formula in any field:

if(NOT like(DBFNAME.fieldname,'*text-in-question*'))


#> Tricky finds

If you have exhausted the possibilities of Find and the Find Assistant then you will probably have to create a formula to find the records for you (see the Help files on how to do this). However, remember that the formula is lost once the find is performed. This can be annoying if you don't enter it correctly or you need to modify it for any reason. One way around this is to cut and paste the formula to and from a text document so that you retain a copy of it. However more permanent solutions are:

   * create a calculated field that simplifies the find

   * create a looping macro to do the search and set a Boolean field to TRUE if the records matches the criteria (then just search for all those records with TRUE in the Boolean field. Don't forget to fill the Boolean field with FALSE before you use it next time!)

   * create a variable field and do a worksheet find on that variable field. You do this by placing @VarField (where VarField is the name of your variable field) in the field that you wish to search.




#> Including Find criteria on a report

The best way of doing this is to use one or more variable-type fields in the report header in a text block or as separate fields. These fields will not appear except in PrintPreview or when the report is printed. 

For example, lets say that you have a Named Find/Sort that uses two variable fields to select records between two dates. The fields are named VarStart and VarEnd. The user fills in the fields and then runs a macro to go to the report. The header panel would have a text block containing the fields and text like this: 

 Sales Report for <> thru <>

You insert the fields into the text block not by typing them in as text, but by using the Text, Insert, Field Value method.

Another example might simply have your report macro set a variable field to the a description of the find criteria before the report is shown. A sample macro where a user has a radio button to select a value of ThisYear or LastYear:

View Report
 RUN If(userselect = 'ThisYear' run and return from FindThisYearMacro
      else run and return from FindLastYearMacro
 SET VarConditions = Combine('Report for ',If(userselect = 'ThisYear',Year(Today()),Year(today()) - 1))
 VIEW switch to report xxx
 PrintPreview

You would then put VarConditions in the header panel of your report.



#> How to pre-fill fields in a form-based find

(An edited version of a post by Carlos A Rodrigues Alves)

In order to pre-fill some or all of the fields when the user doing a form -based find, do the following:

1) Create a 'stored find' with all desired presets criteria
2) Create a macro that runs this stored find and then start a 'find again' search

It probably easiest if you attach the macro to a button. The when you run the macro (or click your button) the stored find is executed and then a find form appears with the stored find criteria already filled in. Then the user can type new criteria on others fields.


###> Sorting



#> Setting default sort order for a database or view

In v97, you can set default sort settings for a database in FILE / USER SETUP / APPROACH PREFERENCES / ORDER menu item. Don't forget to click on 'Save Default' after you have set up your desired sort order.

In v3.0*, you can set the default sort order in the TOOLS / PREFERENCES menu.

If you want to have a default order for a particular report then:

  1. create a Name Find/Sort
  2. in the FORM / FORM PROPERTIES / MACROS select the macro name in the 'on switch to..." pull down list

In v 2.1, you can't set a default sort order. A work around is described in article 'Saving records in their sort order' in this FAQ.


#> Saving records in their sort order

Sort the records as you want them, and then export (ALT-FILE-EXPORT) that database into a new .dbf file. This .dbf must contain the same files as the old .dbf. Delete the old .dbf and rename the new .dbf with the old .dbf file name.  e.g. Say you have a database called PEOPLE.DBF. Sort the records and export all the fields in PEOPLE.DBF into another database called TEMP.DBF. Exit Approach. Delete PEOPLE.DBF. Rename TEMP.DBF as PEOPLE.DBF.

In short, it is much better to just save them in entry order and sort them once they are loaded...


#> Sorting memo fields or fields that reference a memo field

Keith Seeley writes: Approach is resistant to sorting any field that is a memo field or references a memo field.  However, there is one way to get the first 23 characters into a calculated field that can be sorted (more than 23 if you want to add additional calculated fields).

You need to convince Approach that it's not dealing with a memo field by converting each of the first 23 characters in the memo field to it's ASCII value, then converting it back to a character and combining as you go along.

Define two calc fields, SortableMemo and SM, and sort on SortableMemo.  All you need to do is simply change "YourMemoFieldHere" in the SM formula to the name of your memo field.


SM = Left(YourMemoFieldHere, 23)

SortableMemo =
Combine(Chr(Asc(Middle(SM, 1, 1))), Chr(Asc(Middle(SM, 2, 1))), Chr(Asc(Middle(SM, 3, 1))), Chr(Asc(Middle(SM, 4, 1))), Chr(Asc(Middle(SM, 5, 1))), Chr(Asc(Middle(SM, 6, 1))), Chr(Asc(Middle(SM, 7, 1))), Chr(Asc(Middle(SM, 8, 1))), Chr(Asc(Middle(SM, 9, 1))), Chr(Asc(Middle(SM, 10, 1))), Chr(Asc(Middle(SM, 11, 1))), Chr(Asc(Middle(SM, 12, 1))), Chr(Asc(Middle(SM, 13, 1))), Chr(Asc(Middle(SM, 14, 1))), Chr(Asc(Middle(SM, 15, 1))), Chr(Asc(Middle(SM, 16, 1))), Chr(Asc(Middle(SM, 17, 1))), Chr(Asc(Middle(SM, 18, 1))), Chr(Asc(Middle(SM, 19, 1))), Chr(Asc(Middle(SM, 20, 1))), Chr(Asc(Middle(SM, 21, 1))), Chr(Asc(Middle(SM, 22, 1))), Chr(Asc(Middle(SM, 23, 1))))


###> Calculated fields



#> IF limitations in v3.0*

v3.0* allows for a maximum of 30 levels of imbedded IF's e.g.:

FIELD1=IF(x,a,IF(y,b(IF z,c,IF...

To get around this, simply use additional formulae, e.g.:

FIELD1=IF(x,a,IF(y,b(IF z,c,FIELD2)))
FIELD2=(IF(x1,a1,IF(y1,b1,IF(z1,c1...)))


#> Using values from the previous record

There are a couple of ways of doing this depending on what you are trying to achieve. 

One method is to go to the 'previous record', set a variable field/s to the required value/s, and then go back to your original record.

A more complex method is to use an alias of the database to access both the current and previous forms at the same time, using joining fields that a set one record apart using macros. I.e. if you are joining by a field Id, then create a field PreviousID, set its value to Id - 1 using a macro, and use PreviousId to join to the alias. This solution only works though if Id is sequential with no omissions (which is unlikely).



#> Tricky calculations

One way around some curly calculations is to imbed and IF statement in it. Check this one out:

     SSum(If(condition,field.A,(field.B + field.C)))

One paper you can write this out as:
    
     IF (condition) THEN Ssum(field.A)
                    ELSE =(field.B + field.C)


#> Generating a random unused PIN number

The following method for generating a random usused PIN number (ie a numeric password') was submitted by Mark Pearson:

My aim was to create a random number of 6 digits between 400000 and 999999, check that the number generated was not allocated to a record anywhere else and apply to a specific record for use. The reason I needed this was as a pin code for a call accounting system to be used by residents.

I used two variable numeric fields, two regular fields and three macros.

Macro one (This is actioned when on the record to receive the new number)

set var1 = studentID ' This sets a var field to the student or record id and will be used later to complete a find'

set var2 = Trunc(random()*1000000)+400000 'This creates the random number
but it is possible for it to be greater than 999999'

set var2 = If(Var2 > 400000 and Var2 < 999999, Var2, Var2 - 400000) 'This
reduces the value if was greater'

Find - Stored find 'create a stored find based on a worksheetview that has the var2 field and the field to get the random number. This find locates any record that matches the new generated number. If it finds a
match  it continues this macro. If it finds no matches it goes to a macro2

Run macro3


Macro2
Find - Stored find that uses a worksheet view with the studentID field.
Finds the student that =@var1
Set - Random number field = var2


Macro3
Set var2 = Trunc(random()*1000000)+400000
set var2 = If(Var2 > 400000 and Var2 < 999999, Var2, Var2 - 400000)
Find stored find as per macro1
Run macro3



#> The Combine() function in calculated and memo fields

The results of the Combine() function in a calculated or variable field is truncated to 254 characters. However, the results are not truncated if the function is used in a macro SET command on a memo field.

Use 'CHR(13), CHR(10)' in a Combine function to insert a Carriage Return/Line Feed. Eg. Combine(your.memofield, Chr(13), Chr(10), Chr(13), Chr(10), Chr(13), Chr(10),'Yours faithfully,', Chr(13), Chr(10), Chr(13), Chr(10), Chr(13), Chr(10), your.LetterWritersName)

The Chr(10)'s may not be needed depending on what you are doing. If you end up with twice as many lines as you expect, then remove all the Chr(10)'s.


#> Using calculated fields in joins and exports

A calculated field will not appear in the join dialog if it uses fields from more than one database (.dbf) file or if it includes summary functions. Note that using a calculate field in a join may result in substantially decreased database performance.

A work around in situations in which you cannot get a calculated field to appear in a dialog box (join, export, etc...) is to create another field and set the value of that field to the calculated field using a macro.

Also see article 'looping macros'


#> Calculations on numbers in a text field (eg imperial measurements such as 3'6")

If you want to do calculations on numbers contained within a text, you first have to get the number out of the text field and then do the calculations. To do this you will have to use the Position function to locate where the single and double quotes are in the text string, and the Left and Mid functions to extract the numbers. Then you do your calculations. Then you can use the results of your calculations to create a new text string if that is what you need (using the Combine function).

This could all be done in the one formula, but it would be a long a complicated one!

Here is an example of this process spread over 4 formulas to make it more readable. The original measurement is contained i a text field called 'size'. It calculates half the length contained in 'size' and puts the result in 'halfsizedtext'. It should work regardless of how many digits or decimal places are in the original measurement (eg 3' 6", or 123' 4.57")

   - feet = Left(size, Position(size, Chr(39), 1) - 1)
   - inches = Middle(size, Position(size, Chr(39), 1) + 1, Position(size, Chr(34), 1) - Position(size, Chr(39), 1) - 1)
   - halfsize = ((feet * 12) + inches) / 2
   - halfsizetext = Combine(Trunc(halfsize / 12, 0), Chr(39), ' ', halfsize - (Trunc(halfsize / 12, 0) * 12), Chr(34))



###> Summary fields



#> Summary fields

Calculated fields that have a "summary" type functions like SCOUNT, SSUM, etc... only work and display properly when they are used on fields in joined databases, and not the main database for the form. E.g. If your form is based on a database called DEPOSITS, which is joined to another database called BANK then ON THAT FORM you can only use SSUM on BANK fields. A summary of a DEPOSITS field would have to be displayed on a form that uses BANK as its main database.

If you want to count only some records, use an If statement within
the SCount expression. Eg:

     Bigrecords = SCount(If(DB.bigsmall = 'BIG',1,0))

   ... will count records containing BIG in the field named.

The following summary was contributed by Paul Bent:

If you have a form (say) based on table A with a repeating panel based on table B then it works like this:

SSum(tableA.field)   summary option all records in table A  - will only
display in print preview or design. If you want to display it in browse you need a workaround using an alias table.

SSum(tableB.field)   summary option all records in table B  - will display in Browse if placed outside the repeating panel.

SSum(anyfield)   summary option summary panels where placed - will only
display in design or print preview when placed in a summary panel on a
report. What it summarises depends on the panel properties.



#> Demystifying Summary Functions

(This article was submitted to the Approach Users Mailing list by Jerry Sikes, Unisource Converting)

Here is a guideline on proper Summary Functions use. All page references are to Lotus Approach Release 3.0 users Guide, copyright 1994 Approach Software Corporation.

   1. p7-15 - "You can add a calculated field to a form to show a total, average, count, or other summary on data in a repeating panel." The key is placement of the summary calculated field "on form", not in panel.

   2. p7-16 - "A summary on data in a repeating panel is calculated in Browse and Preview, and in Design if you're showing data rather". This means that a summary calculated field can be visible in all Approach modes.

   3. p7-16 - In reference to the field definition of a summary calculated field, "In the Define Summary panel, select "Summary of all records in database," where database is the name of the main database for the (repeating)panel;". p7-21 - "Because of the join the function counts(summarizes) only the records that appear in the (repeating)panel." Most important aspect for correct calculation is not using the "Where-placed" default Summary Definition. In Field definition, you must define the summary for the repeating panels main database.

   4. p8-19 - "For more flexibility, however, you can use a calculated field that has been defined as where-placed, which you can reuse as often as you wish. A where-placed calculated field looks at the summary panel it's place in and automatically summarizes" This applies only to report summary panel usage. You can use the same summary calculated field in leading, trailing, and grand total summary panels. When you place a summary calculated field on a form, its where-placed is not a summary panel, therefore Approach cannot figure which group of records to summarize in browse.

   5. p8-19 - "A calculated field in a summary panel is calculated when you preview the report÷" This reference applies only to calculated fields in summary panels. Summary calculated fields are visible on forms provided they are defined properly.

   6. A summary calculated field can be bound by Mathematical functions. Such as; Round(SSum( Database."Item Extension"),2).

   7. A summary calculated field cannot be bound by an If function. The If function must be bound by the summary calculated field. For example; Round(SSum( If (Database."Ship Status"="Shipped", Database." Amount",0),2). This would selectively summarize only those items in the repeating panel whose status is shipped.


#> Problems with summary panels

Sometimes a problem is encountered when creating a summary report in which a 'Zero Items could be added to the report' error is received, and the is body panel in the report in which to add fields.

Believe it or not, the problem is caused by a video driver conflict! The solution is to create a regular columnar report and add the summary panels afterward using the Create - Summaries option in Design
mode.


#> Using a summary field to count records which meet certain criteria

To count the number of records that have a value within a certain range, you can use a formula like the following:

Count1 = SSum(If(Amount <= 1000,1,0))
Count2 = SSum(If(Amount > 1000 and Amount <= 3000,1,0))

Count1 will contain the number of records with values less than $1000, and Count2 will contain the number of records with values between $1000 and $3000


###> Repeating panels



#> Problems with repeating panels

Firstly, does the repeating panel contain the right fields? If so, try moving the repeating panel a bit on the form. Do the fields move with it? If not then they are not really in the repeating panel. To correct this, select all the fields and cut them from the form; select the repeating panel so that the panel edges are highlighted and paste the fields into it. Try moving it again to check they are now in the repeating panel. If they still don't move, try deleting both the fields and repeating panel and setting it up from scratch.

Other things you may need to check are whether or not the data is actually there in the right database and fields, and that the database is meaningfully joined to the parent database.



#> Finds on repeating panels fields

If any find criteria are put in a repeating panel the find will return all the records that fulfill the criteria but will not display any other records in the repeating panel. A way around this is to set up a view that shows the specific fields you will be searching. Do your search with that view, then switch back to your original view with the found set. 


#> Using an alias to limit the records in a repeating panel

This describes how to use an alias to limit the number of records shown in a repeating panel. Say you have a form based on a database A, which contains a repeating panel based on database B, and you want to specify criteria beyond that which satisfies the join to limit the records shown in the repeating panel.

There is no "filter" option on a repeating panel,  but you can achieve the result using an alias:

1) Add a field or fields to database A that contains the values for limiting the repeating panel content.
2) Go to Create-Join and make an alias of database B.
3) Join B to A using the new fields.
4) Base the repeating panel on the alias of B.

Note that the contents of the repeating panel will always be limited by the criteria you specified. If you want a repeating panel to show all the records in database b limited only by the join, then you will need to create another repeating panel based on database B and not its alias.



###> Working with other data formats and applications



#> Exporting numbers

If you are having difficulty exporting numbers as fixed length fields, or any other particular format, use the NumToText function and if necessary manipulate the text field into the desired format.



#> Approach 97 incorrectly exporting numbers via macros

Approach 97 has a bug in its exporting of numeric values via macros. If you are experiencing any difficulties make sure have installed the latest apfixpak.exe. It is available from:
*IBM's Approach Support web site: http://www-1.ibm.com/support/manager.wss?rs=1&rt=0&org=sims&doc=83FE03EFA9A58FC5852569EE0079ED8B
*Lotus FTP site: FTP://FTP.SUPPORT.LOTUS.COM/ (From this site browse to pub, desktop, Approach, win32, 97, updates). 
*http://www.xpertss.com. Go to the "free downloads" area, and search in Products for Approach

See technote 148713, title:  Incorrect Results Exporting Numeric Values Via Macro:  http://www-1.ibm.com/support/manager.wss?rs=1&rt=0&org=sims&doc=4BFAC85907156BA6852569EE007BD337


#> Working with Paradox database files

A number of people have reported indexing and General Protection Fault problems when working with Paradox files with Approach versions up to and including v96. To avoid these make sure you are using:

  either: Approach v3.02 on MS-Windows 3.1 or (WFWG v3.11)

      or: Approach v96 or later on MS-Windows 95.

You will find problems if you attempt to use v3.0* on MS-Windows 95, or if you use v3.00 or 3.01 on any operating system. However, you will probably be better off converting your database files to dBase IV. Also see 'Accessing .dbf's updated by Access / Paradox' in this FAQ.

The Approach equivalent of Paradox DFunctions is to define calculated fields using the SSum, SAvg, SMax etc functions.

The following freeware purports to mend dbase and paradox datafiles, but I have not received any reports of its effectiveness:
http://www.ppsoft.dk/Paradox_Dbase.htm 



#> Accessing Access files (*.mdb)

The 16-bit ODBC drivers for Access 2.0 can be purchased from Microsoft.

The 32-bit driver is available from:

http://www.microsoft.com/odbc/download/default.htm

However, it can only be installed if you have a Microsoft product already installed on your hard drive. If you don't have any Microsoft products then you will need purchase a third party driver set from a company like Intersolv:

http://www.intersolv.com


#> Accessing .dbf's updated by Access / Paradox

When records are added to a database using a different database  application, Approach's index file (.adx) is not updated, and therefore Approach cannot access the new records. The indexes can be rebuilt by closing and reopening Approach. Once this is done the new data can be seen. Apart from this inconvenience, adding data to a database using other applications while Approach is open, may also increase the possibility of index files becoming corrupt. It's therefore not recommended.


#> Using index files other than .adx (eg.mdx)

All versions of Approach are capable of maintaining .mdx index files used by other database applications, but it is not capable of creating them. If you need to use them you have to first create them using some other program.

Up to version v96 Approach was able to maintain .mbx indexes, but this facility was removed in v97 and later because Lotus considered it to be "unreliable".

Some .mdx indexing utilities which subscribers have mentioned are:

"Database Manager" http://inner-smile.com/dl_dm.htm (freeware)
"DBFViewer 2000" http://www.dbf2002.com 
"Developer 1" http://downloads-zdnet.com.com/3000-2210-10179455.html?tag=lst-0-2
http://www.dbcommander.com/ ($100)
http://delphi.icm.edu.pl/ftp/tools/dbu13.htm ($60)


#> Export of Crosstabs to 1-2-3

Just copy and paste it! Highlight the entire crosstab by clicking in the upper left corner, then copy it. Switch over to your spreadsheet, and paste it.


#> Using Approach and IBM DB2

Check out the web site:

http://www-4.ibm.com/software/data/db2/db2lotus/appindex.html

It provides step-by-step instructions, tips and general information.

In vME and v9.1 people experienced a weird problem in that they couldn't scroll past the 50th record. Apparently it DOES NOT occur if you open the approach file NOT fully maximized, and login through the db2 client. However, if the first thing you do is scroll to the RIGHT to see your columns, you'll get the 50 record problem. As long as your APR is NOT fully maximized and you scroll past record 50, and you'll probably never see the 50 record problem for the remainder of that session.  Weird... The problem was fixed in v9.5


#> SQL and Approach

SQL or 'Structure Query Language' is a whole big area of database theory that if you don't know you will just have to go out there and learn it. It is a 'language' and therefore is akin to programming. So if you are not a programming or are not interested in going in that direction then SQL probably isn't for you. The SQL entries in this FAQ assume that you know SQL but want to know about how you implement SQL queries using Approach.

In v96 and later you can create and use SQL queries with just Approach by itself.

People have reported a few different things that don't quite match up about v3.* and SQL: either it is unable to connect to Oracle, or requires an Oracle or SQL-Server backend, or can only connect to SQL Server v5.0 or earlier tables. Whatever the true situation is, it is probably best to avoid v3.0* if you want to access SQL tables.

Whatever version you are using, make sure you downloaded the latest GA MDAC from Microsoft at http://www.microsoft.com/data

If you are using dBase files don't forget to start your query with:

    Type=dBase

You can perform an SQL query on only a single dBaseIV table at a time. However, you can add and join more than one SQL tables simultaneously. 

If you know SQL and don't want to use the Approach's SQL Assistant, you can manually create an SQL statement in a text editor and save it with a .qry extension.

Also see article 'Using SQL from LotusScript'


#> Using SQL from LotusScript

On page 8-51 of 'Developing SmartSuite Applications Using LotusScript' there is an example of embedding SQL SELECT statements in a Script.

Other example LotusScripts using SQL can be found in the Approach User Support Example Databases for Lotus Approach web page:

    http://www.johnbrown.com.au/approach/examples.htm

Using SQL SELECT statements in scripts means that you can use values obtained from the user in the select statement without having to create new queries each time.

Sub GetItem(FindItem as String)

 'the ITEM_NO the user is looking for gets passed to the sub

 ' the line we're focusing on in the SELECT statement would
 ' look something like this:

  Type=dbase

  SELECT invoice97.ACCT_NO,invoice97.INVOICE_DATE,invoice97.QTY_SHIPPED,
   invoice97.ITEM_NO,invoice97.SELL_PRICE,invoice97.PERIOD,invoice97.WEEK
  FROM "C:\lotus\work\approach\invoice97.dbf" invoice97
  WHERE (invoice97.ITEM_NO = FindItem)
  ORDER BY invoice97.PERIOD,invoice97.WEEK
End Sub




#> Using SQL in Approach with non-SQL data sources

The following is an unedited post from Jerry Sykes:

Here's a primer on SQL Select theory in Approach for Non-SQL database sources such as dBASE IV. SQL select is comprised of 4 sections

1. SELECT 
2. FROM 
3. WHERE  optional
4. ORDER BY  optional
As with any script string, enclosed the entire SQL statement in double quotes.
q.SQL = " "
Before beginning with the Select part, lets look at the "FROM" statement
"FROM" has two parts; FROM ""table full path name"" aliasname
Alias is the important concept here. It is the short reference name you are calling this datasource. Here is a FROM clause from of one of mine;
FROM ""F:\Programs\RawMaterials\BoxTrans.dbf"" BoxTrans 
then the variable substitution example from Help examples.
FROM """"+ Q.Tablename+ """"+ tname + " 
Notice my database table full path name has is enclosed by double quotes, yet my alias has none. Approach will interpet this when it translates the full string to;
FROM "F:\Programs\RawMaterials\BoxTrans.dbf" BoxTrans
stripping the outer set of quotes. In the second example. Q.Tablename is the Approach Query class property that is meant to hold the full tablename path.
Assuming Q.tablename is set previously in the script and is a variable a third set of  double quotes is necessary for runtime interpetation. In the same manner, the Alias variable must have one set of double quotes. The alias does not necessaraly have to be the database name. Any unique character combination except script keywords is ok. Such as;
FROM "F:\Programs\RawMaterials\BoxTrans.dbf" B
Just be sure you use the declared alias in all SQL alias.fieldname references.
Summing up the WHERE clause, if you want to supply the path in a SQL
statement, then 
"" mappeddrive:\..\databasename "" alias
else
""" + scriptvariable + """ " + aliasvariable + "
where scriptvaiable is the full path and name and aliasvariable is what you are naming this datasource within this script.
After you understand the alias naming convention, the alias is used in the other three sections.
If all fields are desired then
SELECT * FROM
where * is a all fields wildcard
else
SELECT alias.fieldname1, alias.fieldname2 ... alias.fieldnameN FROM
the last field selected should have no comma after it, just a space then FROM.

An example;
SELECT BoxTrans.ItemNum, BoxTrans.JobNum, BoxTrans.TransDate,
BoxTrans.FoldWeekOf FROM
If you use a variable alias type, as in this example,
FROM """"+ Q.Tablename+ """"+ tname + " ,
then  "+ tname + ".fieldname syntax is used. My preference is to avoid the "+
tname + " type of alias. It requires much more care in typing. If you are
using long fieldnames in your tables, it may be necessary to use double
quotes.
SELECT BoxTrans.""Item Number", BoxTrans.""Job Number"",
BoxTrans.""Transaction Date", BoxTrans.""Fold Week Of"" FROM
Continuing, the choice of syntax in your WHERE clause, follows the exact
syntax rules for the alias.fieldname part, but a slight variation is required for the criteria. From the Script Help...Approach Objects...SQL...Example,
WHERE ("& TName & ".""Room Name/Number"" = '" & DeletedRooms(i) & "')"
and one of mine
WHERE (BoxTrans.TransDate = '""'and BoxTrans.FoldWeekOf = '"+MySQL+"')
In both of these examples, the right hand conditional phrase takes a slightly different syntax. Instead of double quotes, you use 
alias.fieldname = single quote double quote +VariableCondition+ double quote single quote.
Notice an & and a + are interchangable when building string combinations.
The best method of troubleshooting a bad syntax SQL statement is to put a
breakpoint in the script after the SQL. Drill to the SQL statement of the
query object in the variable pane. Click on the SQL statement in the Variables pane. The runtime/substitution construction of the SQL statement will be visible on the bottom line of the variables pane. The following complete script,
qu.SQL = "SELECT * FROM ""F:\Programs\RawMaterials\BoxTrans.dbf"" BoxTrans
WHERE (BoxTrans.TransDate = '""'and BoxTrans.FoldWeekOf = '"+MySQL+"') ORDER
BY BoxTrans.ItemNum,BoxTrans.JobNum"
shows this string in the variables pane at runtime, when viewing the query object at a breakpoint script halt.
SELECT* FROM "F:\Programs\RawMaterials\BoxTrans.dbf" BoxTrans WHERE
(BoxTrans.TransDate = '"'and BoxTrans.FoldWeekOf = '4/6/98') ORDER BY
BoxTrans.ItemNum,BoxTrans.JobNum



#> Sending email directly from a form

Using a macro, you can send email to a particular email address 

OPEN   mailto:username@domain.com

If the email address is in a database field, then use:

OPEN   mailto:<>

If the email address is in a variable field, then use:

OPEN   mailto:<>

The following does the same thing using a script:

Sub CreateEMail

	Dim lngRtn As Long

	lngRtn = Shell("rundll32.exe url.dll,FileProtocolHandler mailto:" &
CurrentView.Body.emailfield.Text)

End Sub

Note that the mailto protocol also lets you insert the subject and a limited amount of text in the message body, but can't use it to send file attachments. Full details are in RFC2368 (search for this document on the web).




#> Using the contents of a variable field as an export filename

Create an macro that performs the required export to a set filename (say c:\temp\tempdata.dbf), then runs the script shown below. The script copies the exported file to the desired diskdrive, filename and directory contained in a variable field (VarField). For the script to work, the variable field must be displayed on the current view.

Sub Rename
    Dim filename As String
    filename$ = Cstr(currentview.body.VarField.text)
    Filecopy "c:\temp\tempdata.dbf", filename$
End Sub

If you want the variable field to only contain the filename then use the following variation:

Sub Rename
    Dim filename As String
    filename$ = Cstr(currentview.body.VarField.text)
    Filecopy "c:\temp\tempdata.dbf", "c:\path\"&filename$&".dbf"
End Sub

If you don't know the path name of the destination file (because it's on a network, or installed on different computers), you could use the LotusScript function in article "Getting the path of a database file" in this FAQ.

The next script basically does the same thing as the first, except that it renames the file rather than creating a new copy of it.

Sub MyReName
     Name "c:\temp\tempdata.dbf" As filename$
End Sub



#> Exporting summary fields

Let's say that the database that contains the data that is summarised in your summary field is called 'Main'.

Create a form based on a mock database that displays: 
    * a repeating panel of the records in 'Main'
    * the summary field
    * either a calculated (or variable field).

Set the calculated field to equal the summary field, or if you are using a variable field use a looping macro to set its value to that of the  summary field.

The calculated or variable field can then be exported.



#> Using a macro or Script to open documents in other applications

To opening a WordPro to a particular document from Approach, just create a macro with an OPEN command, and enter the path and filename of the WordPro document.

However, there is a problem with the OPEN command in that it gives an error if you have a space in the path or file name. To get around this, create a one line global LotusScript using the OpenDocument method to open the WordPro file. You can then run the sub LotusScript with the macro Run command if you like. An example LotusScript is:

Sub TestLWPOpen
'Contributed by Paul Bent XpertSS.com
    Dim LWPApp As Variant
    Set LWPApp = CreateObject("WordPro.Application")
    LWPApp.Visible = True
    Call LWPApp.OpenDocument("test doc.lwp", "c:\temp\")
End Sub

If you don't /can't use LotusScript, or need to do something a little more complicated, then consider using a DOS batch file which calls WordPro (or any other applications or applications) with the filename as a parameter. To do this, simply put the following line in a plain text file that has a .bat filename extension (eg. mybatch.bat) where 'f:\rescon\letter.lwp' is the path and filename of the WordPro document you wish to open:

c:\lotus\wordpro\wordpro.exe f:\rescon\letter.lwp

Then create a macro in Approach that calls the .bat file with the 'open' command:

OPEN c:\batch\letter.bat


#> Problems getting TeamMail to work

If you are using TeamMail in Approach to send email through Lotus Notes, then make sure that the mail Program in FILE / PREFERENCES / USER PREFERENCES / MAIL AND NEWS in Notes is set to "Lotus Notes", not "None". If it is set to "None" then you may find that Approach occasionally locks up or will take an excessive amount of time trying to send the message, followed by an error message stating "Mail Error: Operation Successful", although the email is never actually sent.  This scenario specifically occurs when the user attempts to send a "Snapshot of the current view".

This following applies to v3.0 and later and was submitted by Bill Tarkulich:

The "Mail Error" dialog box shows up usually because you have both Notes and other Email clients on your local system. Assuming you want to use a non-notes client to do the mailing, you'll want to change the configuration. A 32 bit application will look in the Registry; a 16 bit application, will look in the WIN.INI file. 

32 bit apps:
TeamMail gives preference to Lotus mail applications by looking at the following key and sees the Notes app. and may go berserk: HKEY_LOCALMACHINE_SOFTWARE_LOTUS_COMPONENTS TEAMMAIL  You'll want to remove the reference to the mail app so that Approach can find the default MAPI client.

16 bit apps:
Because cc:Mail, Release 2.1 and Release 2.2, are 16 bit applications, they require changes to WIN.INI.  You must comment out the call to the mail application from the WIN.INI file under the heading  [Lotusmail]. 

Outlook is a 32 bit app and requires removing the mail application reference from the Registry Key.  I've got Outlook running on 3 different machines and Approach sends mail through them all quite nicely, once I resolved this.

Good Luck,
Bill

The following further thoughts come from Rainer Schmidt (Germany):

Windows 98SE and prior

We found out that TeamMail prefers to use a Lotus Mail Application and looks to the registry key as described by Bill Tarkulich. If it doesn't find any Lotus mail application, it produces the mail error message.

If you delete the key there, it's name might be „AddressbookLastFirst" with value, Outlook Express should work already, because TeamMail then looks automatically for the standard MAPI client.

As I use Eudora and not OE, this had no success so far. I had to install Windows Messaging and Windows Fax which are on the Win98 CD, but were not installed automatically. Maybe it is necessary to setup a path for the „Post-Office", it doesn't matter which path, it takes „any" path.
The programs can be found somewhere on the Win98 CD, I found them under: Win98 CD -> Tools -> OldWin95 -> message
After installing these, everything worked fine here with Teammail and Win98SE and Eudora.

Windows ME and probably prior (couldn't test it anymore after it worked)

A new thought was brought to us by Roland Bierlein with articles in the newsgroups "de.comm.software.outlook-express" and in "http://smartsuitefaq.vol4u.de" (many thanks to him), which again needs some manipulation of the Windows registry:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\OptionalComponents\MAPI

There you can find the string entry 'Installed' with the value '0' (zero). After changing the value to '1' (one) TeamMail and WinME and Eudore worked properly together, (it did not work after 'simply' installing Windows Messaging and deleting the Teammail key). Maybe this valuechange is enough to get it run without changing and installing as descibed above (for WinME _and_ older Win 9x versions) - would be nice!


#> Export in the Quickbooks export format

This is an example in which data is exported in the Quickbooks export format. The print # statement lays dowm exactly what you want.
Sub QBexport
        '-----QuickBooks(tm) Export Script
        '-----Jerry Sikes 2.7.98
        '-----
        '-----Declare Account Constants
        Const A1$ = "A/R 902:Direct - 902"
        Const A2$ = "Revenue from Sale"
        Const A3$ = "Invoice"
        Const A4$ = "Sale"
        Const A5$ = "Credit Memo"
        Const A6$ = "A/R 902:UWW"
        Const A7$ = "A/R 902:Southeast - 902"
        Dim TypeOfInvoice As String, AccountName As String, DueDate As Variant,td As Variant
        Dim RS As New ResultSet,ay As Integer, am As Integer, ad As Integer
        Dim FileNum As Integer, i As Integer
        Set RS = CurrentDocument.Tables(0).CreateResultSet()
        
        '-----Start Process and Output QB Record Declaration type
        FileNum% = Freefile()
        td = Datevalue(currentview.body.MyList.text)
        ay%=Year(td)
        am%=Month(td)
        ad%=Day(td)
        A8$ = Format(Datenumber(ay%,am%,ad%),"mm-dd-yy") + ".iif"
        TableName$ = "j:\programs\accounting\qbexport\"+  A8$
        Open TableName$ For Output As FileNum%
        Print #FileNum%, "!TRNS"&Chr(9)&"TRNSTYPE"&Chr(9)&"DATE"&Chr(9)&"ACCNT"&Chr(9)& _
            "NAME"&Chr(9)&"AMOUNT"&Chr(9)&"DOCNUM"&Chr(9)&"CLEAR"&Chr(9)&"PONUM"&Chr(9)&"DUEDATE"
        Print #FileNum%,"!SPL"&Chr(9)&"TRNSTYPE"&Chr(9)&"DATE"&Chr(9)&"ACCNT"&Chr(9)& _
            "NAME"&Chr(9)&"AMOUNT"&Chr(9)&"DOCNUM"&Chr(9)&"CLEAR"&Chr(9)&"INVITEM"
        Print #FileNum%, "ENDTRNS!"
        '-----Start Main Process Loop
        Do
                If rs.getvalue(34) = "CN" Then
                        TypeOfInvoice = A5$
                Else
                        TypeOfInvoice = A3$
                End If
                If Left(RS.GetValue(8),1) = "J" Then
                        AccountName = A6$
                Elseif Len(RS.GetValue(8))  = 3 Then
                        AccountName = A7$
                Else    
                        AccountName = A1$
                End If
                td = RS.GetValue(9)   'Current system date
                ay%=Year(td)
                am%=Month(td)
                ad%=Day(td)
                Select Case currentview.body.terms.text
                Case Is = "Net 10"
                        duedate = Datenumber(ay%,am%,ad% + 10)
                Case Is = "1% Net 10"
                        duedate = Datenumber(ay%,am%,ad% + 10)
                Case Is = "Net 30"
                        duedate = Datenumber(ay%,am%,ad% + 30)
                Case Is = "2% 10 Net 26"
                        duedate = Datenumber(ay%,am%,ad% + 26)
                Case Is = "2%10 Net 26"
                        duedate = Datenumber(ay%,am%,ad% + 26)
                Case Is = "2% 10 Net 30"
                        duedate = Datenumber(ay%,am%,ad% + 30)
                Case Is = "2% 10 Net 30"
                        duedate = Datenumber(ay%,am%,ad% + 30)
                Case Is = "COD"
                        duedate = Datenumber(ay%,am%,ad%)
                Case Else
                        duedate = Datenumber(ay%,am%,ad% + 30)
                        
                End Select
                        '-----Output Invoice TRNS LINE
                i% = i% + 1
                Print #FileNum%, "TRNS" & Chr(9) & TypeOfInvoice & Chr(9) & Format(RS.GetValue(9),"mm/dd/yy") & Chr(9) & AccountName _
                       & Chr(9) & RS.GetValue(8) & Chr(9) & RS.GetValue(5) & Chr(9)& RS.GetValue(1) _
                   Chr(9) & "N" & Chr(9) & RS.GetValue(12) & Chr(9) & Format(duedate,"mm/dd/yy") 
                        '-----Output Invoice SPL LINE
                Print #FileNum%, "SPL" & Chr(9) & TypeOfInvoice & Chr(9) & Format(RS.GetValue(9),"mm/dd/yy") & Chr(9) & A2$ _
                   & Chr(9) & RS.GetValue(8) & Chr(9) & -RS.GetValue(5) & Chr(9) & RS.GetValue(1) _
                   & Chr(9) & "N" & Chr(9) & A4$
                Print #FileNum%, "ENDTRNS"
        Loop While RS.NEXTROW
        Close FileNum%
        RS.Close
        Messagebox "Invoices Ready For Import Into QuickBooks. Open QuickBooks and Click on File / Import. Select file " + A8$, 0 + 64, i% &"Records Exported"
End Sub



#> The Approach ODBC SQL server driver

The Approach v97 ODBC SQL server driver has a character limit of  254 (or 256, depending). There is no easy workaround, although there is apparently a complicated one. Basically this requires creating an intermediate database in which memo fields have been broken up into 254 character lots. This could be done either using multiple fields within the same record (in which case you in effect extended the limit to 254 times the number of fields you define) or by splitting the contents of the memo field over several records which all contain a common identifier in another field so that that can be linked together. So, an 800 character memo record would either take up 4 fields in a single record, or be spread over 4 separate records depending which method you use. Memo fields can be split up using the Middle() function.

Note: v9.5 doesn't have this limitation (apparently). I am not sure about the intervening versions of Approach

Search the FAQ for other articles on using Approach as a front-end for SQL tables.


#> ODBC Connection to Oracle database tables

The following combinations have been reported to work:

     v97 to connect to Oracle 7.3.x and 8.1

The Intersolv drivers that come with Approach have a few limitations, including a maximum field length is 254 characters and that you cannot see tables owned by sys or system

Note that object names (tables, fields, etc.) are case-sensitive and names that have no underscores automatically appear with an initial cap regardless of how you entered it. Names with underscores appear as you entered them.


#> Transferring data to the Clipboard

The best method of copying information to the Clipboard in MS-Windows depends on what information you want to copy, and what format you need the copied information to be in.

If you want to copy a number of fields from linked tables as a single block of text (eg a particular [persons name, address, phone number etc...) then you first need to combine all of the information into a single text, variable or memo field and display it on an appropriate view. You can populate the field using a macro attached to a button that combines all of the information you want in the desired format (eg Combine(Customer.firstname, ' ', Customer.surname', ', Customer.addess1, ' ',Customer.addess2, ' ', Customer.addess3).

Once you have it set up, all you need to do is click the button, then click into the field and cut or copy the text as required. Alternatively you can add the following lines to you macro so that it will copy it to the clipboard for you as well:

send keys {TAB}  (add additional tabs if required)
edit copy
send keys {ESC}  (optional, this just deselects the field)  

If even clicking on the button is too much for you, then you can attach the macro to some other event such as any data change on some other field (to do this: go into Design mode, select the desired field, open the info box [Alt-Enter] and select the macro under the desired option in the Macro Tab)

If you want to copy fields as separate cells so that you can paste them as a table into a word processor document or spreadsheet, you first need to create a Worksheet that contains all of the desired fields in each record. To copy the information: 1) Switch to the Worksheet; 2) Find the desired set of records either by using Approach's Find menu item and clicking on EDIT, SELECT ALL, EDIT, COPY VIEW, INCLUDE DATA, ALL DATABASE, OK; or by selecting a block of records by clicking the mouse on the left hand side of the Worksheet next to the first record in the block, then click next to the last record in the block while holding down the  key, then click on EDIT, COPY. Then go to the application where you want to paste the data and paste it.
* You can also do it using LotusScript. See article 'Copying calculated fields to the clipboard' for an example.


#> Accessing information in an Approach database on the web (WWW)

If you want to publish static pages on the web, then you can use FILE / SAVE VIEW AS... / SAVE FILE TYPE = HTML. To save information as database tables on a web server use Approach's 'Saving to Internet' feature (search Approach HELP for more details). If you want to have a live database running, then you need to find an ISP that will let you do some CGI, PHP, or some other scripting, and write or buy the appropriate scripts that you need. These do not come with Approach. 

You can open MySQL databases via the web using its ODBC driver with Approach, as long as the MySQL database resides on a web server and you have a connection to the internet open before attempting to open the db from Approach.

The following words of advice were contributed by Michael Cook:

I've been using Approach to develop databases and making them accessible over the web for about 1 ½ years now.  Here are the major issues:

1. The current (Jan, 2002) implementation of many ODBC database drivers are not thread safe. In your web server configuration, you need to set the ODBC drivers to a single thread configuration; assuming your web server has that ability.  This applies to dBase, FoxPro, Access, and  many Intersolve drivers.

2. If you delete a record using the Approach client, and do not compress the dBase table, an SQL INSERT will no longer work for your browser clients out on the web; i.e. new records will not get written to the Approach dBase table.  Conversely, where your database has parent and child tables (joins), if a record is deleted or updated using a  browser client, a user in an Approach client will not see the change until the dBase table is compressed.  A strategy that I have used is to build in a macro or script in Approach that does a "compress" after a record is deleted, or on APR file open/file close.

3.  Depending on the development environment you are in (PHP, ASP, etc.) you may have some limitations.  For example, dBase tables are NOT recommended if your scripting language is PHP.  The PHP documentation warns that using dBase as your back end tables will result in your tables being corrupted if more than one user accesses your database at the same time.

4. The ODBC drivers do not support indexing over multiple columns (fields), so depending on the size of your tables, searching make take quite a while. If you only need to search on one field, then you can do an SQL CREATE INDEX and index on the chosen field.  This is a different index from what Approach uses.  Approach uses ADX files, and the MS ODBC implementation uses MDX files.  You will have to periodically recreate an MDX index using SQL when new records are added and/or deleted.

If you want to dramatically extend the capabilities of Approach and dBase, check out dB2k at http://www.dbase.com  

I hope this helps.

Mike



#> How to lauch your default browser to view a URL contained in a text field


Create a button to activate a script or macro along the following lines:

Macro: use the Open command and substitute the field contents in the parameter by enclosing tablename.fieldname in double angle brackets. Eg:
 
Open 'http://'<>

This apparently doesn't work in properly in v97.
 
Script: use shell rundll32.exe to invoke the http protocol handler. Say the object name of the fieldbox containing the url is fbxURL

 
Dim intRtn As Integer

intRtn = Shell("rundll32.exe url.dll,FileProtocolHandler http://" & CurrentView.Body.fbxURL.Text)
See article 'A button activated script that launches URL contained in a text field' for more details. ###> Network installation of Approach #> Running Approach on a network You can have multiple Approach applications use the same database at the same time on a network with no problems. The .adx index files are specific to a particular .dbf and they can be shared across any number of .apr files as long as the .apr file formats are the same. Make sure the time and date on all machines are synchronized and have the same file sharing options set, otherwise problems can occur. Also ensure that each machine has plenty of spare hard disk space for temporary files. There is no special network version of Approach. When you are doing the installation you will be asked if it is to go onto a desktop or a server. Check the README.WRI that comes with Approach and the Manual for future information. However, as with all software (executables) you will notice a drop in performance running Approach from the LAN server compared to the running it on a desktop. Some report that the drop in performance is particularly marked if you use calculated fields. The general consensus therefore seems to be that you should run Approach on each desktop individually, but just store the data and the .vew/.apr files on the server. With this configuration the speed of your desktops is more critical than the speed of your server. So if you have a choice, use an older slower computer as the server, and your fastest computers as workstations. This configuration also means you won't be loading your network up with large executables. However, unless you have software distribution software, the "software" person to go nuts if there are 100 workstations to upgrade at some stage in the future... I guess you'll just have to way up the pros and cons. Multiple users can open the APR file and the data file. Approach will handle record locking to prevent people overwriting data someone else updated. Another thing that may influence the performance of the network (and hence Approach) is your choice of protocol. If you are running NT or a peer-to-peer Win 95 network then you will get much better performance out of NetBEUI (a Microsoft protocol) compared to IPX/SPX (a Novell protocol) Note: The file locking protocol (Approach, dBase4, or dBase3 ...) must be the same on all the workstations to maintain the integrity of your files. This is specified in approach.ini (in MS-Windows 95 or earlier) or the registry (in MS-Windows 98 or later). For MS-Windows 95 and earlier, the approach.ini should have one of the following settings: ... To optimize sharing for approach (preferred) use: sdBaseFileSharingMethod=APPROACH ... If applications other than approach may access the dBase4 files use: sdBaseFileSharingMethod=DBASE4 In MS-Windows 98 or later, the registry should contain the following key: HKEY_CURRENT_USER\Software\Lotus\Approach\99.0\General\sdBaseFileSharingMethod = DBASE4. Restart Approach for these settings to take effect. If you are having trouble with network errors, try searching this FAQ for the error message. There are a few articles on different error messages. One problem that frequently drives people up the wall is when a database is made read only using network security or read and write passwords in the .apr, the has user go through several 'file is read only' messages when the database is opened. To get around this, rather than protecting the database files with network security, make different views for the different user types, and make appropriate fields on the forms Read-only. You will not be able to use Worksheets, though. Use network security to control access to the .apr's #> Finding the current Network ID See scripts titled 'Find the current network ID No.1' and 'Find the current network ID No.2' in the 'Example LotusScripts' section of the FAQ. #> Dealing with different paths to the same data from different computers Problems can arise when writing scripts in a database application that runs on a network when the precise path to the database tables or other files depends on what computer you are on. Eg on all the client computers the path might be \\Vaio\database\ or e:\data, but on the server computer the path to the same files may be \\Admin\database\ or c:\data. There are several ways of dealing with this depending on what you are doing. If the files you are looking for are in the same path as the database application (ie. when you are running Approach locally, but the .apr's and data files are on the network), then declare a global string variable called, say, Path [ie put 'DIM Path as String' into (Globals)(Declarations) ] and initialize that variable to the current document path [ie put 'Path = CurrentDocument.Path' into (Globals) Initialize ]. ~However~, apparently there is a bug in v95 to v9.7 in which the Initialize sub doesn't always run (although I personally haven't every encountered this problem. It always works fine in my applications...). If you encounter this problem try putting the path command in a different global sub called, say StartUp, and then call StartUp from a MACRO called OPEN. Approach is designed to always run the a macro call OPEN if it is present when the application opens. If it is not in the exact same path then you can use string functions to create other variations. For instance, a useful one I use a lot is the create and initialize a string variable that contains just the drive information: Drive = Left$(Path, 3). If the path is unrelated and independent of the current document path and/or drive then you have a couple of options. One option is to the DOS SUBST command to create an alias of the same name on each computer that points to the network folder you want to access. An alternate method is to create a text file on each computer which contains a declaration of a constant which contains the path for that computer. Eg. create a text file on every computer called "c:\data\path.txt". The contents of the file should be: 'Const Path = "\\Vaio\database\' or whatever the path is for that computer. Then, in (Globals)(Options) of the .apr put: %INCLUDE "c:\lotus\MachineBackground.txt" Then just use the 'Path' constant wherever you need to specify the path of the files. #> Accessing .dbf files using Novell client 4.83 on Windows 2000 To avoid getting a "file has been damaged" error when trying to access Approach .dbf files stored on a Novell server using Novell client 4.83 on Windows 2000, you apparently need to the Novell client patch from Novell (which updates the NWFS.SYS file) ###> Upgrading Approach and/or your operating system #> Do you need to upgrade? If you are using versions of Approach newer than v3.x, see the article 'Versions of Approach for MS-Windows / NT' in this FAQ to see what the later versions give you, and which version is the best one for your operating systems. Assuming you are running Approach v2.x or 3.x: * If you are running Windows 3.x and using anything prior to v3.02*, then yes you should upgrade to 3.02 at a minimum! * If you are running Windows 95/98 or ME, you have an option to stay where you are or to move up to any newer version, but the best one to start with is v97. With it you get many new features, LotusScript, and you avoid the bugs that were in v96. * If you are running or considering upgrading to Windows 2000 or XP, you will likely find that your older Approach versions no longer work properly and they do not take advantage of the power of these newer operating systems. The 9.7 and 9.8 releases come within SmartSuite only, and are the best 9.x versions for these operating systems. NOTE : If you are upgrading from v3.* to v9.* or later, then it is highly recommended that you first upgrade and convert your database applications to v97, and then upgrade to later versions from there. The rest of this article relates to upgrading from v3.02 to v97 or later: You only really need to upgrade if you want to use LotusScript to create your own functions that are not possible using macros and calculated fields. But there are other "goodies" in the newer releases you will want to consider. Starting with V96/97 many new features were added to make developing your applications easier to do: (And this is not an exhaustive list!) * LotusScript enables sophisticated task automation using an object-oriented BASIC-like programming system. Attach scripts to a wider variety of object-related events than are available when using macros. * New Internet features include the ability to save views as .HTML or save entire applications in a .APT file for sending to remote users or storing on a FTP or web server. * Multiple-page forms - up to 5 pages per form are allowed. * The ability to display a form view as a "dialog box" with tabs for each page. * The Find Assistant helps you create complex queries with the help of an "Assistant" to guide you step-by-step. * The ability to assign names to Finds and Sorts created manually on a view or using the new "Assistant" and run them either directly or from a macro. * A new "Action Bar" with common functions immediately available (Browse, Design, New Records, Find, and select from a list of Named Find/Sorts) * Updated SmartMasters with examples of LotusScript. * Drill-down to data from a chart or crosstab to view the records summarized on a worksheet or other view that you select. * The Message command in a macro can have two buttons labeled by you and set to run other macros of your choice. * TeamSecurity increases data security by providing customized security privileges for individuals or groups. The application designer can set up explicit control over database access privileges, view access, and design privileges. Like all upgrades, earlier versions cannot use the .apr's created / converted to a later version. Newer versions of Approach cannot save .apr's in earlier formats (i.e... v97 and vME cannot save a .apr in v3.02 format). And you should not share databases between users running V3.02 and V97 or V9.x because the "SmartIndex" file formats are different. Firstly, install the new software and install the latest version of the fix pack (available from the XpertSS.com web site's Free Downloads area usually) before you do anything else. Then test thoroughly all parts of your application. Conversion Tips: 1) In order to work reliably, all finds you created within macros should be made into Named Find/Sorts and assigned names. Then update the macro Find command to refer to the named find. 2) If you edit a Find command that references a Named Find/Sort in a macro and then exit the macro editor using the "Cancel" key, you will delete the Named Find Sort (a bug that exists in all versions of Approach to-date). 3) You can't use the Find Assistant for variable field finds. Use a view find instead. If the name of the variable field includes spaces, the correct syntax is @"Name of variable Field" 4) Finds you created with formulas and variable type fields may not work. The problem is the order of the fields in the formula. For example, a find with "If(table.field = variablefield)" will work, but if you have it set up as "If(variablefield = table.field)" it will not. (although this DOES work in v3.02) 5) v96/ v97 are unforgiving regarding mismatched field types when using a variable with a predefined find. The find will not work if the variable field type is not the same as the criteria field (although this DOES work in v3.02). 6) Do not save your .apr on a report, crosstab, or chart view unless you also change your Approach Preferences to not "Show" Report Summaries. Otherwise the .apr will open in Design Mode on that view. 7) The format of your form letters may be corrupted and need recreating. Some people have experienced difficulties with some macros not working after upgrading. If you find some that don't work then you will need to rebuild them. Apparently macros with references to Lotus Notes are particularly susceptible. #> Conversion of old .apr's to Approach 96 The conversion is straight forward, however people have struck problems with stored finds. In order to work reliably, all stored finds should be recreated in Approach 96 and assigned a name. See 'Stored Finds in Approach 96/97'. Once an .apr has been converted it can no longer be used by an older version of Approach. Therefore make sure you keep a copy of your old .apr just in case you strike problems or need the old version for some reason. Your data remains unchanged and can still be access by any version of Approach, as well as any other database program that uses the data format (dBase IV by default) you are using. (MS-Access, Paradox, etc...) #> Approach and Windows NT Reports have been made to the list of problems encountered running Approach v3.0* and v96 on Windows NT v4.0, including losing drives and corrupting .apr's. It is therefore probably not a good idea to do this. However, Approach 97 appears to work fine on NT. Performance can be enhanced by increasing the size of the paging file (ie 'virtual memory on the hard disk). This is done in the NT control panel under systems performance. If after installing NT you find that the layout of your printed reports have all changed, try reinstalling your fonts and printer drivers. #> Upgrading ... Firstly, do you need to upgrade? If you are using anything prior to v3.0* than yes, you need to upgrade! For other versions, see the article 'versions of Approach' in this FAQ to see what the later versions give you, and which version is the best one for your operating systems. If you are upgrading from v3.* to v9.* or later, then it is recommended that you first upgrade and convert you database applications to v97, and then upgrade to later versions from there. The rest of this article relates to upgrading from v3.02 to v96 or later: You only really need to upgrade if you need to use LotusScript to create your own functions that are not possible using macros and calculated fields, or if you need to be able to use the web features. Like all upgrades, earlier versions cannot use the .apr's created / converted to a later version. Newer versions of Approach cannot save .apr's in earlier formats (i.e... v97 and vME cannot save a .apr in v3.02 format). Firstly, install the new software and install the latest version of the fix pack (available from the web site) before you do anything else. In order to work reliably, all stored finds should be assigned a name. In v96 and later an unnamed stored find is only stored as a 'current find' which is then overwritten by any subsequent unnamed stored find. So it is important to name your stored finds. You can't use the assistant for variable finds. Use a view find instead. If the name of the variable field includes spaces, the correct syntax is @"Name of variable Field" v96/ v97 are unforgiving regarding mismatched field types when using a variable with a predefined find. The find will not work if the variable field type is not the same as the criteria field (although this DOES work in v3.02). Some people have reported the following problems: (personally, I encountered none. Ed) The v97 fix pack fixes problems with Export Macros causing GPF's along with other bugs. In v97 reports with outer joins enabled fail to display data in two .apr's. In v96 they wouldn't group correctly but the body was OK. The format of form letters may be corrupted and need recreating. Some people have experience difficulties with some macros not working after upgrading. If you get some that don't work then you will need to rebuild them. Apparently macros with calls to Lotus Notes are particularly susceptible. #> Free Approach 3.02 Upgrade According to the technotes available at the Lotus web site, version 3.02 of Approach is available free to customers experiencing an issue with Approach 3.0. Technotes on the following topics all contain the phrase, 'This issue has been addressed in Approach 3.02': * Only One Mailing Label Prints Per Page * Error: Unable to Build Index Required for XXX * Fill Field Option is Grayed Out in Browse/Worksheet * Stack Overflow Running Approach 3.0 QuickStart Tutor. * Import Table Has Changed, Unable to Import Data * Sending the Current View Only Sends All Views * General Protection Fault in Module KRNL386.EXE * Record Header Size... Bytes Too Small Saving an .APR * Form or Report Places Fields on Top of Each Other * Repeating Panel Will Not Sort in Approach 3.0 * Crosstab Repeats the Same Value in Each Row * Changing Number to Boolean Returns Incorrect Results * Slow Performance using PowerClick for Grand Total * Internal Error - Couldn't Load String 1035 with Spell * Approach Export Macro to Fixed Length Inserts Spaces * Find Using a Wild Card Returns Blank Date Fields * Error: No Records Found Finding Times in DB2 Database * Error: Out of Disk Space Finding a Date in SQL or DB2 * Fields Formatted as Zip Code Corrupt Data in Approach * Error: Macro Step Not Valid Editing Valid Macro * Percent Format Displays Zeros after the Decimal So, if you are having troubles in any of the above areas it may pay to check what version of Approach you have (by selecting Help: About Approach). If you are using 3.00 or 3.01 then you may be able to get a free upgrade to v3.02 by contacting Lotus. #> Approach v97 and Windows 98/vME Many people have reported that when using v97 on Windows 98 and Windows ME the performance in design mode is very poor, but the problem doesn't appear to be universal. Apparently Lotus is aware of the problem and is working on it, but Windows 95 is probably the best for match for v97. If you are using later version of windows then you probably should move to v9.5 or v9.6.* The poor performance arises from Approach making tens of thousands of registry reads for every click you make in design mode. The slowness varies from system to system depending on size of registry, hard disk set up etc. The same click in v9.* versions results in just a handful of registry operations, and is consequently much faster. Download Regmon.exe from http://www.sysinternals.com if you'd like to see what registry calls are being made by any software. Other problems are caused by a conflict with Norton's Anti-Virus software. Make sure you have the latest version of Norton's, including installing the upgrade available from Norton's web site, or else remove it from your system altogether. Just turning it off apparently doesn't always help the problem (although it would be worth a try). One person reported success by wiping their hard drive and starting again, which seems to be a good thing to do when you upgrade the operating system anyway. Another performance suggestions is to turn off the Microsoft "FastFind" option, as that is overhead you do not need. #> Running different versions of Approach concurrently A number of people have reported do this without any problems. However, each version before v97 requires a different .apr's. The following applies to running any pre-v97 version of Approach with any other version of Approach: Since Approach can't save to older versions, it means that .apr's have to be developed on the oldest version that you want to use. Then, open copies of that .apr in the newer versions. BUT you should avoid using different versions to access the same .dbf's they also use different index files (.adx). Therefore you really should create separate copies of the database files (.dbf's) as well, but this creates difficulties if you want to make new entries or changes to that data. So therefore, if you want to share databases so that you can update them, everybody should use the same version. #> Running applications developed in Approach for MS-Windows on OS/2 versions The main thing to be careful of this that you use only True Type fonts. Otherwise you formatting will probably change. Obviuously any calls to Windows specific OLE functions won't work under OS/2 This article was submitted by Ward Scarff : My experiences with apps developed on Win, then run on Os/2 operating system, is restricted to A3.x and A97 (not more recent versions). However, I hope the following items do not hinder your implementation ... * language settings - a continual problem I had in 3.x (and sometimes A97) is the language settings differences between Win machines and OS/2 Warp. A message along the lines of "... can't open dbf because a user has it open in another language ..." often prevented concurrent access. Even when just one person opened the app (without another user in there) Approach would rebuild the indexes for each field as the first new record was entered. Thereafter it worked ok for that user in that session, but if the next user had different language settings (ie likely using the other operating system) then the indexes would rebuild again. * tabbing - at times I have developed on Win and then found that for OS/2 users their tab key will not move them between fields. I thought it was related to a setting in App which treated Enter as tab, but could not get it to work that way. The only way I solved this was to rebuild the offending forms bit by bit. That worked ok - my conclusion was that a form edited/saved many times was too hard for os/2 * drop down lists - this one I have not solved ... sometimes standard Windows functions like typedown do not work on OS/2 machines e.g. you have the user pick from a list of names and expert them to type T to go to the first one on the list. This is a problem for users scrolling through long lists of items. * screen (colours?) - some apps I have done look fine on my Win machine but when I open them up on OS/2, elements of the form are "not there" e.g. short lines of text, or the form label within a text box. Also have noticed that on os/2 some report forms have no column headings, but they print ok. I have never solved this, but perhaps using a narrow range of colours (e.g. the Approach equivalent of browser-safe palette?) might work better. * progress bar - when doing large sorts, exports/imports etc I notice that on OS/2 the progress bar looks slightly different. Not a major issue, but some discerning users may ask why it looks different. * macro pause - most of my report macros use the sequence Find All>run named find >Find again and pause for imput>change view to the report or chart. Sometimes on os/2 the find again and pause for input does not occur, which prevents the user from altering the find criteria if they want to. Note that I use macros, not scripts, so perhaps scripts may work better. #> Installing the Approach 97 apfixpak Apfixpak.exe is a self-extracting file. To update Approach 97 for Windows: 1. Make sure Approach 97 is not running. 2. Copy Apfixpak.exe to your Approach 97 product directory (c:\lotus\Approach\). 3. Click the Start button and choose Run. 4. From the c:\lotus\Approach\ directory Type "Apfixpak.exe -o" on the command line. You can get it from the "free downloads" area on http://www.xpertss.com - Search in Products for Approach and it will be a little way down the list. You can tell it is installed because the approach.exe file will be dated in October 1997. #> Approach and Windows 2000 Crosstabs don't print in v9.5 or v97 under Windows 2000. A number of people has said they were unable to install Approach on Windows 2000 with service pack 1 on it. #> Approach on a Linux server If you use Linux as a file server you can do a network install of Approach onto your Linux server and run it from an MS-Windows workstations without any problems. It apparently doesn't make any difference to the speed of even big database applications compared to running them locally. At last report, Approach will not run on a Linux computer using WINE (a freeware MS-Windows emulator), but will run using Win4Lin (commercial software) if you have Windows 98 installed. #> Dialing phone numbers from within Approach Prior to v9.5 Approach used it's own internal dialer. See the Dialer tab in the FILE / USER SETUP/ PREFERENCES menu In v9.5 and later versions Approach uses the windows dialer which has its own setup. You can use the following script instead of using approachdial so that the name (in Aname) of the person you are calling is displayed in Windows Dialer. Put this bit in declarations: Declare Sub PhCall Lib "tapi32" Alias "tapiRequestMakeCall" (Byval No As String, Byval A As String, Byval B As String, Byval C As String) The create the following script in Globals:
Sub PhoneCall (Number As String, AName As String)
        Dim no As String, nul As String
        no =  Number
        Nul = ""
        PhCall no, nul, Aname, nul
End Sub
The Windows Dialer also maintains a log of calls made that can be accessed with the following LotusScript commands:
with source.parent
     call Phonecall (.Telno, .PersonName)
end with
#> Approach and Windows XP Microsoft's latest Compatibility Update (Dec 2001) covers Approach v9.1, 9.5 and 9.6. v9.7 was XP certified at release anyway. When install v9.7 on Windows XP you get a message stating that there are problems with running Approach on Windows XP. Actually, v9.7 works perfectly fine on XP. Other v9.*'s also run fine except that printing crosstabs doesn't work. (Note: Printing crosstabs from any version before v9.7 doesn't work on any edition Windows, so if this hasn't been a problem for you in the past then it obviously isn't a feature you use anyway!) 16 bit applications such as v3.0* and earlier won't run under XP ###> Building applications and working with .apr's #> Automatically opening files Make sure .apr (.vew for v2.1) extensions are associated with Approach. You can do this in the File/Associate menu of File Manger. Then create a Windows program item with a command line something like: c:\path\database.apr (for >v3.0*) where a:, \path, and database.* are the drive, path, and filename of your database file. To automatically open several files use the command line: c:\approach\approach.exe c:\path\db1.apr c:\path\db2.apr Use .vew instead of .apr for v2.1 files #> Automatically opening a particular view Approach automatically opens the form that you had up on the screen the last time you saved the .apr file (or .vew in v2.1). So next time you make some changes make sure the right form is on the screen when you save it. If you find this annoying, or it isn't working for some reason, you can use either a macro or script to automatically switch you to the desired form. Macro method: Set up a macro to automatically change to that form when the database is opened. (See "Automatic macro on opening/closing View file"). LotusScript method: Place the following script in the initialize event of your database application: Set currentwindow.activeview = currentdocument.YOURFORMNAME CurrentWindow.Browse #> Automatic macro on opening/closing View file You can create a macro that runs automatically each time you open a particular approach view file by assigning it the name "OPEN". Similarly, if you assign the name "CLOSE" to a macro it will run each time you close it's associated file. In version of Approach including and after v96 you can also do it by specifying the macro in the form properties. Some people have experienced Approach 'forgetting' the OPEN macro. This happens if you save the .apr from design mode. If it happens you have to delete then recreate the OPEN macro. So beware of saving in design mode! In v97 the same problem has been report if the tabs are visible. Well..., it keeps life interesting! #> Keeping users out of design environment If you are using v3.0* you can set a design mode password by selecting the Tools/Preferences/Password menu item. Approach will then not let anyone in design unless they know the password (even by status bar, icon or key combination). Read on if you are using v2.1, or if you would also like to remove the temptation of changing the form: Menus can be customized so that the design environment option never appears. Apparently, custom menus are kept in .APR files so that no custom files on user PCs would be required. Icon bars can be customized so the design environment icon never appears. The status bar on the bottom of the Approach window will let the user go into the design environment. The status bar can be suppressed but this prevents the user from reading useful information such as current record number and how many records were found out of how many. There are no Approach macros and formulas that support display of such record information on a form. In v2.1 there is no way to prevent a user from getting into the design environment via CTRL-D. .APR / .VEW files can be made read-only by changing their properties in File Manager, but if a user gets into the design environment, Approach won't tell them they cannot save design changes until they try to save their changes, and they may know how to change the file properties. #> Database security In v2.1 you can give each .dbf a password which is set in the FILE / DATABASE OPTIONS menu in design mode. Passwords can be set for either read-only or read-write access. However, the user has to enter a password for each joined .dbf that requires it. A better alternative may be to create your own security system. The first view that users see could prompt them for an ID and password, this checks against a list of users and sets a variable field to their security level. All macros that switch to a view could then check if the current user has the right access level. In v3.0*, is exactly the same but passwords are set in TOOLS / PREFERENCES. v96 and v97 come with a team security feature. See the manuals and / or help for details. Database encryption (introduced in v96?) will most likely protect the database from any simple attempts at decrypting it, but most methods of encryption are likely to get cracked within the course of a few minutes in the hands of a skilled crypt-analyst with the proper equipment. #> Changing security passwords A design password can only be changed in design mode. If you delete a password in TeamSecurity then you are in effect setting the password to "". Therefore the password dialogue box will still come up. To stop the password dialog box from coming up you need to uncheck the database in the appropriate TeamSecurity section. If you've forgotten the password, there's a recovery service available (for a small fee) at http://www.xpertss.com in the XpertSS Products section. Others which have been mentioned are: * http://www.pwcrack.com/approach.shtml * http://www.bykeyword.com/pages/detail1/download-1144.html #> Stopping people accidentally entering data One way of doing this is to create two separate forms: one for data entry and on for retrieval. Make all the fields on the retrieval form read-only so that data cannot be entered. #> Stopping users from deleting records You can't actually disable the delete function. The easiest way around this is to use a custom menu that doesn't contain Delete Current Record or Delete Found Set so that the user doesn't have access the Delete Record menu item. This also disables the CTRL-Del Hot Key for deleting a record, so they won't be able to use that either. Alternatively you display information in calculated fields and getting its contents from the fieldbox's Text property in LotusScript. CurrentView.Body.CalcFieldName.Text Note that the object name becomes the calculated field name. You can't edit the object name of a control bound to a calc field and if you subsequently rename the calc field the object name doesn't change. This can get very confusing when identifying objects in the IDE! #> Stopping Approach from prompting to save an .apr If you have modifiable text boxes on reports, you will be familiar with the fact that every time you close the .apr after modifying it you are prompted is save the .apr. You can suppress the save prompt with the following script... Sub ClearSaveFlag Currentdocument.modified = False End Sub #> Running a Macro in a different .apr files Using Win 3.1, one way of doing this would be to use the Windows Macros (Recorder) rather than Approach Macros. With the Win 95 versions, it would be easiest to convert the macro/s to Scripts, and then cut and paste them into the new .apr #> Moving a view from one .apr to another The following method can be used to move or copy a view (eg a form or report) from one .apr to another: 1. Save the .apr if you have modified it 2. Save a temporary version of the .apr under a different name, using FILE / SAVE AS menu item with the APR ONLY set. 3. Delete all the views from the temporary .apr except the views you want to transfer. 4. In the .apr you want to transfer the views to, go into DESIGN mode, and import the temporary .apr file using the FILE / Import Approach file... menu item #> Starting Approach without displaying the startup banner When you execute Approach, is you use the -s switch Approach will start without displaying the startup banner. Eg. The following Windows shortcut will start Approach without the startup screen an load people.apr C:\lotus\approach\approach.exe -s c:\_data\people.apr #> User selection of database tables within an .apr For a long time the answer to the questions, "Is it possible for the user to select which database they want to work with within an .apr?", and "Is it possible to use the one .apr to work with different database tables?" was... "No!" However, if you know LotusScript then it is possible! Just check out Jerry Sikes' solution which uses the ReplaceWithResultSet method to allow the user to select a database table from a dropdown list populated from the contents of a directory. See the example LotusScript titled 'User selection of database tables within an .apr' #> Distributing .dbf database files to users It is possible to distribute updated versions of .dbf files for users to access using their existing .apr, as long as the name and structure of the database remains totally unchanged. You should also distribute the new .adx along with it. They just need to replace the old .dbf and .adx (and .dbt if used) with the new copies that you supply. #> Scripts are not imported with an .apr When importing an .apr, the scripts are not imported along with it (up to version v9.6 at least). Hopefully this will be fixed in future versions. ###> Example LotusScripts #> Example LotusScript: Getting the path of a database file You can get the current directory with the CurDir() function and the current drive with the CurDrive() function. Note that while you are using an apr on a drive E:\, the Curdrive$ could still be C:\ so you should maybe use a Chdrive before. Another way, if the dbf are associated with your apr, is to use TableName.Property. Eg: Dim TN, TNF As String TN = CurrentDocument.Tables(i).TableName 'TablesName TNF = CurrentDOcument.Tables(i).FullName 'Full path with extension An example of this method is the following LotusScript function was submitted by Steve Carpenter. If you know the table name it will give you the current path. Function GetTablePath (Byval pTableName As String) As String ' Takes table name and returns path of first occurence of the table from tables ' collection, or "" if table not found. ' 2/9/98 sc GetTablePath = "" Dim Testname As String pTableName = Trim$(Ucase$(pTableName)) Forall mTable In currentdocument.tables() If Instr(mTable.Tablename,":") > 0 Then Testname = Left$(mTable.Tablename,Instr(mTable.Tablename,":") - 1) Else Testname = mTable.Tablename End If If Ucase$(Testname) = pTableName Then GetTablePath = mTable.Path Exit Forall End If End Forall End Function Another example is this following Script, which will bring up a help file which is in the same folder as the current document: Sub RunHelp Dim a as integer a = Shell("WINHELP.EXE "+currentdocument.path+"helpfile.hlp",1) End Sub #> Example LotusScript: Screen updating during script execution Using the REPAINT statement, followed by a 'YIELD' statement. The 'YIELD' statement transfers control to the operating system, so that it can process the events in its queue - including Approach events such as 'REPAINT' as well as non-Approach events. Eg: 'Script submitted by Jerry Sikes Sub Click(Source As Button, X As Long, Y As Long, Flags As Long) Dim buttonlabel As String buttonlabel = source.text source.enabled = False source.text = "Executing Order Update" CurrentWindow.Repaint Yield RunStoredProc("exec ucd.jerry.usp_fg_setvalues_01") source.text = buttonlabel source.enabled = True E #> Example LotusScript: ConvertNumberToText 'Written by Bruno Dumon, 1996 (Belgium) 'Copyright 1996 by Bruno Dumon ' 'Permission is granted to freely copy this script in electronic form, 'or to print for personal use. It may be use in any Approach database, 'but may not be distributed for profit either by itself or as part of 'a collection or database. It may also be used in other programs 'using lotusscript, like WordPro, Notes or Freelance. ' 'Disclaimer: This script is provided as is without any express or implied 'warranties. The author assumes no responsibility for errors or omissions, 'or for damages resulting from the use of the information contained herein. ' 'If you have any suggestions or problems, mail Bruno Dumon at 'dumona@unicall.be. Also, if you make any improvements to it, 'please mail me a copy of it. ' 'How To Use It: '============= 'Copy and paste the three following functions into the script editor: ' - ConvertNumberToText ' - ConvertTwoNumbers ' - ConvertThreeNumbers 'Then, somewhere in your own code, call the ConvertNumberToText 'function by putting: ' result$ = ConvertNumberToText(x) 'The script works for numbers ranging from 1 to 999,999,999. Function ConvertNumberToText(getal) Dim e$(10) Dim t$(10) Dim h$(10) e$(1) = "one" e$(2) = "two" e$(3) = "three" e$(4) = "four" e$(5) = "five" e$(6) = "six" e$(7) = "seven" e$(8) = "eight" e$(9) = "nine" e$(10) = "ten" t$(1) = "eleven" t$(2) = "twelve" t$(3) = "thirteen" t$(4) = "fourteen" t$(5) = "fifteen" t$(6) = "sixteen" t$(7) = "seventeen" t$(8) = "eighteen" t$(9) = "nineteen" t$(10) = "twenty" h$(1)="ten" h$(2)="twenty" h$(3)="thirty" h$(4)="fourty" h$(5)="fifty" h$(6)="sixty" h$(7)="seventy" h$(8)="eighty" h$(9)="ninety" h$(10)="hundred" g$ = Format$(getal) 'Make a string of the number L = Len(g$) If L >=1 Then o1$ = e$(Val(Right$(g$,1))) If Len(g$) = 1 Then r$ = o1$:Goto finished End If If L >= 2 Then o2$ = ConvertTwoNumbers(g$,e$(),h$(),t$()) If Len(g$) = 2 Then r$ = o2$:Goto finished End If If L >=3 Then o3$ = ConvertThreeNumbers(g$,e$(),h$(),t$()) If Len(g$) = 3 Then r$ = o3$:Goto finished End If If L >= 4 Then v$ = Right$(g$,4) If Val(Left$(v$,1)) <> 1 Then o4$ = e$(Val(Left$(v$,1))) + " thousand " + o3$ Else o4$ = " thousand " + o3$ End If If Len(g$) = 4 Then r$ = o4$: Goto finished End If If L >= 5 Then v$ = Right$(g$,5) o5$ = ConvertTwoNumbers(Left$(v$,2),e$(),h$(),t$()) + " thousand " + o3$ If Len(g$) = 5 Then r$ = o5$:Goto finished End If If L >=6 Then v$ = Right$(g$,6) o6$ = ConvertThreeNumbers(Left$(v$,3),e$(),h$(),t$()) + " thousand " + " "+o3$ If Len(g$) = 6 Then r$ = o6$:Goto finished End If If L >= 7 Then v$ = Right$(g$,7) o7$ = e$(Val(Left$(v$,1))) + " million " + ConvertThreeNumbers(Mid$(v$,2,3),e$(),h$(),t$()) + " thousand " + o3$ If Len(g$) = 7 Then r$ = o7$: Goto finished End If If L >= 8 Then v$ = Right$(g$,8) o8$ = ConvertTwoNumbers(Left$(v$,2),e$(),h$(),t$()) + " million " + ConvertThreeNumbers(Mid$(v$,3,3),e$(),h$(),t$()) + " thousand " + o3$ If Len(g$) = 8 Then r$ = o8$: Goto finished End If If L >= 9 Then v$ = Right$(g$,9) o9$ = ConvertThreeNumbers(Left$(v$,3),e$(),h$(),t$()) + " million " + ConvertThreeNumbers(Mid$(v$,4,3),e$(),h$(),t$()) + " thousand " + o3$ If Len(g$) = 9 Then r$ = o9$: Goto finished End If finished: ConvertNumberToText = r$ End Function Function ConvertThreeNumbers(what$,e$(),h$(),t$()) v$ = Right$(what$,3) v2$ = ConvertTwoNumbers(Right$(what$,2),e$(),h$(),t$()) If Left$(v$,1) = "0" Then ConvertThreeNumbers = ConvertTwoNumbers(v$,e$(),h$(),t$()) :Exit Function If Val(v$) = 0 Then ConvertThreeNumbers = "":Exit Function If Val(Left$(v$,1)) <> 1 Then If Val(v2$) <> 0 Then ConvertThreeNumbers = e$(Val(Left$(v$,1))) + " hundred and " + v2$ Else ConvertThreeNumbers = e$(Val(Left$(v$,1))) + " hundred " + v2$ End If Else If Val(v2$) <> 0 Then ConvertThreeNumbers = " hundred and " + v2$ Else ConvertThreeNumbers = " hundred " + v2$ End If End If End Function Function ConvertTwoNumbers(what$,e$(),h$(),t$()) v$ = Right$(what$,2) If Val(v$) >=11 And Val(v$) <= 19 Then ConvertTwoNumbers = t$(Val(v$)-10) Else If Val(Right$(v$,1)) <> 0 Then ConvertTwoNumbers = h$(Val(Left$(v$,1))) + "-" + e$(Val(Right$(v$,1))) Else ConvertTwoNumbers = h$(Val(Left$(v$,1))) End If End If End Function #> Example LotusScript: CurrencyToWords function Submitted by Paul Bent, Northwind IT Systems fCurrencyToWords converts any currency value to text, adds the currency name and handles cents in nn/100 format. It can be adapted to support multiple languages. Public Function fCurrencyToWords(Byval curValue As Currency, _ Byval strCurrency As String) As String '--- Converts a monetary value to words '--- Parameters ' [In] ' curValue the monetary value to be converted. Note the calling proc ' must use CCur() if the value to be passed is not currency data type ' strCurrency name of the currency such as dollars or pounds ' function assumes it is plural '--- Return value ' returns the value in words else an empty string if an error occurred '--- Author Paul Bent, Northwind IT Systems '--- Contact paulbent@nothwindit.co.uk 'Constants representing conversion strings 'Note these could be declared as Public and moved into a LSS file 'There could be several versions of the LSS file to provide multiple language support Const W_MILL = "million" Const W_THOU = "thousand" Const W_HUND = "hundred" Const W_1 = "one" Const W_2 = "two" Const W_3 = "three" Const W_4 = "four" Const W_5 = "five" Const W_6 = "six" Const W_7 = "seven" Const W_8 = "eight" Const W_9 = "nine" Const W_10 = "ten" Const W_11 = "eleven" Const W_12 = "twelve" Const W_13 = "thirteen" Const W_14 = "fourteen" Const W_15 = "fifteen" Const W_16 = "sixteen" Const W_17 = "seventeen" Const W_18 = "eighteen" Const W_19 = "nineteen" Const W_20 = "twenty" Const W_30 = "thirty" Const W_40 = "forty" Const W_50 = "fifty" Const W_60 = "sixty" Const W_70 = "seventy" Const W_80 = "eighty" Const W_90 = "ninety" Dim lngValue As Long 'Integer portion of curValue Dim intNum As Integer 'Digit set being processed in integer portion of curValue Dim intC1 As Integer 'Counter for parsing loop Dim strTmp1 As String 'Temp string buffer Dim strTmp2 As String 'Temp string buffer Dim strRtn As String 'Buffer to build the return string 'Check curValue is not zero or negative If curValue = 0 Then Exit Function 'Get the integer portion of curValue lngValue = Int(curValue) 'Handle cents strRtn = Format$(100 * (curValue - lngValue), "00") & "/100" 'Handle the integer portion If lngValue > 0 Then 'Need to insert " and " before the cents If Len(strCurrency) = 0 Then 'No currency name to be inserted strRtn = " and " & strRtn Else 'Currency name to be inserted, check the plurality 'Might need changes here if not English language If lngValue = 1 Then 'Currency should be singular If Right$(strCurrency, 1) = "s" Then strCurrency = Left$(strCurrency, Len(strCurrency) - 1) End If End If 'Insert the currency name strRtn = strCurrency & " and " & strRtn End If 'Zero prefil to ensure digits processed are in sets of three strTmp1 = "000" & Cstr(lngValue) 'Process chars in strTmp in sets of three from least to most significant Do While Isnumeric(strTmp1) And Val(strTmp1) > 0 'Handle tens and units 'Convert to numeric intNum = Val(Right$(strTmp1, 2)) 'Remove them from the temp buffer strTmp1 = Left$(strTmp1, Len(strTmp1) - 2) 'Initialize the second buffer strTmp2 = "" 'Convert to word If intNum > 9 And intNum 20 Then Select Case intNum - 9 Case 1 strTmp2 = W_10 & " " & strTmp2 Case 2 strTmp2 = W_11 & " " & strTmp2 Case 3 strTmp2 = W_12 & " " & strTmp2 Case 4 strTmp2 = W_13 & " " & strTmp2 Case 5 strTmp2 = W_14 & " " & strTmp2 Case 6 strTmp2 = W_15 & " " & strTmp2 Case 7 strTmp2 = W_16 & " " & strTmp2 Case 8 strTmp2 = W_17 & " " & strTmp2 Case 9 strTmp2 = W_18 & " " & strTmp2 Case 10 strTmp2 = W_19 & " " & strTmp2 End Select Elseif intNum > 0 Then Select Case Val(Right$(Cstr(intNum), 1)) Case 1 strTmp2 = W_1 & " " & strTmp2 Case 2 strTmp2 = W_2 & " " & strTmp2 Case 3 strTmp2 = W_3 & " " & strTmp2 Case 4 strTmp2 = W_4 & " " & strTmp2 Case 5 strTmp2 = W_5 & " " & strTmp2 Case 6 strTmp2 = W_6 & " " & strTmp2 Case 7 strTmp2 = W_7 & " " & strTmp2 Case 8 strTmp2 = W_8 & " " & strTmp2 Case 9 strTmp2 = W_9 & " " & strTmp2 End Select End If If intNum >= 20 Then Select Case Left$(Cstr(intNum), 1) Case "1" strTmp2 = "Error" & " " & strTmp2 Case "2" strTmp2 = W_20 & " " & strTmp2 Case "3" strTmp2 = W_30 & " " & strTmp2 Case "4" strTmp2 = W_40 & " " & strTmp2 Case "5" strTmp2 = W_50 & " " & strTmp2 Case "6" strTmp2 = W_60 & " " & strTmp2 Case "7" strTmp2 = W_70 & " " & strTmp2 Case "8" strTmp2 = W_80 & " " & strTmp2 Case "9" strTmp2 = W_90 & " " & strTmp2 End Select End If 'Handle hundreds intNum = Val(Right$(strTmp1, 1)) strTmp1 = Left$(strTmp1, Len(strTmp1) - 1) If intNum > 0 Then If Len(strTmp2) = 0 Then strTmp2 = W_HUND & " " & strTmp2 Else strTmp2 = W_HUND & " and " & strTmp2 End If Select Case intNum Case 1 strTmp2 = W_1 & " " & strTmp2 Case 2 strTmp2 = W_2 & " " & strTmp2 Case 3 strTmp2 = W_3 & " " & strTmp2 Case 4 strTmp2 = W_4 & " " & strTmp2 Case 5 strTmp2 = W_5 & " " & strTmp2 Case 6 strTmp2 = W_6 & " " & strTmp2 Case 7 strTmp2 = W_7 & " " & strTmp2 Case 8 strTmp2 = W_8 & " " & strTmp2 Case 9 strTmp2 = W_9 & " " & strTmp2 End Select End If 'Handle thousands and greater If Not Len(strTmp2) = 0 Then Select Case intC1 / 3 Case Is 1 strRtn = strTmp2 & strRtn Case 1 If Instr(1, strRtn, W_HUND, 5) > 0 Then strRtn = strTmp2 & W_THOU & " " & strRtn Else strRtn = strTmp2 & W_THOU & " and " & strRtn End If Case Else If Instr(1, strRtn, W_HUND, 5) > 0 Or _ Instr(1, strRtn, W_THOU, 5) > 0 Then strRtn = strTmp2 & W_MILL & " " & strRtn Else strRtn = strTmp2 & W_MILL & " and " & strRtn End If End Select End If 'Increment the digit counter intC1 = intC1 + 3 Loop 'Return value fCurrencyToWords = strRtn End If End Function #> Example LotusScript: Conditional Automatic Entry 'Written by Mr Rhodri Edwards, 1996 '(C) Copyright 1996 by Rhodri Edwards ' 'Permission is granted to freely copy this script in 'electronic form, 'or to print for personal use. It may be 'use in any Approach database, but may not be distributed 'for profit either by itself or as part of a collection or 'database. ' 'Disclaimer: This script is provided as is 'without any express or implied warranties. 'The author assumes no responsibility for errors or 'omissions, or for damages resulting from the use of the information contained 'herein. ' 'This script tests the value held within a text box and if it equals '"Do it" assigns a value to 5 other fields and finishes by tabbing to 'another fieldbox. If CurrentView.Body.Field0.Text = "Do it" Then CurrentView.Body.Field1.Text = "Test1" CurrentView.Body.Field2.Text = "Test2" CurrentView.Body.Field3.Text = "Test3" CurrentView.Body.Field4.Text = "Test4" CurrentView.Body.Field5.Text = "Test5" CurrentView.Body.Field6.SetFocus End If 'This example assumes that all the fields you want to set are not on a 'repeating panel. If they are replace "Body" with "RepeatingPanel". ' 'Field* is where you would put the name of the fieldbox you want to 'set/move to. ' 'The script itself should be attached to the "LostFocus" event of 'field0 (i.e. the field the user fills in). ' 'One important thing to note is: ' 'SetFocus won't work if you are moving from a repeating panel to a body 'part of a form. Instead the field you move to "hovers" in the top 'left hand corner of the s #> Example LotusScript: Create a delimited text file from two fields 'The purpose of this script is to create an delimited text file from 2 fields 'in a database. Field_1 is a text value to output in every record. Field_2 is 'a grouping field. Many records with similiar attributes can be this value. 'The database is sorted by Field_2 prior to Script execution. This script is 'used to export invoice transactions to a mainframe Cost of Sales and Cost of 'Production application. The mainframe input format requires a batch header '(Field_2) to preceed each group of detail records (Field_1). In my App 'Field_1 and Field_2 are calculated fields. I'm testing another variety of 'this as an audit trail or event log on users activity. Sub Click(Source As Button, X As Long, Y As Long, Flags As Long) Dim fileNum As Integer, I As Integer Dim N As Long Dim fileName As String, many_rec As String, few_rec As String, inv_test As String fileNum% = Freefile() fileName$ = Curdrive () +"\WINDOWS\TEMP\DATA.TXT" N=CurrentWindow.NumRecordsFound many_rec$=Source.Field_1.Text ' Field_1 is an Object name for detail text string to output few_rec$=Source.Field_2.Text batch_test$=Source.Field_2.Text ' Field_2 is an Object name for batch section text string to output ' Write out the data. Open fileName$ For Output As fileNum% Write #fileNum%, few_rec$ Write #fileNum%, many_rec$ ' Writes First records information I%=I%+1 Do While I%= N CurrentApplication.ActiveDocWindow.NextRecord I%=I%+1 many_rec$=Source.Field_1.Text few_rec$=Source.Field_2.Text If few_rec$>batch_test$ Then Gosub ResetHeader Write #fileNum%, many_rec Loop Close fileNum% Goto Skip ResetHeader: Write #fileNum%, few_rec$ section_test$=Source.Field_2.Text Return Skip: End Sub 'Written by Jerry Sikes Unisource Converting>, 1996 '(C) Copyright 1996 by Jerry Sikes ' 'Permission is granted to freely copy this script in electronic form, 'or to print for personal use. It may be use in any Approach database, 'but may not be distributed for profit either by itself or as part of 'a collection or database. ' 'Disclaimer: This script is provided as is without any express or 'implied warranties. The author assumes no responsibility for errors or 'omissions, or for damages resulting from the use of the information contained 'herein, or your own version containing your desires for the usage of the 's #> Example LotusScript: Disable the action bar, smart icons, status bar and view tabs 'Written by Jerry Sikes, 1996 'Copyright 1996 by Jerry Sikes ' 'Permission is granted to freely copy this script in electronic form, 'or to print for personal use. It may be use in any Approach database. 'This script was electronically copied in part from Script Editor - 'Help - Approach Objects - Contents - Approach LotusScript Reference '- All Elements A-Z - ActionBarVisible property - Example ' 'Disclaimer: This script is provided as is without any express or implied 'warranties. The author assumes no responsibility for errors or omissions, 'or for damages resulting from the use of the information contained herein. ' 'How to use 'This script allows you to disable the action bar, smart icons, status bar 'and view tabs at program opening. Used in conjunction with a custom menu, 'you can effectively disable a user from any Approach action or event 'that you do not allow. This example is used in Globals - Initialize. 'However, it could be modified as a sub and used conditionally to control actions 'on a form until the action is complete. (Globals) Sub Initialize 'This program performs the same function 'that the Clean Screen menu item on the Edit 'menu does. CurrentWindow.Redraw=False 'Turn off redraw temporarily 'Turn off each bar. CurrentWindow.ActionBarVisible=False CurrentWindow.IconBarVisible=False CurrentWindow.StatusBarVisible=False CurrentWindow.ViewTabVisible=False CurrentWindow.Redraw=True 'Turn it back on CurrentWindow.Repaint 'Now repaint the window. End Sub 'Of interest in this example are the Redraw and Repaint properties. These 'following sub routines work great to freeze the screen during macro 'processing or can be used within other scripts during execution. Named sub 'routines can be called using the run command within the Macro Editor. Sub Freeze_screen CurrentWindow.Redraw=False 'Turn off redraw temporarily End Sub Sub Redraw_screen CurrentWindow.Redraw=True 'Turn it back on CurrentWindow.Repaint 'Now repaint the window. E #> Example LotusScript: Serialized invoice number on billing 'Written by Jerry Sikes, 1996 '(C) Copyright 1996 by Jerry Sikes ' 'Permission is granted to freely copy this script in electronic form, 'or to print for personal use. It may be use in any Approach database, 'but may not be distributed for profit either by itself or as part of 'a collection or database. ' 'Disclaimer: This script is provided as is without any express or implied 'warranties. The author assumes no responsibility for errors or omissions, 'or for damages resulting from the use of the information contained herein In my invoicing application, it is necessary to assign a serialized invoice number when the invoice is billed. The invoice record was created when the order was taken. If this was a make to order job, it could be 1 week per operation before it is ready to bill. I created an invoice number log table with the following fields;inv_no1(serial increment);sub_number(join field with invoice record-unique to each invoice) plus fields with creation formulas to set account number,po number, bill and ship name from the invoice record table. On my main data entry screen, I did not want to leave a fieldbox from the join table, that could accidently be focused on. Accidental click or tab would create a new record in the join table. So I hid it behind a text box and took it out of the tab order. I attached this script to the invoice record inv_no fieldbox. Sub Gotfocus(Source As Fieldbox) If currentview.body.inv_no.text ="" Then 'Checks if an invoice number is already assigned If currentview.repeatingpanel.ITEMNO.TEXT="" Then 'Checks if repeating panel(invoice line items) has at least one item Messagebox "Invoice not ready",MB_OK + MB_ICONSTOP,"Finish Invoice" Else If source.inv_date.text>"" Then 'Forces user to enter invoice date prior to assignment of invoice number currentview.body.inv_no1.SetFocus 'This moves focus to the hidden empty field from invoice number assignment table 'Approach, by definition, creates a new record in the join table when 'typing into an empty join field currentview.body.inv_no.text=currentview.body.inv_no1.text 'new invoice number is set in invoice record from hidden join field currentview.body.terms.SetFocus 'moves focus to invoice terms field Else Messagebox "Enter Invoice Date", MB_OK + MB_ICONEXCLAMATION, "Invalid Date" currentview.body.inv_date.SetFocus End If End If Else Messagebox "Invalid Operation" , MB_OK + MB_ICONEXCLAMATION, "INVOICE NUMBER ALREADY EXISTS" End If End Sub I've sent this script to show syntax use of currentview.body.objectname.text The ".text" syntax is used regardless if the field type is text, numeric or date. If you want to manipulate a numeric field with a mathematical operation, then use Val(currentview.body.numeric_field_object_name.text)*0.6. Date fields have similiar script operators. If your object name(field name) is two words use a ~(tilde) in place of the space. currentview.body.Account~Number.text Jerry Sikes Unisource Conv #> Example LotusScript: Draw rounded rectangles to size (for envelope windows) 'Written by Jerry Sikes, 1996 '(C) Copyright 1996 by Jerry Sikes, Unisource Conveting ' 'Permission is granted to freely copy this script in electronic form, 'or to print for personal use. It may be use in any Approach database, 'but may not be distributed for profit either by itself or as part of 'a collection or database. My company produces envelopes, roughly 8 million per day. Many envelopes have windows cut into them so address, postal barcodes or other information may be displayed. We have about 250 double window dies of various configurations. LotusScript made it possible to accurately draw rounded rectangles of each die, exactly to scale and proportion. The first time a die is input, we use the the size and positional data based on that job. Approach, through formulas, determines absolute coordinates. This is used to compare requests for the same proportions, but perhaps a differant positioning of the die relative to the left and bottom of an envelope. I will not get into the search criteria used in finds. This script shows how to manipulate screen objects locations and size. For referance, 1 inch = 1440 twips. A twip (TWentIeth of a Point) is a measurement equal to 1/1440th of an inch. For referance, input for each window (2 per double die) is, width, height, distance from left edge of envelope to left edge of each die and distance from bottom of envelope to bottom of each die as numeric 2.4. The intersection of the left edge of the left most die and the bottom of the lowest die become coordinates (0, 0). The coordinates for the four corners for each window are then calculated. (X_1, X_2, X_3, X_4. Y_1, Y_2, Y_3, Y_4) Sub Click(Source As Button, X As Long, Y As Long, Flags As Long) Dim ln As LINEOBJECT Dim rb As ROUNDRECT Set rb=Source.body.ObjRoundRect1 rb.Left = 2880+(1440*Val(SOURCE.x_1.TEXT)) 'The 2880 keeps the result no closer than 2 inches from the left of the form rb.Top = 8640-(1440*Val(source.y_1.TEXT)) '8640 is 6 inches from top rb.Width = 1440*Val(source.SIZE_WIDTH_1.TEXT) rb.Height = 1440*Val(SOURCE.SIZE_HEIGHT_1.TEXT) rb.NamedStyle="Default" rb.Background.Color.SetRGB(COLOR_CORNFLOWER) Set rb=Source.body.ObjRoundRect2 rb.Left = 2880+(1440*Val(SOURCE.x_3.TEXT)) rb.Top = 8640-(1440*Val(source.y_3.TEXT)) rb.Width = 1440*Val(source.SIZE_WIDTH_2.TEXT) rb.Height = 1440*Val(SOURCE.SIZE_HEIGHT_2.TEXT) rb.NamedStyle="Default" rb.Background.Color.SetRGB(COLOR_CORNFLOWER) Set ln=Source.body.objLine2 ln.Left = 2880 Set ln=Source.body.objLine3 ln.Top = 8640 'objLine2 & 3 are my 0,0 referance lines Set ln=Source.body.objLine21 If Val(source.x_1.text)>Val(source.x_3.text) Then ln.Left = 2880+(1440*Val(source.x_1.text)) Else ln.Left = 2880+(1440*Val(source.x_3.text)) End If Set ln=Source.body.objLine31 If Val(source.y_2.text)>Val(source.y_4.text) Then ln.Top = 8640-(1440*Val(source.y_2.text)) Else ln.Top = 8640-(1440*Val(source.y_4.text)) End If 'objLine21 and 31 float as necessary E #> Example LotusScript: Using keydown event to automatically enter or modify a date Written by Jerry Sikes Unisource Converting>, 1997 (C) Copyright 1997 by Jerry Sikes Permission is granted to freely copy this script in electronic form, or to print for personal use. It may be used in any Approach database, but may not be distributed for profit either by itself or as part of a collection or database. Disclaimer: This script is provided as is without any express or implied warranties. The author assumes no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein, or your own version containing your desires for the usage of the script. The scheduled manufacturing date of an order in our plant is always set to a Monday's date. (Scheduled week of) All orders for that week are numerically sequenced. The main table for this app is a Lotus Notes view whose selection formula returns only unscheduled orders. The scheduler uses two Approach applications in a tiled top - bottom view. The second app is the same Notes database but based on a Notes view with a selection formula that returns only scheduled orders. The objective of the script is to allow the scheduler to press the + key to return this Mondays date and additional + keystrokes increments the date by 7 days. This script allows normal date typing. It does not intefer with the use of the spacebar to set the current month-day-year. It does not intefer with normal tabbing through the field. Dates in scripting are variants, My source as fieldbox is FoldStartDate, a date field. But when scripting reads a fieldbox, it reads the text representation of the date, thus Datevalue() must be used to convert the text to variant type. DateNumber(Year,Month,Day) is used to modify the date. Year, month and day are integer values and can be additive. DateNumber(97+1,12-1,14+6)=11/20/98. Sub Keydown(Source As Fieldbox, Charcode As Long, Repeats As Integer, Flags As Integer, Overridedefault As Integer) Dim td As Variant,wd As Integer,ay As Integer, am As Integer, ad As Integer If charcode=107 Then currentview.body.fold_id.SetFocus 'I have to temporarily move out of the source field to check/change its contents If source.text="" Then 'True condition when FoldStartDate is blank td = Date$ 'Current system date wd%=Weekday(td) ay%=Year(td) am%=Month(td) ad%=Day(td) source.text=Datenumber(ay% ,am%, (ad%-(wd%-2))) source.setfocus Else 'False condition when FoldStartDate is not blank td = Datevalue(source.text) wd%=Weekday(td) ay%=Year(td) am%=Month(td) ad%=Day(td) source.text=Datenumber(ay% ,am%, (ad%+7)) source.setfocus End If End If End Sub '--------------------------------------------------------------------------- This is the next field in the tab order is called ReadyDate, which indicates the ready date at plant after all production operations. It's keydown script is similiar to the above script but initially uses the FoldStartDate(if not blank) with a + keystroke and then increments by one day each additional + keystroke. Sub Keydown(Source As Fieldbox, Charcode As Long, Repeats As Integer, Flags As Integer, Overridedefault As Integer) Dim td As Variant,wd As Integer,ay As Integer, am As Integer, ad As Integer If charcode=107 Then currentview.body.fold_id.SetFocus If source.text="" Then If currentview.body.FoldStartDate.text="" Then td = Date$ wd%=Weekday(td) ay%=Year(td) am%=Month(td) ad%=Day(td) source.text=Datenumber(ay% ,am%, ad%) source.setfocus Else td = Datevalue(currentview.body.FoldStartDate.text) wd%=Weekday(td) ay%=Year(td) am%=Month(td) ad%=Day(td) source.text=Datenumber(ay% ,am%, ad%) source.setfocus End If Else td = Datevalue(source.text) wd%=Weekday(td) ay%=Year(td) am%=Month(td) ad%=Day(td) source.text=Datenumber(ay% ,am%, (ad%+1)) source.setfocus End If End If E #> Example LotusScript: Launch multiple Approach applications at start-up Written by Jerry Sikes Unisource Converting>, 1997 (C) Copyright 1997 by Jerry Sikes Permission is granted to freely copy this script in electronic form, or to print for personal use. It may be used in any Approach database, but may not be distributed for profit either by itself or as part of a collection or database. Disclaimer: This script is provided as is without any express or implied warranties. The author assumes no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein, or your own version containing your desires for the usage of the script. This global script is attached to an open macro in Approach which forces a second application to open with the first eveytime. It also checks to see if the app is aready open. Sub OpenMyDocs Dim MyDoc As String Dim NumDocs As Integer Dim Docs As Variant Dim MyOpen As String Dim fname As String If(CurrentApplication.Documents.IsEmpty=False) Then NumDocs = CurrentApplication.Documents.count For i = 0 To NumDocs-1 Print CurrentApplication.Documents(i).Name If CurrentApplication.Documents(i).Name="Scheduling" Then MyOpen="True" End If Next End If If MyOpen ="True" Then CurrentApplication.Scheduling.activate Else Set CurrentDocument= CurrentApplication.OpenDocument("Scheduling.apr","f:\orders") End If CurrentApplication.By_Assignment.activate CurrentApplication.ApplicationWindow.domenucommand(IDM_TILE_TOP_BOTTOM) E #> Example LotusScript: Syntax use of currentview.body.objectname.text 'Written by Jerry Sikes, 1997 '(C) Copyright 1997 by Jerry Sikes ' 'Permission is granted to freely copy this script in electronic form, 'or to print for personal use. It may be use in any Approach database, 'but may not be distributed for profit either by itself or as part of 'a collection or database. ' 'Disclaimer: This script is provided as is without any express or implied 'warranties. The author assumes no responsibility for errors or omissions, 'or for damages resulting from the use of the information contained herein I've sent this script to show syntax use of currentview.body.objectname.text The ".text" syntax is used regardless if the field type is text, numeric or date. If you want to manipulate a numeric field with a mathematical operation, then use Val(currentview.body.numeric_field_object_name.text)*0.6. Date fields have similiar script operators. If your object name(field name) is two words use a ~(tilde) in place of the space. currentview.body.Account~ Numbe #> Example LotusScript: Script Launch at Record Change Event 'Written by Jerry Sikes, 1997 '(C) Copyright 1997 by Jerry Sikes ' 'Permission is granted to freely copy this script in electronic form, 'or to print for personal use. It may be use in any Approach database, 'but may not be distributed for profit either by itself or as part of 'a collection or database. ' 'Disclaimer: This script is provided as is without any express or implied 'warranties. The author assumes no responsibility for errors or omissions, 'or for damages resulting from the use of the information contained herein I've been stumbling along with scripting and stumped on how to have a script launch as I browse through each record. Finally I stumbled across how. The event is RecordChange and available only as a DocWindow event. In the script window, under objects, the objects are divided into three sections. Globals, your application and Approach itself. The last object available as you drill down your application objects is DocWindow. Care must be used with attached script. The script will run regardless of the form your on. If - Then - Else statements must be used to control action for a singular form. I have had success with the following: If currentview.name="My Form Name" Then 'add true action here Else 'add false action here. False action is optional. End If The script executes with each change in record number, regardless of the method of c #> Example LotusScript: Check Existing Data and ask for details for new record 'Written by Ian Curry Jist Enterprises Limited>, 1997 '(C) Copyright 1997 by Ian Curry 'Permission is granted to freely copy this script in electronic form, 'or to print for personal use. It may be use in any Approach database, 'but may not be distributed for profit either by itself or as part of 'a collection or database. ' 'Disclaimer: This script is provided as is without any express or 'implied warranties. The author assumes no responsibility for errors or 'omissions, or for damages resulting from the use of the information contained 'herein, or your own version containing your desires for the usage of the 'script. 'Please mail any improvements to the Approach Users Mailing List I have created a credit control and diarying database, database names in CAPS : There are a number of different accounts (ACCTMAIN) each with a number of transactions (TRANMAIN), each transaction can have one action (CURRENT) a current database and then old actions are transferred to history. There are also notes (CURRNOTE) that can be allocated to an account, action or transaction and which are also later transferred to history. The main working screen "Account Action Details" is based on the ACCTMAINDatabase and has 2 repeating panels - CURRNOTE and TRANMAIN. In the repeating panel for the TRANMAIN database (transacspanel) users can enter one action into the CURRENT database. The CURRENT database has a STD Ref, Action Reference, Diary Date, Raised Date ans Completed Date. The following script checks that the diary date is after TODAY() and if it isn't checks with the user to see if they want to change it. Then if the standard reference is 13, a new record is created in the CURRNOTE database and will appear in the other repeating panel. Sub Lostfocus(Source As Fieldbox) Dim DDATE As Variant INITRAN=source.transacspanel.Transaction~ Reference.text ANUMBER=currentview.body.Account~ Number.text DDATE = source.transacspanel.Diary~ Date.text AREF= source.transacspanel.Action~ Reference.text If DDATE="" Then Messagebox ("Please complete a Diary Date") source.transacspanel.Diary~ Date.setfocus End End If If Datenumber(Year(DDATE) , Month(ddate) , Day(DDATE)) Datenumber(Year(Today()) , Month(Today()) , Day(Today())) Then answer% = Messagebox("The Diary Date that you have entered is before today - would you like to change it ?",36,"CCS Warning") If answer% = 6 Then source.transacspanel.Diary~ Date.text="" source.transacspanel.Diary~ Date.setfocus End If Else If source.transacspanel.STDAction.text="13" Then NEWNOTES = Inputbox$( "Please Enter the Notes","CCS Quick Note Entry",,250,250) If NEWNOTES ="" Then End Else answer2% = Messagebox("Does this note only apply to this transaction?",3+32+256,"CCS") If answer2%=2 Then source.transacspanel.STDAction.setfocus End End If Dim con As New Connection Dim qry As New Query Dim rs As New ResultSet If (con.connectto ("dbase IV")>False) Then Set qry.connection = con qry.tablename="m:\group\ba\ccs\currnote.dbf" Set rs.query = qry If ((rs.execute)>False) Then rs.addrow NewValue=rs.setvalue(1,ANUMBER) If answer2%=6 Then NewValue=rs.setvalue(2,INITRAN) End If NewValue=rs.setvalue(3,Today()) Newvalue=rs.setvalue(4,NEWNOTES) NewValue=rs.setvalue(5,AREF) rs.updaterow End If End If con.disconnect End If End If CurrentApplication.ApplicationWindow.DoMenuCommand(IDM_REFRESH) End If E #> Example LotusScript: Lotus Notes SQL script 'Written by Jerry Sikes, 1997 '(C) Copyright 1997 by Jerry Sikes ' 'Permission is granted to freely copy this script in electronic form, 'or to print for personal use. It may be use in any Approach database, 'but may not be distributed for profit either by itself or as part of 'a collection or database. ' 'Disclaimer: This script is provided as is without any express or implied 'warranties. The author assumes no responsibility for errors or omissions, 'or for damages resulting from the use of the information contained herein This script is connected to a button for testing. My production order system exist in Lotus Notes. This script pull values from Notes into an Approach invoicing application. The final version of this script will bypass the inputbox and pull all records assigned to the user as a batch rather than this one at a time version. Sub Click(Source As Button, X As Long, Y As Long, Flags As Long) Dim CON As New CONNECTION Dim QRY As New QUERY Dim RS As New RESULTSET jobcode = Inputbox$("Please Enter Job Number?","Notes Query",,144,144) If jobcode = "" Then Goto Finish If (CON.connectto("Lotus Notes - Workspace", , ,"Production Orders.nsf")>False)Then ‘the actual NSF is prod_env.nsf. Approach recognizes the formal database title as shown if you opened a Lotus Notes Workspace from Approach. This syntax forces Approach to ask for a log in, using the current user id. The session remains active until you quit Approach, even though I’m forcing a disconnect at the end of this script. Set QRY.CONNECTION = CON QRY.TABLENAME = "SPECIALS" ‘ SPECIALS is a form name. A view name could have been used QRY.SQL = "SELECT * FROM""Production Orders.nsf\SPECIALS"" SPECIALS WHERE (SPECIALS.job_no = '"+jobcode+"')" Set rs.query = qry If((rs.execute)>False)Then currentapplication.applicationwindow.domenucommand (IDM_NEWREC) currentview.body.branchno.text = RS.GetValue("branch") If RS.GetValue("order_suffix") = "" Then currentview.body.PONUMBER.text = RS.GetValue("po_number") Else currentview.body.PONUMBER.text = RS.GetValue("po_number") +"-" + RS.GetValue("order_suffix") End If currentview.body.recieved_from.text = RS.GetValue("salesman") currentview.body.SHIP_VIA11.text = RS.GetValue("ship_route") currentview.body.SHIP_TERMS1.text = RS.GetValue("freight_type") currentview.body.comments1.text = Left(RS.GetValue("cnr_card_type") +" "+ RS.GetValue("branch_specs"),110) currentview.body.comments11.text = jobcode + Chr(10) + RS.GetValue("special_ship") currentview.repeatingpanel.ITEMNO.text = RS.GetValue("prod_no") currentview.repeatingpanel.rp_qty.text = RS.GetValue("quantity") currentview.repeatingpanel.rp_sell.text = RS.GetValue("branch_cost_per_m") currentview.body.req_date.text = RS.GetValue("req_ship_date") currentview.body.ship_name.text = RS.GetValue("ship_name") currentview.body.sn2.text = RS.GetValue("sn2") currentview.body.sn3.text = RS.GetValue("sn3") currentview.body.ship_addrs.text = RS.GetValue("ship_addrs") currentview.body.ship_addrs2.text = RS.GetValue("ship_addrs2") currentview.body.ship_city.text = RS.GetValue("ship_city") currentview.body.ship_st.text = RS.GetValue("ship_st") currentview.body.ship_zip.text = RS.GetValue("ship_zip") currentview.body.ship_attn.text = RS.GetValue("ship_attn") currentview.body.ord_date11.text = RS.GetValue("ord_date") currentview.body.ord_date11.SetFocus currentapplication.applicationwindow.domenucommand (IDM_NEXT) ‘commits record Else Messagebox "The Item was not found. Please Try Again", 0 + 16,"Notes Query" End If CON.disconnect End If Finish: E #> Example LotusScript: Read in the Approach User Section in win.ini This script will search the win.ini for an Approach User Section, read the value of the next line and place it into a variable field. You can then use this variable field in new record creation formula to tag who input the record. Sub UserID 'Written by Jerry Sikes , 1997 '(C) Copyright 1997 by Jerry Sikes ' 'Permission is granted to freely copy this script in electronic form, 'or to print for personal use. It may be use in any Approach database, 'but may not be distributed for profit either by itself or as part of 'a collection or database. ' 'Disclaimer: This script is provided as is without any express or 'implied warranties. The author assumes no responsibility for errors or 'omissions, or for damages resulting from the use of the information contained 'herein, or your own version containing your desires for the usage of the 'script. 'Add a section to a workstations win.ini '[Approach User] 'user name 'create a variable field named id_var (type:text) 'make sure this field is present on the start up Form 'run this script via the OPEN macro, which will self execute at apr start. Dim fileName As String, fileNum As Integer Dim id As String, Label As String, MyFlag As String fileNum% = Freefile() 'reserve the next file open number fileName$ = "c:\windows\win.ini" 'name the target MyFlag = "false" 'set the flag Open fileName$ For Input As fileNum% 'open the file for read only Do Until Eof(fileNum%) 'check every line Line Input #fileNum%, Label 'input current line If MyFlag = "true" Then 'test MyFlag id = Label 'Set id to one line below the True flag operation MyFlag = "false" 'reset MyFlag End If If Label = "[Approach User]" Then 'Looking for section MyFlag= "true" 'found it End If Loop currentview.body.id_var.text = id 'set variable field with supplied name Close fileNum% ' close the win.ini E #> Example LotusScript: Handling Approach Object Errors This example stops an error generation when no records from a Named Find called from within LotusScript. In Globals --> Declarations include the following statement on a line by itself. (Help says to leave a blank space after the statement, so I typed a space before a carraige return) %INCLUDE "C:\LOTUS\APPROACH\APRLSERR.LSS" The aprlserr.lss declares as public constants some Approach specific errors. The line "Public Const AprErrNAMEDFIND = 11022" gives you the error handler to use within a script. Open it with a text editor and print it for future reference. This is an example of a button script that calls a Named Find. If no records are found, the flow of control passes to the end: Sub Click(Source As Button, X As Long, Y As Long, Flags As Long) On Error 11022 Goto theend CurrentWindow.NamedFindSort = "A6" Exit Sub theend: Print "Error" Exit Sub E #> Example LotusScript: Error trapping and data manipulation script I wasn't aware of the %INCLUDE "C:\LOTUS\APPROACH\APRLSERR.LSS" ... detailed by Jerry Sikes (see article 'Handling Approach Object Errors') but the following script will trap the same error whilst also containing examples of SQL commands and references to databases that are both on and off the current view Sub Click(Source As Button, X As Long, Y As Long, Flags As Long) Dim TRANID As String, NOTES As String Dim DDATE As Variant, CDATE As Variant, RDATE As Variant Dim AREF As Integer, ANUMBER As Integer, STDREF As Integer, NUMCURR As Integer If source.transacspanel.Action~ Reference.text="" Then 'ie there is no CURRENT record Messagebox "To enter a new action, just choose a STD Action Reference",65,"CCS Message" End Else 'this section sets all values that will be required throughout the script Currentwindow.redraw=False 'prevents the screen from re-drawing TRANID=source.transacspanel.Transaction~ Reference.text DDATE=source.transacspanel.Diary~ Date.text CDATE=Today() RDATE=source.transacspanel.Raised~ Date.text AREF=source.transacspanel.Action~ Reference.text ANUMBER=currentview.body.Account~ Number.text STDREF=source.transacspanel.STDAction.text ' This section is purely used to work out how many transactions (records in CURRENT.DBF) have the same action reference ' therefore whether to remove the note or not Dim con As New Connection Dim qry As New Query Dim rs As New ResultSet If (con.connectto ("dbase IV")>False) Then Set qry.connection = con qry.tablename = "m:\group\ba\ccs\current.dbf" Qry.SQL="SELECT * FROM"""& qry.tablename &"""Current WHERE (Current.""Action Reference"" = "& AREF & ")" Set rs.query = qry If ((rs.execute)>False) Then NUMCURR = (rs.numrows) 'number of records in current with the same action reference End If End If con.disconnect 'End of section for counting transactions 'This section will delete the record from current If (con.connectto ("dbase IV")>False) Then Set qry.connection = con qry.tablename = "m:\group\ba\ccs\current.dbf" Qry.SQL="SELECT * FROM"""& qry.tablename &"""Current WHERE (Current.""Unique Transaction Reference"" = '" & TRANID & "')" 'Note the syntax for TE Set rs.query = qry If ((rs.execute)>False) Then rs.deleterow rs.updaterow End If con.disconnect Dim newdata(1 To 7) As Variant newdata(1)=AREF newdata(2)=ANUMBER newdata(3)=TRANID newdata(4)=DDATE newdata(5)=RDATE newdata(6)=CDATE newdata(7)=STDREF 'And now to add a new record in actions If (con.connectto ("dbase IV")>False) Then Set qry.connection = con qry.tablename="m:\group\ba\ccs\actions.dbf" Set rs.query = qry If ((rs.execute)>False) Then rs.addrow For i=1 To Ubound(newdata) 'Used to enter value in each FIELD NewVAlue=rs.setvalue(i,newdata(i)) Next rs.updaterow End If End If con.disconnect End If 'This section creates a new record in the NOTES database and removes from currnote if required If (con.connectto ("dbase IV")>False) Then Set qry.connection = con qry.tablename = "m:\group\ba\ccs\currnote.dbf" Qry.SQL="SELECT * FROM"""& qry.tablename &"""currnote WHERE (currnote.""Action Reference"" =" & AREF &")" Set rs.query = qry On Error Goto Skip 'An error will occur when there are no notes against a transaction If ((rs.execute)>False) Then NOTES=rs.getvalue(rs.fieldid("Notes")) RDATE=rs.getvalue(rs.fieldid("Date")) ' DDATE is Date of the NOTE If NUMCURR = 1Then rs.deleterow rs.updaterow Else End If End If con.disconnect Dim newdata2(1 To 5) As Variant newdata2(1)=ANUMBER newdata2(2)=TRANID newdata2(3)=RDATE newdata2(4)=NOTES newdata2(5)=AREF If (con.connectto ("dbase IV")>False) Then Set qry.connection = con qry.tablename="m:\group\ba\ccs\notes.dbf" Set rs.query = qry If ((rs.execute)>False) Then rs.addrow For i=1 To Ubound(newdata2) NewVAlue=rs.setvalue(i,newdata2(i)) Next rs.updaterow End If End If con.disconnect End If End If Skip : 'If there are no notes the script will continue from here 'This little section is purely to make the screen update and NOT SHOW deleted records ! currentwindow.redraw=True CurrentApplication.ApplicationWindow.DoMenuCommand(IDM_REFRESH) End 'I needed this to prevent a "No Resume" error when there were no NOTES End Sub I have a large application, the main screen is based on the ACCOUNTS database and contains 2 panels : TRANSACATIONS and CURRNOTES. Against each transaction, the user can enter ACTIONS which can be repeated for more than one transaction. Notes can be entered which refer to a particular action OR transaction. When a new action is required, the current action is transfered to ACTNSOLD alongwith any CURRNOTES being transferred into NOTES so that a history is maintained. --------------------------------------------------------------------- (c) 1997 Ian Curry - Jist, All rights reserved, permission is granted for this document to be distributed in electronic form (such as email, newsgroups, and the WWW) as long as it is posted in its entirety including this copyright statement, and is not distributed for financial #> Example LotusScript: Creating a dot notation text file Sub Create90 '-----Jerry Sikes 01.21.98 '-----This script creates a tab delimited text file '-----It's purpose is create a dot notation string '-----with day of year dot machine id dot shift '-----This will be used with a machine scheduling application '-----where I need to know if a shift is available for a '-----specific machine at some future date. '-----This script is for testing purposes only and does not '-----represent it's final structue. Dim filenum As Integer Dim filename As String Dim rec As DayRecord '-----I previously declare my own data type '-----in Globals...Declarations '-----Type DayRecord ' Machine_Shift_Block As String * 10 ' Shift_Status As String * 3 ' End Type Dim Numeric_Date As Single, Day_of_Year As Single Dim rs As New ResultSet Set rs =CurrentDocument.Tables(1).CreateResultSet() '-----This immediately brings in an already open, join table '-----This is all records from that table. Very fast '-----To determine the table number, I look in the Approach '-----file properties. The table are listed in order 0...n counter1% = 0 Record_Number%=0 filenum% = Freefile() filename$ = "c:\windows\temp\mach_rec.txt" Open filename$ For Output As filenum% 'Open filename$ For Random As filenum% Len = Len(rec) '-----Random stores the info in a binary format. This may be my final output type '-----This way I can call a record by its record number with the Get statement '-----(I have not figure out all the details yet) For counter1% = 0 To 90 Numeric_Date!=Csng(Date)+counter1% Do For shift_number% = 1 To 3 Record_Number%=Record_Number%+1 Day_of_Year! = Csng(Cdat(Numeric_Date)-Datenumber(Year(Date$)-1,12,31)) '-----This mimics the Approach DayOfYear function rec.Machine_Shift_Block = Trim(Str(Day_of_Year!))+"."+ rs.GetValue("id")+"." _ +Trim(Str(shift_number%)) Select Case Weekday(Numeric_Date!) Case Is = 7'-----Saturday rec.Shift_Status = "Off" Case Is = 1'-----Sunday rec.Shift_Status = "Off" Case Else rec.Shift_Status = "On" End Select '-----For those not familiar with VB..case is much better than Nested If...Then...Else Select Case Day_of_Year! Case Is = 100 '-----Good Friday rec.Shift_Status = "Off" Case Is = 145 '-----Memorial Day rec.Shift_Status = "Off" Case 180 To 184'-----Vacation Shutdown rec.Shift_Status = "Off" Case Is = 250'-----Labor Day rec.Shift_Status = "Off" Case 330 To 331'-----Thanksgiving rec.Shift_Status = "Off" Case 355 To 359'-----Vaction Shutdown rec.Shift_Status = "Off" 'No Case Else. Would reset Saturday and Sunday to On End Select Print #fileNum%,Str(Record_Number%)+Chr(9)+rec.Machine_Shift_Block+Chr(9)+rec.Shift_Status 'Put # filenum%,Record_Number%,rec '-----Print # works with Output while Put is for Random Next shift_number% Loop While rs.nextrow rs.firstrow Next counter1% Close filenum% rs.close '-----Always put things away E #> Example LotusScript: Progress bar The following script and class is an reusable progress bar. It is called by script and will divide you data to progress into 10 parts. Run the Sub CreatePBar to make the screen objects on a form. Include the Class "Progress" in your Global declarations. Look at the sample On Click Script at end to see usage example. Jerry Sikes '-----Progress Bar Class '-----Jerry Sikes 2.18.98 'Install Class in Global Declarations Class Progress Public ProgressName As String Public pb(10) As display Public sb(3) As display Private maxValue As Long Private js As Integer Private Sub CheckMax If maxValue = 0 Then Error 999 End Sub Sub Value(v) CheckMax Select Case v Case Is > maxValue * 0.9 pb(10).visible = True Case Is > maxValue * 0.8 pb(9).visible = True Case Is > maxValue *0.7 pb(8).visible = True Case Is > maxValue * 0.6 pb(7).visible = True Case Is > maxValue * 0.5 pb(6).visible = True Case Is > maxValue * 0.4 pb(5).visible = True Case Is > maxvalue * 0.3 pb(4).visible = True Case Is > maxValue * 0.2 pb(3).visible = True Case Is > maxValue * 0.1 pb(2).visible = True Case Else pb(1).visible = True End Select End Sub Sub Max(m) maxValue = m End Sub Sub reset For js% = 1 To 10 pb(js%).visible = False Next End Sub Sub ReplaceText(t) sb(3).text = t End Sub Sub New Set pb(1) = currentview.body.Pbar1 Set pb(2) = currentview.body.Pbar11 Set pb(3) = currentview.body.Pbar12 Set pb(4) = currentview.body.Pbar13 Set pb(5) = currentview.body.Pbar14 Set pb(6) = currentview.body.Pbar15 Set pb(7) = currentview.body.Pbar16 Set pb(8) = currentview.body.Pbar17 Set pb(9) = currentview.body.Pbar18 Set pb(10) = currentview.body.Pbar19 Set sb(1) = currentview.body.Sbar Set sb(2) = currentview.body.Sbar2 Set sb(3) = currentview.body.SText1 For js% = 1 To 3 sb(js%).visible = True Next sb(3).text = "Loading..." End Sub Sub delete For js% = 1 To 10 pb(js%).visible = False Next For js% = 1 To 3 sb(js%).visible = False Next End Sub End Class Sub CreatePbar '-----Progress Bar Objects '-----Jerry Sikes 2.18.98 '-----Install As Global Sub '-----Run From Script Editor to create objects on '-----each desired form '-----I usually group these items after creation to '-----place where I want it to appear. Dim MyRect(12) As rectangle Dim MyText As textbox Dim pb(13) As display For i% = 1 To 12 Set MyRect(i%) = New Rectangle(currentview.body) Set pb(i%) = MyRect(i%) Next Set MyText = New Textbox(currentview.body) Set pb(13) = MyText With pb(11) .name = "SBar" .height = 810 .width = 2250 .left = 4590 .top = 3420 .visible = False .NamedStyle = "Default" .BackGround.Color.SetRGB(COLOR_25_GRAY) .border.pattern = $LtsBorderPatternRaised End With With pb(13) .name = "SText1" .height = 420 .width = 1110 .left = 4680 .top = 3510 .visible = False .text = "Loading..." .border.left = False .border.right = False .border.top = False .border.bottom = False .BackGround.Color.SetRGB(COLOR_25_GRAY) End With With pb(12) .name = "SBar2" .height = 360 .width = 2070 .left = 4680 .top = 3780 .visible = False End With With pb(1) .name = "PBar1" .height = 180 .width = 90 .left = 4860 .top = 3870 .visible = False .BackGround.Color.SetRGB(COLOR_BLUE) .border.pattern = $LtsBorderPatternSolid .Border.Color.SetRGB(COLOR_BLUE) End With With pb(2) .name ="PBar11" .height = 180 .width = 90 .left = 5040 .top = 3870 .visible = False .BackGround.Color.SetRGB(COLOR_BLUE) .border.pattern = $LtsBorderPatternSolid .Border.Color.SetRGB(COLOR_BLUE) End With With pb(3) .name ="PBar12" .height = 180 .width = 90 .left = 5220 .top = 3870 .visible = False .BackGround.Color.SetRGB(COLOR_BLUE) .border.pattern = $LtsBorderPatternSolid .Border.Color.SetRGB(COLOR_BLUE) End With With pb(4) .name = "PBar13" .height = 180 .width = 90 .left = 5400 .top = 3870 .visible = False .BackGround.Color.SetRGB(COLOR_BLUE) .border.pattern = $LtsBorderPatternSolid .Border.Color.SetRGB(COLOR_BLUE) End With With pb(5) .name = "PBar14" .height = 180 .width = 90 .left = 5580 .top = 3870 .visible = False .BackGround.Color.SetRGB(COLOR_BLUE) .border.pattern = $LtsBorderPatternSolid .Border.Color.SetRGB(COLOR_BLUE) End With With pb(6) .name = "PBar15" .height = 180 .width = 90 .left = 5760 .top = 3870 .visible = False .BackGround.Color.SetRGB(COLOR_BLUE) .border.pattern = $LtsBorderPatternSolid .Border.Color.SetRGB(COLOR_BLUE) End With With pb(7) .name = "PBar16" .height = 180 .width = 90 .left = 5940 .top = 3870 .visible = False .BackGround.Color.SetRGB(COLOR_BLUE) .border.pattern = $LtsBorderPatternSolid .Border.Color.SetRGB(COLOR_BLUE) End With With pb(8) .name = "PBar17" .height = 180 .width = 90 .left = 6120 .top = 3870 .visible = False .BackGround.Color.SetRGB(COLOR_BLUE) .border.pattern = $LtsBorderPatternSolid .Border.Color.SetRGB(COLOR_BLUE) End With With pb(9) .name = "PBar18" .height = 180 .width = 90 .left = 6300 .top = 3870 .visible = False .BackGround.Color.SetRGB(COLOR_BLUE) .border.pattern = $LtsBorderPatternSolid .Border.Color.SetRGB(COLOR_BLUE) End With With pb(10) .name = "PBar19" .height = 180 .width = 90 .left = 6480 .top = 3870 .visible = False .BackGround.Color.SetRGB(COLOR_BLUE) .border.pattern = $LtsBorderPatternSolid .Border.Color.SetRGB(COLOR_BLUE) End With pb(12).SendToBack pb(13).SendToBack pb(11).SendToBack End Sub Usage Sample: Sub Click(Source As Button, X As Long, Y As Long, Flags As Long) Dim LocalRS as New ResultSet Dim IsJob List As Long Dim b As New progress CurrentWindow.Repaint Set LocalRS =CurrentDocument.Tables(0).CreateResultSet() localrs.lastrow Call b.max (LocalRs.CurrentRow) localrs.firstrow Call b.ReplaceText("Loading Jobs...") Do Call b.value(LocalRs.CurrentRow) IsJob(LocalRs.GetValue(1)) = LocalRs.CurrentRow Loop While LocalRs.NextRow localrs.firstrow Call b.reset CurrentWindow.Repaint 'The sub could continue with reuse of the Progress bar E #> Example LotusScript: Flashing text When this script is called, the message turns RED, blinks 5 times and then turns black and stops. Notes: "Warn" is a text box with the required message on a view i.e. Please Wait....... The text color of the message is Black. The fill color of the view is white. The flashing color of text is Red. This script was forwarded from the Approach Discussion community on Lotus Support Website. Sub Click(Source As Button, X As Long, Y As Long, Flags As Long) for i = 1 to 5 source.warn.font.color.setrgb(color_red) source.warn.setfocus for q = 1 to 50000 next source.warn.font.color.setrgb_white source.warn.setfocus for q = 1 to 50000 next next source.warn.font.color.setrgb(color_black) E #> Example LotusScript: Import a text file (or .dbf) into a DBF The following was posted to the Approach Users Mailing List by Ankur R. Desai: Sub import Dim t as table 'the table we will replace Dim r as ResultSet 'the object we use to modify the table Dim a$, j% 'extra variables Dim afile as integer 'the file number Set t = CurrentDocument.GetTableByName("tablename") 'Where tablename is the table you want Set r = t.CreateResultSet() 'Saves the hassles of using the connect and query 'At this point however, you could do an SQL query with the Query 'statement to select specific records the following way I think 'r.query.sql = "SELECT ... " 'r.execute() - returns true if successful If r.NumRows() > 0 Then ans = MessageBox("Yo, dis table be not empty, delete it?",4) if ans = 6 Then Call r.FirstRow() 'go to the first row For j = 1 to r.NumRows() Call r.DeleteRow() 'delete it Next end if End if afile = freefile() 'Get a file number to read from Open "filename.txt" For Input As afile 'we open the filename and give it a filenumber you could ask 'the user for the filename with the InputBox statement 'in another message, I can post the routine to call the 'OPEN-CommonDialog to get the filename from a user using 'The standard Windows 95 OPEN box, it's not that hard 'Search Lotuscript on altavista and you'll find it one the 'first page of results Do Until Eof(afile) 'EOF is End of File Line Input #afuke,a$ 'Read in one line - if you have a comma delimted file you 'could use the Input statement to read each item Call r.AddRow() 'Add a row to the table Call r.SetValue("field1",Mid(a$,1,6)) Call r.SetValue("field2",Mid(a$,7,10)+".0") 'Sets field1 to the first 6 characters of a$ 'and field2 to to the next 10adding a .0 in the end Call r.UpdateRow 'This commits the addition to the table Loop 'Around we go Close afile 'Always close any files you open Call CurrentWindow.refresh() 'Refreshes the data in the current window with the updated dbf Call CurrentWindow.repaint() 'And redraw the window 'you could do anything you want at this point 'for example you could do a find on certain records and 'find all records with a specific value and fill field3 with 'a value, ex: Dim myfind as new FIND 'make a new find object Call myfind.And("field1","Horseradish") 'add an AND condition to find all records where field1 = 'Horseradish Call CurrentWindow.FindSort(myfind) 'excute the find Call CurrentWindow.FillField("field3","foobar") 'fill all field3 in the found set with the work Yuck End Sub You can also import another DBF using the Connection property by doing the following: Dim Q as New Query Dim C as New Connection Dim RS as New Resultset If C.ConnectTo("dBASE IV") Then 'Connect to dBASE. Set Q.Connection = C Q.Tablename = "path\filename.dbf" Set RS.Query = Q If (RS.Execute)Then 'Do funky stuff here Call RS.FirstRow() For j = 1 To RS.numrows() Call R.AddRow() Call R.Setvalue("CT_CODE", RS.GetValue("CT_REAS_CD")) Call R.SetValue("CT_DESC",RS.GetValue("CT_REASON")) Call RS.Nextrow() Call R.UpdateRow() ....... Other nice lotusScript functions: c$ = CurrentDocument.GetTableByName("tablename").NumRecords 'Gives you the number of records in a table in your APR 'Could replace "tablename" with CurrentView.MainTable b$ = CurrentWindow.NumRecordsFound 'Gives you the number of records in the current found set 'With these two numbers you can fill in a variable field in a report 'and be able to print out the info in the status bar CurrentView.Footer.Field = "Found "+b$+" o #> Example LotusScript: Linked List class (beats 64K limit on arrays) 'List' is an Approach 97 class that allows you to make dynamic lists of any length. The following notes on its usage were posted to the Approach Users Mailing List by Ankur R. Desai: Dim MyList List 'Note no AS 'or Dim MyList List as Integer 'Thefirst list was a variant list, the second an integer list 'Next cool part - you don't need numbers to reference it: List("Fred") = 12 List("Barney") = 35 List(0) = 2 List(1) = 3 Print List("Fred") 'Values are added in the order of statements List(1) is actually the 'fourth element in the list 'You can of course Erase List 'There's also IsList(MyList) 'and IsElement(MyList("Fred")) 'and in a forall you can use the ListTag statement to get the name of the current element ForAll E in MyList Print ListTag(e) 'will print name of current element e = e + 1 'adds one to each element in list End #> Example LotusScript: Fill Field No.1 Sub FillField 'This script was written by John Brown (of the Approach Users Mailing List) 'It fills a Numeric field with an incremental series of numbers ' eg 1, 2, 3, ... or 3, 6, 9 ... or 10, 7, 5, ... ' 'To use, create a new sub in the Script editor and paste the script over the 'default script contents. Then modify those lines of the script indicated my 'comments Dim Num As Integer Dim Inc As Integer Dim Counter As Integer Num = 1 'This line sets the starting number (change as desired) Inc = 1 'This line sets the increment (change as desired) Counter = 0 Dim rs As New ResultSet Dim C As New Connection Dim Q As New Query If C.ConnectTo("dBASE IV") Then Set Q.Connection = C ' In the next line set the path and filename of your .dbf file (retain the quotes) Q.Tablename = "C:\_DATA\scm\ascm\ascm6.dbf" Set rs.Query = Q If (rs.Execute)Then Call rs.FirstRow Do Until Counter = rs.NumRows 'In the next line replace "PersonID" with your the name of your Numeric field Call rs.SetValue( "PersonID", Num) rs.UpdateRow Num = Num + Inc Counter = Counter +1 If Counter rs.NumRows Then Call rs.NextRow Loop End If End If CurrentDocument.Window.Refresh Messagebox "Done!", 0, "FillField Script" En #> Example LotusScript: Fill Field No.2 This script was sent to the mailing list by Paul Bent (with some comments added by John Brown). It does approximately the same thing as Fill Field No.1, expect that it demonstrates different techniques and has different features: Paul writes: "The table's already opened by the apr so I've used a Table object and the CreateResultSet method instead of a Connection object. I've used a For Next loop instead of a Do loop I made the ID a text field, length 6 and the ID must be 6 long, zero filled from the left - just for fun! I put in the statements to get the start & step values from the user. In real life I would validate the user input but didn't bother for this demo." Sub FillField Dim Tbl As Table, RS As New ResultSet, C As Long, CurVal As Long, IntVal As Long Dim ConfMsg As String, MR As Integer On Error Goto ErrTrap CurVal = Clng(Inputbox$("Please enter the starting ID number:", "Enter ID", "1", 180, 180)) IntVal = Clng(Inputbox$("Please enter the value to increment each ID number by:", "Enter Step", "1", 180, 180)) ConfMsg = "Start value: " & Format$(CurVal, "000000") ConfMsg = ConfMsg & Chr$(10) & Chr$(13) ConfMsg = ConfMsg & "Increment: " & Cstr(IntVal) ConfMsg = ConfMsg & Chr$(10) & Chr$(13) ConfMsg = ConfMsg & Chr$(10) & Chr$(13) ConfMsg = ConfMsg & "Update all records with the new ID numbers ?" MR = 2 MR = Msgbox(ConfMsg,33,"Confirm Update") If MR = 2 Then Goto ExitSub End If Set Tbl = CurrentDocument.Tables(1) 'Use appropriate Table number. Tables are listed in the 'FILE / APPROACH FILE PROPERTIES menu item. 'The first table listed is Table (0), the second is Table (1),... Set RS = Tbl.CreateResultSet RS.FirstRow For C = 1 To RS.NumRows RS.SetValue("PersonID"), Format$(CurVal, "000000") 'Replace PersonID with your field name RS.UpdateRow CurVal = CurVal + IntVal RS.NextRow Next CurrentApplication.ActiveDocWindow.Refresh Msgbox Trim$(Str$(RS.NumRows)) & " records have been updated with new ID numbers.", 64, "Update Completed" Goto ExitSub ErrTrap: Msgbox "Error " & Str$(Err) & " - message: " & Error$, 16, "System Error" Resume ExitSub ExitSub: Exit Sub E #> Example LotusScript: Named Find Event Paul Bent submitted the following script, saying: At http://XpertSS.com we were asked recently how to trigger a script when a named find is run from the list in the Action Bar. Well there is no such event but you can hide the Action Bar and substitute a drop down list box containing the named finds. A script or macro can then run the find on data change in the drop down box. Sub NewFindList Dim aFinds As Variant, UB As Integer, aFStr() As String, C As Integer 'We need an array of variants to get the named finds then a string array to set the list from aFinds = CurrentDocument.NamedFindSorts UB = Ubound(aFinds) 'Now we know how many so resize an array of strings. We need 'data type string to use the SetList method. Redim aFStr(UB) 'Load the strings into the array For C = 0 To UB aFStr(C) = aFinds(C) Next 'Populate a dropdown box list with the string array. 'The dropdown box is named FList and is unbound. When I created it I 'had to type z as the first list item because an empty list is not allowed at creation. CurrentView.Body.FList.SetList(aFStr) End Sub To perform a named find as soon as it is selected, put the following script in the Change Script of the FList object: Sub Change(Source As Dropdownbox) If CurrentView.Body.Flist.Text = "" Then Goto ExitSub CurrentWindow.NamedFindSort = CurrentView.Body.Flist.Text ExitSub: End Sub Alternatively, you perform the find by clicking a button (after you have selected the Named find in the dropdown box), by inserting the following in the Click script of the button object: Sub Click(Source As Button, X As Long, Y As Long, Flags As Long) If CurrentView.Body.Flist.Text = "" Then Goto ExitSub CurrentWindow.NamedFindSort = CurrentView.Body.Flist.Text ExitSub: E #> Example LotusScript: Named Find Event with selection sort This is another version of Paul Bent's Named Find Event script with a selection sort routine added by John Brown Sub Switchto(Source As Form, View As VIEW) Dim aFinds As Variant, UB As Integer, aFStr() As String, C As Integer, Temp As String, Lowest As Integer, Start As Integer 'We need an array of variants to get the named finds then a string array to set the list from aFinds = CurrentDocument.NamedFindSorts UB = Ubound(aFinds) 'Now we know how many so resize an array of strings. We need 'data type string to use the SetList method. Redim aFStr(UB) 'Load the strings into the array For C = 0 To UB aFStr(C) = aFinds(C) Next C ' Selection Sort routine For Start = 0 To (UB -1) Lowest = Start For C = (Start + 1) To UB If aFStr(C) aFStr(Lowest) Then Lowest = C End If Next C If Lowest > Start Then Temp = aFStr(Start) aFStr(Start) = aFStr(Lowest) aFStr(Lowest) = Temp End If Next Start 'Populate a dropdown box list with the string array. 'The dropdown box is named FList and is unbound. When I created it I 'had to type z as the first list item because an empty list is not allowed at creation. CurrentView.Body.FList.SetList(aFStr) E #> Example LotusScript: Named Find Event with a different sort routine This is another version of the Named Find Event script submitted by Paul Bent. This time he has included a sort routine to sort the Named Finds. Sub NewFindList Dim aFinds As Variant, intLB As Integer, intUB As Integer, aFStr() As String Dim intC1 As Integer, intC2 As Integer, intC3 As Integer, varTmp As Variant 'Get the named finds in the apr as an array of variants aFinds = CurrentDocument.NamedFindSorts 'Get the bounds of the array intLB = Lbound(aFinds) intUB = Ubound(aFinds) 'Loop through the array comparing each element with all higher elements 'If the lower element is greater than the higher element then switch them For intC1 = intLB To intUB - 1 For intC2 = intC1 + 1 To intUB If aFinds(intC1) > aFinds(intC2) Then varTmp = aFinds(intC1) aFinds(intC1) = aFinds(intC2) aFinds(intC2) = varTmp End If Next Next 'Now resize an array of strings. We need the finds as data type string 'to use the SetList method. Redim aFStr(intUB) 'Load the strings into the array For intC3 = 0 To intUB aFStr(intC3) = aFinds(intC3) Next 'Populate a dropdown box list with the string array. 'The dropdown box is named FList and is unbound. When I created it I 'had to type z as the first list item because an empty list is not allowed at creation. CurrentView.Body.FList.SetList(aFStr) End S #> Example LotusScript: Find the current network ID No.1 This script was submitted to the Approach Users Mailing List by Steve Carpenter. To get the username you need to access the Windows 95/98 registry, using functions not part of LotusScript but part of the Windows API (Application Programming Interface). LotusScript lets you use external functions if you declare them first and follow the calling conventions. Put the declares in the "Declarations" section of your document under "Globals", then add the function to your scripts. ' Registry Declarations: Declare Public Function RegOpenKeyExA Lib "advapi32" Alias "RegOpenKeyExA" (Byval HKEY As Long,Byval lpszSubKey As String,Byval dwreserved As Integer,Byval samDesired As Long, keyresult As Long) As Long Declare Public Function RegQueryValueExA Lib "advapi32" Alias "RegQueryValueExA" (Byval HKEY As Long,Byval lpszValueName As String,Byval dwreserved As Integer, lpdwtype As Long, Byval lpData As String, readbytes As Long) As Long Declare Public Function RegCloseKey Lib "advapi32" Alias "RegCloseKey" (Byval HKEY As Long) As Long Function GetUserName() ' Returns user name from Windows 9x registry ' 10/22/98 sc (based mainly on a Lotus sample script) Dim happkey As Long Dim HKEY_LOCAL_MACHINE As Long Dim KEY_READ As Long Dim HKEY_CURRENT_USER As Long Dim ValueType As Long Dim ReturnedKeyContents As String * 255 Dim readbytes As Long ReturnedKeycontents$=String$(255,Chr$(32)) Dim Username As String HKEY_LOCAL_MACHINE= &H80000002 HKEY_CURRENT_USER= &H80000001 KEY_QUERY_VALUE=1 KEY_ENUMERATE_SUBKEYS=8 KEY_NOTIFY=16 KEY_READ=KEY_QUERY_VALUE Or KEY_ENUMERATE_SUBKEYS Or KEY_NOTIFY ' this is the key to read KeyName$="Network\Logon" ' this is the value to look up in the key ValueName$="UserName" lstat=RegOpenKeyExA(HKEY_LOCAL_MACHINE,KeyName$,0,KEY_READ,happkey) ReadBytes=255 lstat=RegQueryValueExA(happkey,ValueName$,0,valueType, ReturnedKeyContents$,ReadBytes) regclosekey(happkey) UserName=Left$(ReturnedKeyContents$,ReadBytes-1) UserName=Trim$(UserName) If Len(UserName) = 0 Then GetUsername = "UnknownUser" Else GetUsername = UserName End If End Function #> Example LotusScript: Find the current network ID No.2 The following script was submitted to the Approach Users Mailing List by Bill Tarkulich Using Win32 API "getusername", he did it this way: Declare Function GetUserName& Lib "advapi32.dll" Alias "GetUserNameA" (Byval _ lpBuffer As String, nSize As Long) Dim results As Long Dim Patha As String *200 results = GetUserName(Patha,pa #> Example LotusScript: User selection of database tables within an .apr In this script, Jerry Sikes demonstrates how to use the ReplaceWithResultSet method to allow the user to select which database table they want the .apr to access. This is the ultimate work around for people who need to access more than one database with a single .apr. Sub DropDownExample '-----Jerry Sikes 1998.09.15 '-----To test, create a unbound fieldbox '-----change to dropdown list '-----use automatic values '-----name the object MyDropList Dim lbx As DROPDOWNBOX Dim lbxVal() As String Set lbx = CURRENTVIEW.body.MyDropList Dim pathName As String, fileName As String '----- substitute your path pathName$ = "c:\Lotus\work\Approach\*.dbf" fileName$ = Dir$(pathName$, 0) MyCount% = 0 '----- First do loop counts number of qualifying tables, in path '----- You must limit the tables presented '----- to only those that will map properly '----- if more than one type of table exists in this directory, '----- try using a common prefix on all qualifying tables '----- "x:\path\Z*.dbf" where Z090898.dbf, Z091098.dbf...Zmmddyy.dbf" Do While fileName$ > "" MyCount% = MyCount% + 1 'Print fileName$ fileName$ = Dir$() Loop '-----This sets the number of variables to the correct count Redim lbxVal(MyCount%-1) '-----Reset the counter MyCount% = 0 '-----Force back to top of list fileName$ = Dir$(pathName$, 0) Do While fileName$ > "" '----Load the strings lbxVal(MyCount%) = fileName$ '-----get the next file fileName$ = Dir$() MyCount% = MyCount%+1 Loop '-----Transfer the entire list to the screen object lbx.SetList lbxVal lbx.text = "" End Sub Sub ReplaceTableExample '-----Jerry Sikes 1998.09.15 '-----This assumes the table selected is of identical '-----structure as the original '-----no error trapping '-----it also assumes the target table is table(0) '-----it also assumes, no alias to table(0) '-----in production, this script would be launched on the change event '-----of the drop down list Dim c As New connection Dim qu As New query Dim rs As New ResultSet qu.Tablename = "c:\Lotus\Work\Approach\" & currentview.body.MyDropList.text 'Print qu.tablename Set qu.connection = c Set rs.query = qu If c.connectto("dBASE IV") Then If rs.execute Then RVal = CurrentDocument.tables(0).ReplaceWithResultSet(RS) End If End If E #> Example LotusScript: Pushing selections from one list box to another This script comes care of Paul Bent at XpertSS.com. He has kindly provided use with an example .apr (http://www.johnbrown.com.au/approach/LBoxes.exe ) containing the script so that you can see it in action (41k self-extracting archive. Just download and execute it. The default unzip directory is c:\lotus\approach\demo). Paul explains: Blockquote> This shows how to design a control using two list boxes and use LotusScript to pop selections from one list and push them into the other list. I created the control using a dialog form. On the form I added two unbound fields, made them List Boxes then resized them vertically so they will display the full list without a scroll bar. When I changed them to List Boxes I just typed a z as the list item because an empty list isn't allowed by the Info Box. In this example the list box objects are named UpdList and SelList. UpdList contains the items available for selection and SelList contains items that have been selected already. In a real application I would set the UpdList from a script attached to the dialog form's Switchto event. For this demo you could type in the UpdList items using the Info Box - Apple, Banana, Cherry, Orange, Pear and Peach would do fine. Placed between the two list boxes are four command buttons: Select One >> Remove One Select All >> Remove All Once the selections have been made you would have a "Done" button that runs a script to read the selections from SelList and batch processes them as required. The following global subs are called from the click events of the respective buttons. The public sub, StrSort, bubble sorts arrays containing the list items. /Blockquote> Public Sub AddAll 'Pops all items from lbxUpdList and pushes them into lbxSelList Dim aUpdList() As String Dim RV As Integer, UB As Integer, NB As Integer, C1 As Integer, CurItem As String, CurTag As Integer On Error Goto ErrTrap 'Exit if no items in the list If CurrentView.Body.lbxUpdList.Count = 0 Then Goto ExitSub 'Store the updates list items CurrentView.Body.lbxUpdList.SetFocus UB = CurrentView.Body.lbxUpdList.Count - 1 Redim aUpdList(UB) For C1 = 0 To UB CurrentView.Body.lbxUpdList.CurrentSelection = C1 aUpdList(C1) = CurrentView.Body.lbxUpdList.Text Next 'Pop the items from the updates list For C1 = 0 To UB CurrentView.Body.lbxUpdList.RemoveListItem(0) Next 'If there are already items in the selected list then add them to the array If CurrentView.Body.lbxSelList.Count > 0 Then CurrentView.Body.lbxSelList.SetFocus NB = CurrentView.Body.lbxSelList.Count UB = Ubound(aUpdList) Redim Preserve aUpdList(UB + NB) For C1 = 0 To NB - 1 CurrentView.Body.lbxSelList.CurrentSelection = C1 aUpdList(C1 + UB + 1) = CurrentView.Body.lbxSelList.Text Next End If 'Push the items into the selected list Call StrSort(aUpdList) RV = CurrentView.Body.lbxSelList.SetList(aUpdList) 'Make sure there is a selected item in the selected list CurrentView.Body.lbxSelList.SetFocus CurrentView.Body.lbxSelList.Text = aUpdList(0) Goto ExitSub ErrTrap: Msgbox "Error " & Str$(Err) & " - message: " & Error$, 16, "System Error" Resume ExitSub ExitSub: Exit Sub E #> Example LotusScript: Accessing items in a list box If you are wanting to use a DropDownBox then the news is bad ... you can't get the list items. However, if you use a ListBox then you can. This snippet loads a string array aUpdList with the list items in a ListBox named lbxUpdList 'submitted by Paul Bent, XpertSS.com ' If CurrentView.Body.lbxUpdList.Count > 0 Then UB = CurrentView.Body.lbxUpdList.Count - 1 Redim aUpdList(UB) For C1 = 0 To UB CurrentView.Body.lbxUpdList.CurrentSelection = C1 aUpdList(C1) = CurrentView.Body.lbxUpdList.Text Next #> Example LotusScript: SQL delete This example LotusScript deletes all rows from the table fg_orders. A WHERE clause or any other SQL statement can also be included. You could also create a stored procedure that accepts a parameter. Note that as far as anyone can tell the query method cannot accept return values. 'Submitted by Jerry Sikes Dim con2 As New connection Dim QRY2 As New query Dim RS2 As resultset If (CON2.connectto("SQL Server", "uid","pwd" , "jaxcnvq1")>False)Then Set QRY2.CONNECTION = CON2 qry2.sql = "Delete fg_orders" If Not (qry2.execute) Then Msgbox "Not success" Goto TheEnd End If Msgbox "Success" End If TheEnd: con2.disc #> Example LotusScript: Activating a macro in another APR Jerry Sikes wrote: blockquote> Here is the script method I use to activate a macro in another APR. I have a global sub called OpenMyDocs in the first APR(calling or source APR). It can be called by a click event or run from a macro. This script checks to see if the target application is already open. If true it uses the activate method and if false it use the opendocument method. This is followed by a RunProcedure method. This runprocedure method is how you start a global script in the second APR. The called script can launch a macro with the RunApproachMacro method. The RunProcedure arguments allows a parameter to be passed. This example passes a do nothing parameter. The called or target APR must have a global sub, such as the example OutsideSub shown. Here I accept the do nothing parameter and simply launch the desired macro. One note, if your target application's name has multiple words with spaces, you must be carefull with the activate method syntax. The OpenDocument method uses string quotes to enclosed the apr name. The activate method does not. For example, If I had previously opened the "Inventory Control Program.APR" and switched backed to another APR, the OpenMyDoc sub would find this already open and branch into true section of the MyOpen = "True" if statement. The correct syntax should be: CurrentApplication.Inventory~ Control~ Program.activate The trick is to use a tilde(~) before each space. /blockquote> 'Submitted by Jerry Sikes Sub OpenMyDocs Dim MyDoc As String Dim NumDocs As Integer Dim Docs As Variant Dim MyOpen As String Dim fname As String If(CurrentApplication.Documents.IsEmpty=False) Then NumDocs = CurrentApplication.Documents.count For i = 0 To NumDocs-1 If CurrentApplication.Documents(i).Name="INVYTRANS" Then MyOpen="True" End If Next End If If MyOpen ="True" Then CurrentApplication.INVYTRANS.activate Else Set CurrentDocument=currentapplication.OpenDocument("INVYTRANS.apr","e:\standard\") End If Call currentapplication.RunProcedure("OutsideSub","Hello") End Sub Sub OutsideSub(MyArg As String) RunApproachMacro("Update Records Macro") E #> Example LotusScript: Converting Approach form to MS Word Document This is a small sample of OLE automation between Approach and Word. It copies the current view, intitializes a new instance of the installed version of word and pastes a picture of the approach view. More sophisticated automation, including transfer of formated text is avaiable for a fee. Paste this sub directly into the global area of your application. Create a new marco, choose the run command and select this sub. Switch to the desired view and run the macro. Submitted by Jerry Sikes (Jacksonville Converting) SikesJ01@unisourcelink.com Sub Sub1 Dim wApp As Variant Dim doc As Variant Dim r As Variant CurrentWindow.SelectAll rval = currentwindow.CopyView($aprCurrentView) Set wApp = CreateObject("Word.application") wApp.Application.Visible = True Set doc = wApp.documents.Add() 'wApp.Selection.TypeText "add some text" wApp.Selection.Paste E #> Example LotusScript: Creating a new row in a repeating panel In order to add a new line to a repeating panel the focus (cursor) must be in the repeating panel. This means that your macro will either have to tab into the panel, or you need to attach it to a button which is in the repeating panel such that it appears on every line of the panel. A neater approach is to use a script, such as this one submitted by Paul Bent. Paul writes: "This code is attached to a "New Line" button on an Orders form. The ProductID field is first in the rp's tab order. If the field in the first row is empty there are no existing order lines. In this case it just has to set focus in the first row to start a new record. If there are rows, it sets focus in the first one then starts a new record." Sub Click(Source As Button, X As Long, Y As Long, Flags As Long) On Error Goto ErrTrap If CurrentView.rpOrdItems.cboProductID.Text = "" Then CurrentView.rpOrdItems.ProductID.SetFocus Else CurrentView.rpOrdItems.cboProductID.SetFocus CurrentWindow.NewRecord End If Goto ExitSub ErrTrap: Msgbox "Error " & Str$(Err) & " - message: " & Error$, 16, "System Error" Resume ExitSub ExitSub: End Sub If you want to add the new line at the top of the repeating panel, then check out "Inserting a new blank record at the top of a repeating panel" in the A HREF="examples.htm">Example Databases/A> section of this web #> Example LotusScript: Copying calculated fields to the clipboard The following script was converted to LotusScript by Keith Seeley from Visual Basic routine contained in a Microsoft Office Developers article titled "Creating Reusable Class Modules" by Mike Gilbert (http://www.microsoft.com/officedev/articles/movs109.htm). Keith writes: "Obviously this only works for a predefined field (hardwired into the sub). I use a function key, but anything that can trigger the sub will work. Also note that the error checking in the function is how I got it. Only recently have I been trying to design 'well behaved' apps with error checking, and this is not one of the routines I've gone through." *****Declares Declare Private Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" ( Byval strDest As Any, Byval lpSource As Any, Byval Length As Any) Declare Private Function GlobalAlloc Lib "kernel32" (Byval uFlags As Long, Byval dwBytes As Long) As Long Declare Private Function GlobalFree Lib "kernel32" (Byval hMem As Long) As Long Declare Private Function GlobalLock Lib "kernel32" (Byval hMem As Long) As Long Declare Private Function GlobalUnlock Lib "kernel32" (Byval hMem As Long) As Long Declare Private Function OpenClipboard Lib "user32" (Byval hWnd As Long) As Long Declare Private Function GetClipboardData Lib "user32" (Byval uFormat As Long) As Long Declare Private Function CloseClipboard Lib "user32" () As Long Declare Private Function EmptyClipboard Lib "user32" () As Long Declare Private Function SetClipboardData Lib "user32" (Byval uFormat As Long, Byval hData As Long) As Long 'Clipboard Constants... Private Const GMEM_MOVABLE = &H2& Private Const GMEM_DDESHARE = &H2000& Private Const CF_TEXT = 1 Private Const CANNOTOPENCLIPBOARD = 2 Private Const CANNOTGLOBALLOCK = 4 Private Const CANNOTCLOSECLIPBOARD = 5 Private Const CANNOTGLOBALALLOC = 6 Private Const CANNOTEMPTYCLIPBOARD = 7 Private Const CANNOTSETCLIPBOARDDATA = 8 Private Const CANNOTGLOBALFREE = 9 *****Copy Data Function Function fSendToClipboard(strText As String) As Variant Dim varRet As Variant Dim fStClpData As Long Dim hMem As Long Dim lpMemory As Long Dim lngSize As Long Dim varTemp As Variant varRet = False fStClpData = False lngSize = Len(strText) + 1 hMem = GlobalAlloc(GMEM_MOVABLE Or _ GMEM_DDESHARE, lngSize) If (hMem) =0 Or Isnull(hMem)Then varRet = Error(CANNOTGLOBALALLOC) Goto sTxtDone End If lpMemory = GlobalLock(hMem) If (lpMemory) =0 Or Isnull(lpMemory) Then varRet = Error(CANNOTGLOBALLOCK) Goto sTxtGlblFree End If Call MoveMemory(lpMemory, strText, lngSize) Call GlobalUnlock(hMem) varTemp = (OpenClipboard(0&)) If varTemp=0 Or Isnull(varTemp) Then varRet = Error(CANNOTOPENCLIPBOARD) Goto sTxtGlblFree End If varTemp = (emptyClipboard()) If varTemp=0 Or Isnull(varTemp) Then varRet = Error(CANNOTEMPTYCLIPBOARD) Goto fSendToClipboardCloseClipboard End If varTemp = SetClipboardData(CF_TEXT, hMem) If varTemp=0 Or Isnull(varTemp) Then varRet = Error(CANNOTSETCLIPBOARDDATA) Goto fSendToClipboardCloseClipboard Else fStClpData = True End If fSendToClipboardCloseClipboard: varTemp = closeclipboard() If varTemp=0 Or Isnull(varTemp) Then varRet = Error(CANNOTCLOSECLIPBOARD) End If sTxtGlblFree: If Not fStClpData Then varTemp = globalfree(hmem) If varTemp=0 Or Isnull(varTemp) Then varRet = Error(CANNOTGLOBALFREE) End If End If sTxtDone: fSendToClipboard = varRet End Function *****Representative Sub to copy the data Sub CopyData Dim varRet As Variant Dim strText As String strText = currentview.body.calctest.text varRet = fSendToClipboard(strText) End Sub #> Example LotusScript: A button activated script that launches URL contained in a text field (Contributed by "Paul Bent" paulbent@northwindit.co.uk>) 1. Select the button. On the macros tab of the Info Box, give it a meaningful object name like btnGoToURL. 2. Open the script editor (Ctrl + K) 3. Select Global in Object list, select Options in the Scripts list. Enter these statements in the script pane: (Option Public is probably there already) Option Public Option Explicit Option Compare Nocase 4. Expand the Object list. Click the green twisty by the name of the apr to expand its object collection one level. Locate the name of the view containing the button and click the twisty to expand it. Expand the Body object, locate the name of the button and select it. 5. With the button selected in the Object list, select Click in the Scripts list. Paste this code into the scripts pane so the end result looks like: Sub Click(Source As Button, X As Long, Y As Long, Flags As Long) '--- Opens the default browser and goes to the ' url contained in the URL field of the current record Dim intRtn As Integer 'Function return value On Error Goto ErrTrap intRtn = Shell("rundll32.exe url.dll,FileProtocolHandler http://" _ & CurrentView.Body.fbxURL.Text) Goto ExitSub ErrTrap: 'Non-specific handler Msgbox "Error " & Format$(Err, "#0") & _ " - message: " & Error$, 16, "System Error" Resume ExitSub ExitSub: End Sub 6. Press F2 and OK the no errors msg, press Shift + F2, ditto. Save the apr then #> Example LotusScript: Loading a document into some other application (Contributed by "David Legge" dave.legge@lineone.net>) It is possible to 'tell MS-Windows' to load a document into its default application for any file type recognised by windows using the Shell command. Eg. x = Shell("rundll32.exe url.dll,FileProtocolHandler d:\clipart\acs.pcx") To make like simple you might like to imbed the command in a script like the following: Sub Loadfile( Filename as string) dim intRtn as integer On Error Goto ErrTrap intrtn = Shell("rundll32.exe url.dll,FileProtocolHandler " & Filename) ExitSub ErrTrap: 'Non-specific handler Msgbox "Error " & Format$(Err, "#0") & " - message: " & Error$, 16,"System Error" Resume Next End Sub #> Example LotusScript: A "Translate" function in LotusScript Paul Bent" paulbent@northwindit.co.uk> writes: LotusScript is a language implemented in many Lotus products and it doesn't have a built in function equivalent to Translate. Approach product functions like Translate() that can be used in calc fields, macros etc can't be called in a script (apart from a condition in a Find object). You have to write your own parsing function. Something like: Public Function fReplaceText(Byval strSource As String, _ Byval strOldText As String, Byval strNewText As String) As String '--- Replaces all occurences of strOldText in strSource ' with strNewText '--- Parameters ' strSource: the string in which text is to be replaced ' strOldText: text to be replaced ' strNewText: replacement text '--- Return value ' returns the source string with the text replaced Dim intP1 As Integer 'Position in string Do While Instr(1, strSource, strNewText) > 0 intP1 = Instr(1, strSource, strNewText) strSource = Left$(strSource, intP1 - 1) & strNewText _ & Right$(strSource, Len(strSource)- intP1 - Len(strOldText) + 1) Loop 'Return value fReplaceText = strSource End Function Then you can call the function from any subroutine, eg: CurrentView.Body.fbxFirst.Text = fReplaceText(CurrentView.Body.fbxFirst.Text, "A" #> Example LotusScript: Another "Translate" function in LotusScript "Steven Levine" steve53@earthlink.net> contributed his version of a "translate" function in LotusScript: Function swapchars(target As String, this As String, forthis As String) As String ' replaces every occurance of 'this' in 'target' by 'forthis' ' swapchas is considered to be a local variable within the subroutine Dim at As Integer, limit As Integer, forthislen As Integer swapchars = target at = 1 limit = Len(target)*2 forthislen = Len(forthis) Do at = Instr(at,swapchars,this) If at = 0 Then Exit Do swapchars = Left$(swapchars,at-1) & forthis & Mid$(swapchars,at+1) at = at + forthislen limit = limit-1 Loop Until (limit = 0) End Function #> Example LotusScript: Passing the contents of a field to Google.com "Tony Franks" T.Franks@ccw.gov.uk> writes: For all you folks out there who, like me, are Lotus Script virgins, this is how you do the passing of field contents to Google. First open your database and go into design. Select the field in question and right click for "Field Properties". Click on the "Macro" tab and note the contents of the "Object name" box. Close the "Field Properties" box. Open the Script Editor [Ctrl+K], make sure the first box at the top left corner says (Globals), then paste in the following: Sub www Dim intRtn As Integer Dim strURL As String, googleSearchString As String strURL = "www.google.com/search?sourceid=navclient&querytime=iE&q=" googleSearchString = currentview.body.ObjectName.text strURL = Lcase$(strURL) & googleSearchString intRtn = Shell("rundll32.Received: from CCW_Gateways-MTA exe url.dll,FileProtocolHandler" & strURL) End Sub In the line googleSearchString replace ObjectName for the content you noted previously. Make sure there is a space at the beginning of the google URL after the first quotation mark (or it won't work!). Create a button next to the field, and selecting the button right click for "Field Properties". Select the Macro tab, and click on "Define Macro", and Click on "New". Give the macro a memorable name (eg "Google search for address"). Select the command "Run", and select the "radio button": Run macro. Look in the dropdown list for "www" and select it. Put a tick in the "Return to the next line in this Macro" Click on [OK], Click on [Done] and save everything. Test your Google search button! Thanks are due to Paul Bent, Jerry Sikes, Keith Seeley, and Rainer Schmid for all the help and encourag #> Example LotusScript: Splitting a text field apart at Tabs You can look for a tab character in a text sring using Chr$(9). "Paul Bent" paulbent@northwindit.co.uk> writes: (The following script) loads parsed values into a passed in array and returns it to the calling proc: Public Function fSplitLineByTabs(Byval strLine As String, _ astrData() As String) As Integer '--- Given a tab delimited string, parses it into "fields" '--- and loads them in an array '--- Author: Paul Bent, Nothwind IT Systems, 14-Apr-2001 '--- Parameters ' [In] ' strLine: the string from which to parse the field values ' [In/Out] ' astrData: array to load the field values into '--- Return value ' returns the number of field names placed in the array Dim intP1 As Integer 'Position in string Dim intP2 As Integer 'Position in string Dim intP3 As Integer 'Position in string Dim intC1 As Integer 'Array index 'Initialize the parameter passed in by reference Erase astrData 'Check strLine is not null If Len(strLine) = 0 Then Exit Function 'Parse the field names intP1 = 1 Do While Instr(intP1, strLine, Chr$(9)) > 0 'Size the array Redim Preserve astrData(0 To intC1) intC1 = intC1 + 1 'Get the next tab char intP2 = Instr(intP1, strLine, Chr$(9)) If intP2 > 0 Then 'Get the following tab character intP3 = Instr(intP2 + 1, strLine, Chr$(9)) If intP3 > 0 Then 'If there's another tab char then parse the text between them astrData(intC1) = Mid$(strLine, intP2 + 1, intP3 - intP2 - 1) Else 'Last field in the string astrData(intC1) = Right$(strLine(Len(strLine) - intP2) Exit Do End If 'Reposition the starting point in the input string intP1 = intP2 + 1 Loop 'Return value fSplitLineByTabs = intC1 End Function Then call it from your sub as follows: Dim intC1 As Integer Dim astrData() As String If fSplitLineByTabs(strToBeSplit, astrData) Then For intC1 = Lbound(astrData) To Ubound(astrData) 'Print the values to the Output pane Print astrData(intC1) Next End If #> Example LotusScript: Using Windows 95/98 API to launch another application Paul Bent submitted the following script which demonstrates the use of Windows API to launch another application, stating that it is much better than using the Shell function, as there is no need to know the path or name of the exe and no parsing problems. '[Globals - Declarations] ShellExecute API '--- ShellExecute uses the shell to open or print a file or run a program. '--- Under Win 95/98, this function will also open a My Computer or Explorer window to a given directory. '--- If an executable program is specified, Windows will run that program. '--- If a document file is specified, Windows will open or print it using the associated program (whatever it happens to be). '--- If successful, the function returns a handle to the instance of the opened program '--- or (in the case of printing) a handle to the invoked DDE server application. '--- If unsuccessful, the function returns either 0 (meaning out of memory or resources) or one of the following error code flags: Declare Public Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _ (Byval hwnd As Long, Byval lpOperation As String, Byval lpFile As String, _ Byval lpParameters As String, Byval lpDirectory As String, Byval nShowCmd As Long) As Long 'hwnd The handle of the window calling the function. 'lpOperation The operation to perform on lpFile. "open" means open the file or run the program (or directory in Win 95/98). "print" means print 'the document. In Win 95/98, "explore" means open the directory in an Explorer window. The default is "open". 'lpFile The file to perform the operation on. 'lpParameters Any command-line parameters to pass to an opened application. 'lpDirectory The working directory for the operation. Public Const ERROR_FILE_NOT_FOUND = 2& 'The specified file could not be found. Public Const ERROR_PATH_NOT_FOUND = 3& 'The specified directory could not be found. Public Const ERROR_BAD_FORMAT = 11& 'The specified executable file (.EXE) was somehow invalid. Public Const SE_ERR_ACCESSDENIED = 5 'Win 95/98 only: Windows denied access to the specified file Public Const SE_ERR_ASSOCINCOMPLETE = 27 'The filename association is either incomplete Or invalid Public Const SE_ERR_DDEBUSY = 30 'The DDE action could not run because other DDE actions are in process Public Const SE_ERR_DDEFAIL = 29 'The DDE transaction failed Public Const SE_ERR_DDETIMEOUT = 28 'The DDE transaction was not completed because the request timed out Public Const SE_ERR_DLLNOTFOUND = 32 'Win 95/98 only: The specified DLL file was not found Public Const SE_ERR_FNF = 2 'Same as ERROR_FILE_NOT_FOUND Public Const SE_ERR_NOASSOC = 31 'There is no program associated with the specified type of file Public Const SE_ERR_OOM = 8 'Win 95/98 only: Windows has insufficient memory to perform the operation Public Const SE_ERR_PNF = 3 'Same as ERROR_PATH_NOT_FOUND Public Const SE_ERR_SHARE = 26 'A sharing violation occured Public Const SW_HIDE = 0 'Hide the opened window Public Const SW_MAXIMIZE = 3 'Maximize the opened window Public Const SW_MINIMIZE = 6 'Minimize the opened window Public Const SW_RESTORE = 9 'Restore the opened window (not maximized nor minimized) Public Const SW_SHOW = 5 'Show the opened window Public Const SW_SHOWMAXIMIZED = 3 'Show the opened window maximized Public Const SW_SHOWMINIMIZED = 2 'Show the opened window minimized Public Const SW_SHOWMINNOACTIVE = 7 'Show the opened window minimized but do not activate the it Public Const SW_SHOWNA = 8 'Show the opened window in its current state but do not activate it Public Const SW_SHOWNOACTIVATE = 4 'Show the opened window in its most recent size and position but do not activate it Public Const SW_SHOWNORMAL = 1 'Show the opened window and activate it (as usual) Then call it as follows Dim hWnd As Long 'Approach doc window handle Dim lngRtn As Long 'API function return value hWnd = CurrentWindow.GetHandle lngRtn = ShellExecute(hWnd, "open", "d:\my docs\mypowerpoint.ppt", "/s", "", SW_SHOWNORMAL) #> Example LotusScript: Go back to the last thing that the user was using David Legge writes: First cut and paste this declaration into Global declarations. Then follow the instructions in the first set of comments - they come out green in the IDE (Script editor) Class ViewCollection ' coded by Dave Legge, 2001 ' --------------------------------------------- ' HOW TO DO IT ' 1 Declare global variable ' Dim Views As Viewcollection ' 2 In (Globals.initialise) or in your files documentwindow.openwindow event add the line ' Set Views = New Trailcollection ' 3 in yourdocument's Documentwindow.Viewswitch event place ' Call Views.moveon ToView ' NOTE: up to Apr 9.7 ToView and FromView parameter Declarations are reveresed in the IDE! ' it ought to be Call Views.moveon FromView !!!!! ' 4 From your button.click or worksheet.cellgetfocus event ' Call Views.moveBack ' --------------------------------------------- trail As collection goingback As Integer Sub New ' Print "Calling TrailCollection.New" goingback = False Set trail = New collection ' On Event Viewswitch From currentdocument.DocumentWindow Call moveonevent End Sub Sub moveon ( Fromview As VIEW) If Not goingback Then trail.add fromview 'Push View onto collection ' Print "Push: "; fromview.name End If goingback = False End Sub Sub moveback If trail.count > 0 Then goingback = True ' Print " Pop "; Trail(Trail.count-1).name, trail.count Set CurrentWindow.ActiveView = Trail(Trail.count-1) ' Top one trail.remove(Trail.count-1) ' Pop it Else Messagebox "At start of Trail" & Chr$(10) & "Can't go back any further",64,"BACK" End If Yield ' Let windows take you there before proceeding goingback = False End Sub End Class #> Example LotusScript: Go back to the last thing that the user was using (A different response) Paul Bent writes: You have to use script to get the TS user, this statement will return the username: CurrentDocument.User Where you store this depends on how it will be used later. If it's to be available to scripts then assign it to a global variable. If to be available to macros, calc fields, default creation & mod formulas etc you need to transfer the username to a variable field. You can run a script automatically when the apr opens by placing it in Globals - Initialize but if using later than A97 there's a bug to workaround. You have to: 1. Locate the DocumentOpened sub in the Approach object and enter a single comment character '. This avoids the bug where Initialize doesn't run when the apr opens but only when the first event script fires which can be a lot later. 2. In the Initialize sub, test for the name of the apr because it will now try to run when other aprs are opened too. 3. One other (harmless) bug is that having entered or modified code in the IDE and pressed F2 to test compile it, when you close the apr, Initialize will run! It's only a design-time problem but it throws you a bit to perhaps see an error that can only come from Initialize when you close the apr. So if you were assigning the username to a global variable you'd first declare it in Globals - Declarations: Public gstrUser As String Then assign the user name in the Initialize sub: Sub Initialize On Error Goto ErrTrap 'Check this apr is the active one With CurrentDocument If .Name = "xyz" Then 'Store the username gstrUser = .User 'Switch to the opening view etc '....... End If End With Goto ExitSub ErrTrap: Msgbox "Error " & Format$(Err, "#0") & " - message: " & Error$, 16, "System Error" Resume ExitSub ExitSub: End Sub If you need to transfer the user to a variable field, the only way is via the Text property of a fieldbox on the active view. You can run a one off sub at design-time to make the fieldbox invisible. Say you create a variable field named vUser, option text, add it to a form and give the fieldbox an object name of fbxUser. Create a global sub to make it invisible, use the F5 key in the IDE to run the sub then save the apr. Sub sHideCtrl CurrentView.Body.fbxUser.Visible = False End Sub Then the Initialize sub, instead of/as well as storing the username in the global variable, has to switch to the view containing the variable field and set its Text property: Sub Initialize On Error Goto ErrTrap 'Check this apr is the active one With CurrentDocument If .Name = "xyz" Then 'Store the username in a global variable gstrUser = .User 'Switch to view containing the variable field Set CurrentApplication.ActiveView = .Name~ Of~ View 'Store the username in the variable field CurrentView.Body.fbxUser.Text = .User 'Switch to the opening view etc '....... End If End With Goto ExitSub ErrTrap: Msgbox "Error " & Format$(Err, "#0") & " - message: " & Error$, 16, "System Error" Resume ExitSub ExitSub: End Sub No there isn't a way to "go back" as such. To a limited extent you could do things like when a user switches view, store the "from view" in a global variable and a generic "back" button can switch to the stored v #> Example LotusScript: "Freezing" the screen while executing a LotusScript (Based on a post by David Legge) Easy! Just use the command: currentwindow.redraw = False ... and will stop the window from redrawing automatically. The trick is that you REALLY REALLY need to make sure it gets unfrozen again! To do this set currentwindow.redraw = True at a point where the code is guaranteed to execute otherwise the window will be frozen forever. Best to place it in an error trap, so that if anything goes wrong it will unfreeze the screen: Sub Mysub(......)etc 'Error trap On Error Goto Trap currentwindow.redraw = False ' YOUR CODE ExitSub: currentwindow.redraw = True Exit Sub Trap: Msgbox "Error " & Format$(Err, "####") & " in Mysub" _ & Chr(10) & Error$, 16, "Trapped Error" Resume ExitSub E #> Example LotusScript: Controlling the window size when opening Approach Dave Legge writes: Cut and paste this, into the Lotus Script Editor In Declarations, put: Public Type RECT Left As Long Top As Long Right As Long Bottom As Long End Type Declare Public Function GetDesktopWindow Lib "user32" _ 'The GetDesktopWindow function returns the handle of the Windows desktop window. Alias "GetDesktopWindow" () As Long 'The desktop window covers the entire screen. Declare Public Function GetClientRect Lib "user32" _ Alias "GetClientRect" (Byval hwnd As Long, lpRect As RECT) As Long Declare Public Function MoveWindow Lib "user32" _ Alias "MoveWindow" (Byval hwnd As Long, Byval x As Integer, Byval y As Integer,Byval w As Integer,Byval h As Integer, Byval repaint As Integer) As Long In globals, put: Sub AprWindowsize( wide As Long, high As Long) 'Set Approach application window to wide x high (in pixels) ' and center it on desktop Dim Hdesktop As Long Dim Hapr As Long Dim RDesktop As rect Dim Rapr As rect Dim ok As Long Dim lft As Long Dim top As Long Hdesktop = GetDesktopWindow GetClientRect Hdesktop , Rdesktop Hapr =Currentapplication.applicationWindow.Gethandle If (wide>RDesktop.right) Or (high>Rdesktop.bottom) Then Currentapplication.applicationWindow.maximize Else Hapr = Currentapplication.applicationwindow.gethandle GetClientRect Hapr , Rapr lft = (Rdesktop.right-wide) / 2 top = (Rdesktop.bottom-high)/2 MoveWindow Hapr, lft,top,wide,high,1 ' h,x,y,w,h,true End If End Sub Then in your-document's DocumentWindow, "OpenWindow" Script put: AprWindowsize 790, 595 It resizes and centers on the ###> Unclassified articles #> Generating and reading barcodes You need the Lotus Postal Barcode font (WPPOST1.TTF) which is included with WordPRO. There are really specific instructions on the Lotus web site about this. Just search the knowledgebase in the Approach support area. http://www.lotus.com #> Zip codes and Post codes USA Zip codes are available from: * The v96 CD-ROM includes zipcode.apr, zipcode.adx and zipcode.dbf. zipecode.dbf in the Extra\Dbases directory (78,000 listings) * Download ZIPCODE.ZIP from IBM's Lotus Approach support site: http://www-3.ibm.com/software/lotus/support/approach/support.html. * http://www.lycos.com (enter zipcodes) * Try the US postal service: http://www.usps.gov/ Australian postcodes are available from the Australia Post website in .csv format (ie delimited text) which is easily imported into Approach: http://www.auspost.com.au/postcodes. UK postcodes are made up of two parts: The first part (outward) contains the area and district. The second part (inward) is used by district sorting office and contains the sector and unit. There are 7 formats for post codes: AN NAA; ANN NAA; AAN NAA; AANN NAA; ANA NAA; AANA NAA; AAA ANA. A list of Valid outward post codes is contained in the mailsort database available from http://www.mailsorttechnical.com/. You can down load a very handy Approach database of UK postcodes (valid 2002) here: http://www.johnbrown.com.au/approach/Pcodes.exe [File size: Compressed = 205kb, "uncompressed" = 124kb] #> Recovering deleted records If you have compressed the database then the deleted records have been discarded and cannot be recovered. Your only recourse would be to recover using a good recent backup of the database. If you haven't compressed the database but your database has memo or PicturePlus fields in the deleted records, you can recover the base records but not these types of fields. This is because the "pointer" to them in the .DBT file is zeroed out when the record is marked deleted. These fields would need to be reentered or recovered from a good recent backup of the database by isolating the "deleted records" so that you can export only the fields you need! Or you could take the recovered database and join it to the backup database and copy over the missing fields that way. Some ways to recover deleted records: Note that what you need to do is in some way remove the "deleted" tag from the base records in the .DBF file. 1) Get a utility program designed for the purpose. Some utility programs will let you undelete one record at a time, or all deleted records at once, or simple export all records to another set of files. * One that has been recommended on the mailing list is a small freeware tool called Database Manager, which can be downloaded from http://www.inner-smile.com/ Make sure you read the readme.txt file carefully. You find it has three levels of access, and recovering deleted records requires full access. Deleted records are "grey" in the listing and there is an icon to undelete the selected row. * Another one is dSalvage Pro ($199.95 from http://www.accutek.com/comtech/) which can undelete records and it has a way to rematch memo fields (not PicturePlus fields) to their base records providing you have something in the memo field to identify its base record match. This could be very laborious on a large database or with recovery of many deleted records! There are many more useful features in this utility program to consider when evaluating it. 2) Use the 32-bit ODBC driver and Approach. You can use ODBC to open your .dbf with Approach and recover deleted base records. If you do not already have the 32-bit ODBC option in your Control Panel, download and install the driver for your operating system from Microsoft's web site. The following steps were tested on a W95 system: * Open the ODBC Data Source Administrator from Control Panel. * On the User DSN page, Click the "Add" button to add a data source. * Select the "Microsoft dBase Driver(*.dbf)" driver then click the "Finish" button. * Enter a data source name of your choice and description. * Select the Database Version as dBase IV. * Uncheck the "Use Current Directory" check box. * Click the "Select Directory" button and navigate to the folder where your .dbf file is located. Select the .dbf file name, then the "OK" button. * Click the "Options" button and you will see a checkbox for "Show Deleted Rows" which you must check to see the deleted records. * Open Approach, then use File, Open and select the "ODBC Microsoft dBase Driver(*.dbf)" option in "Files of type:". You will need to navigate down the path double-clicking the "Connection DBASE", then the folder-name path to your ODBC source, and then the .dbf file name. Then click the "Open" button. * Use File, Export Data to export all records to a new dbf, same name, different folder. * Use the new dbf to restore the deleted records as follows: If you do not have any memo or pictureplus fields, the exported .dbf and .adx files will have all the records restored and can be used in place of the original database. Note that the field names and serial number defaults will not be the same as your original database because ODBC does not use the SmartIndex .ADX file, so you may want to import the exported database into the original database with the update and add records option to add back the deleted records and preserve your field definitions. If you have memo or pictureplus fields, you should not use the exported database as a substitute. Import the exported database into the original database with the update and add records option to preserve existing records with all fields, add deleted records, and preserve field definitions. 3) Use a text or hex editor program It is also possible to recover base records by opening the .dbf in a text editor or hex editor, and replacing the asterisk at the beginning of a deleted record with a space character. If you have only one or two records to fix, this may be the simplest method. However, this is not recommended because you may damage the database instead of fixing it! If you decide to try it, use a copy of your .DBF file, PLEASE! #> Turning off screen updates when running a macro The following LotusScript (by Jerry Sikes) turns off Approach's screen redraw function while it runs your macro. A warning though, if something goes wrong while the script/macro is running, then the screen won't be updated to tell you about it...! Sub MyPrint CurrentWindow.Redraw=False 'Turn off redraw temporarily RunApproachMacro("YourMacro") CurrentWindow.Redraw=True CurrentWindow.Repaint End Sub Replace "YourMacro" with the name of your macro. #> Advise when using memo fields... You cannot enter a tab into a memo field like you can into a word processor document. If you want things to "align" in a column, you use spaces and a fixed-width font like Courier. All fields in dBase records are stored in .dbf files with the exception of Memo fields. For Memo fields the .dbf contains a pointer that indicates the location of the memo field data in a corresponding .dbt file of the same name. It is possible for the pointers in the .dbf and the actual data in the .dbt to get out of sync. In this situation the memo box displayed on a view may display the incorrect information or none at all. There is no automatic way of recovering from this, except of course by restoring the files from yesterdays backup you made... However, there is a way that you can protect yourself against this problem: When creating a record, insert the primary key (i.e. a piece of data that uniquely identifies the record) into the memo field in such a way that it can be extracted if needed. This is best done by having a macro insert the primary key at the beginning of the memo field when the field is created. If the memo field ever gets out of sync, then you can then set up some looping macros to extract the primary key from the memo fields and link it back up to the original record. Personally I've used memo fields for years in v2.1 and v97 in order to create this FAQ and store posts to the mailing list, and I have never had a problem. However, others have had a lot of problems. I have no idea why this is! #> Creating a 'Help' file One idea is to create a database with a PicturePlus field and a text or memo field. In the picture field insert an image of the screen that the particular help file entry pertains to. You can capture this image by going to the screen and then hitting the PrtSC (Print Screen) key and then pasting it straight into the PicturePlus field. Alternatively you mat want to paste it into a graphics program (such as 'Paint' that comes with MS-Windows) and edit it first. Then put the require explanation in the text field. A help database such as this can either be search in it's own right, or linked to an application to create a context sensitive help file. Rather than trying to create an exhaustive help file in one go, another approach is to make a small start, and then add entries as it becomes apparent that they are required. This is the way that this FAQ has been created. Every now and then I add a few more entries, and over the years it has become quite extensive. #> Storing pictures When you put a picture into a PicturePlus file, Approach converts the format into its own common format regardless of the external file type. An alternate method is to leave the photo files as separate files and just put a Link into each record, or put the file name into each record and use the OPEN command in a macro to launch another program to view the photo. You could put a small low-res version in a PicturePlus field so that users can preview the picture before loading. Using LotusScript it is possible to use the Picture object to display pictures stored separate on the hard drive. This is the best overall solution that avoids all of the problems with PicturePlus fields. There is a superb example database available for download which shows exactly how this is done in the Example Databases section of this web site. Pictures stored using JPEG format are generally take a lot less file space than using bit maps or .gifs. The following example was submitted to the Approach Users Mailing List: 362K memory size of image 183K *.bmp file size 193K *.gif file size 52K *.jpg file size (low compression) 27K *.jpg file size (moderate compression) Note that the efficiency of jpg compression will vary with the complexity of the image. #> Remote dialup access to Approach Neither Approach nor SmartSuite have inbuilt facilities to accommodate this, so you need other applications to handle the communications. If you're just interested in a remote dialup connection when needed, people have suggested using PC Anywhere or LapLink. This is by far the simplest and cheapest solution but only one remote user can access the host computer at once, and the host computer cannot be used by office staff while a remote users is linked to it. Depending on the complexity of the database and the number of screen redraws required it can be very slow, and so is really limited to situations in which the remote user just needs to access or enter a few records, rather than any major work. A major problem is that neither PC Anywhere or LapLink provides any transaction protection so that if the connection is lost mid-transaction your database could be corrupted costing you time and money... Approach does not contain any inbuilt protection against this. However, someone pointed out that with PC Anywhere or LapLink you are taking control of the host machine (you don't even need to have Approach installed on the computer that you're working on) so that the only data coming down the phone line is only to redraw the screen. All processing is done on the host computer, if a connection breaks the host the integrity of the database files should not be affected... You can download a trial version of PC Anywhere from their web site. To have remote multi-user sessions you really need a client / server network and Dial Up Networking. To accommodate more advanced requirements consider using Notes which can be set up over an IntraNet or for dialin access. The advantages include the ability to have simultaneous users, greater stability, security, transaction protection, scaleability, remote users can have their own local copy which will "replicate" with the server meaning that it is not necessary to maintain a constant phone connection. This last point may make it a cheaper option in the long run. However, it is considerably more expensive (you need a Notes Server licence, plus a Notes Desktop Licence for each user) and you need to be reasonable competent with Notes to set it up initially. #> Multi-line messagebox It is possible to create a messagebox that contains two or more lines. If you create the messagebox in a macro, just hit CTRL-M at the end of each line. If you create the messagebox in LotusScript, then put a Chr$(13) in the string at the end of every line. Eg: Messagebox "First line of text" & Chr$(13) & "Second line of text" #> Tips on using the Script Editor If the script editor is open and you double-click an object in design, that object will be active in the script editor. Unfortunately the script editor Browser Tab doesn't limit the lists to just those items associated with the object you are working on, which can be rather confusing. One way around this is to use the lists provided in the help file instead. In the v97 Script Editor, go the HELP / LOTUS APPROACH 97 OBJECTS menu, select the "classes" index entry and click "Display". You will see a list of all the Approach classes. Once this is open, just click on the class you are interested in, then click "Class members" to see a list of the Properties, Methods, and Events for that class. #> Printing out .apr file properties If you try to print out the .apr file properties, the printout is truncated. The way to get around this is to use the XpertSS Documenter to do that, plus much much more. It is in the XpertSS Products area on http://XpertSS.com #> Setting the auto-incrementing serial number Unfortunately the auto-incrementing serial numbers that you can set up in the Options>>Default values part of the field definition of a numeric field cannot be accessed or changed using a macro or LotusScript. The only way of changing it is via hand, or by using the SendKey command. Alternatively you can ignore the auto-increment function altogether and create your own auto-incrementing serial number. This would allow you to also us a much more meaningful serial number. For example in the following section Sue Sloan explains how to create an auto-incrementing serial number which starts with the year (eg 2002-00001). She write: 1) Set up a new database - I would call it "control" - with a field in it to use for the "next number", a field for the "current year", and a field "link", text, 1 character defaulting to an X and validated as "unique". Enter a starting number in the "next number" field (not a default number or serial number - enter the starting number on a form view). Enter the current year in the "year" field. 2) Add a similar "link" field to your database where you have the field to be numbered. The default value also would be X. Fill that field with X using Fill Field on a worksheet view, Remove the serial numbering default option from the number field in this database and validate it to not be blank. 3) Join the control database to your database using the "link" fields. Set all join options off. 4) Now you must force the user to create new records in your database using a macro and a button. The macro would be: NewRecord . RECORDS New . SET yearfield = control.year . SET numberfield = control.nextnumberfield . SET control.nextnumberfield = control.nextnumberfield + 1 add whatever you need here This works even in a multi-user system because two users cannot get the same control.nextnumberfield value. 5) Now all you need to do is add a macro named OPEN to your application. It goes to a view based on the "control" database and compares Year(Today) to the "year" field. If it is not the same, the "year" is changed and the "next number" is set to 1. OPEN . VIEW switch to control worksheet . RUN If(Year(Today()) = control.year then end macro (or go to whatever macro you wish to go to) . else continue this macro . SET control.year = Year(Today()) . SET control.nextnumberfield = 1 . ENTER . do whatever else you need to do here Note that the only danger in having this run automatically when the Approach file opens is that you may have a user with his/her computer date set incorrectly. You may want to add a test to make sure the Year(Today()) is > control.year, for example. #> Quick access to objects in the script editor If you are sick and tired of trying to find what you are looking for in the Objects dropdown list in the Script Editor, then just minimize the Script Editor and double-click the object on your view that you want to access the scripts for. The InfoBox will appear, but just ignore that. Instead, click on the minimize Script Editor to bring it up and you'll find that it is now the scripts associated with the object you just clicked on ! #> Automatically saving your work Data is automatically saved once you enter it, so you don't every need to do anything to "save" it. On the other hand, all of your forms, reports, Named Finds, macros and LotusScripts are only saved when you select FILE / SAVE. Unfortunately there isn't any facility in Approach to get it to automatically save your work on a periodic basis. However, if you are developing script are a bit forgetful about periodically saving your work, then you may want to consider adding the following line to the current script you are working on so that your changes will be automatically saved each time you run the script (don't forget to remove it once you finished developing that script): Current.Window.SaveChanges ####> How the Approach Users Mailing List works ##>: Contributors The list is people who have contributed to this FAQ now contains over 125 names! You can see the list at the following URL: http://www.johnbrown.com.au/approach/official.htm#acknowledgements If you would like you name added to this esteemed list, please feel free to post some helpful suggestions and answers to the Approach Users Mailing List. ##>: The Approach Users Mailing List This is a discussion area for anyone uses or provides user support for the Lotus Approach relational database. Subscribers receive an occasional newsletter summarizing recent additions to the FAQ as well as other relevant information and notices. A copy of part 1 of the latest edition of the FAQ is attached to the end of this message. The Approach Users Mailing List is not moderated. Any message sent to it is automatically bounced back out to everyone on the list. ##>: The Topic An on topic message is any message which concerns how to use Lotus Approach software, including relevant books, web sites, helper utilities, and information about new versions that is of broad interest to Approach Users. Requests for people to do paid work on an Approach database are permissible, but replies to these should go directly to the person concerned and not to the mailing list. ##>: Off topic and personal messages Anything that is not on topic is considered off topic, including messages intended for a particular person, replies to other off topic messages or spams, and comments about the value of somebody else's response / option / whatever. The list gives you privileged access to many people around the world. Please be considerate, and don't load their email boxes with unnecessary drivel. People are encouraged to post thank you messages to the people concerned rather than to the mailing list as they are not of general interest. Similarly, expressions of interest in offers of paid work should be sent to the person offering the work rather than to the mailing list. ##>: The List Owner I am student, and do this as a hobby, so be nice! I personally respond to every off topic message in private email. If you see an off topic message on the list, including a subscribe or unsubscribe request, you can assume that I have taken care of it. If you post an off topic message to the list you can expect to hear from me...!? You can email me (John Brown) at approach-owner@mailman.anu.edu.au ##>: Subscribing, unsubscribing, digests and other options You can subscribe, unsubscribe, and change your personal options (including digest mode) at: http://mailman.anu.edu.au/mailman/listinfo/Approach Subscribers can post to the list APPROACH@mailman.anu.edu.au If you have any difficulties with the mailing list please email me at approach-owner@mailman.anu.edu.au with "APPROACH" in the subject line. I hope you find the mailing list useful, and get lots of helpful information from it. ##>: Question and Answer Posts I suggest you use the following format: a) Summarize your question in one sentence, being as specific as you can. E.g. 'Is it possible to save records in alphabetical order?' b) In a short paragraph following the question, provide any further information that people may need in order to fully understand your question E.g. 'I find it annoying to have to continually sort the records and it would be easier if I could just save them in their sorted order. Is this possible?' c) In a final paragraph state what version of Approach you are using (2.1, 3.0,...) as well as any other software or hardware that you refer to. THIS IS VERY IMPORTANT. ##>: comp.databases There is no official association between the mailing list and the Usenet newsgroup comp.databases, or any other newsgroup. However comp.databases is a good forum for discussion. Relevant information gathered from the newsgroup will be included in the Newsletter and FAQ. If you do post to comp.databases please include the word APPROACH in the subject line. Most people on the mailing do not regularly access comp.databases. ##>: Lotus There is official no connection between this mailing list and the Lotus Corporation what so ever. This is a completely unofficial and unconnected mailing list. ##>: Mail storms A mail storm is caused by a mail server which incorrectly sends error messages to the mailing list instead of the Error_to: address in the message header. When it sends an error message to the list it sometimes causes the same error to be repeated. This goes on and on and our inboxes quickly fill up with recurring error messages. This is what is called mail storm. They are unusual, but one has occurred in the life of this mailing list. There is nothing I can do to stop this from happening because it is caused by an error in the remote system. I am able to remove the offending address from the mailing list when I log on and discover the problem, but the mail storm will probably have been stopped by the mail server before I do this. I will however make a complaint to the postmaster of the offending system, asking them to permanently correct the problem. If this ever occurs again DO NOT SEND ANY MAIL TO THE LIST AS IT WILL ONLY MAKE THE SITUATION WORSE BECAUSE EVERY ADDITIONAL MESSAGE SIMPLY INCREASES THE RATE OF THE MAIL STORM. I will appreciate your understanding and cooperation with this, as will everybody else on the list. ##>: Disclaimer This document is provided as is without any express or implied warranties. The editor and contributors assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein. ##>: Editor Editor: approach-owner@mailman.anu.edu.au (John Brown) © Copyright 1995 - 2024 by John Brown, all rights reserved. Permission is given for Approach User Support web pages and associated documents (FAQ, Archive of Scripts, newsletters and mailing list documents) to be linked to or distributed in electronic form (such as email, newsgroups, and the WWW) as long as it is posted in its entirety and contains this copyright statement, and is not for financial gain.